From 8da931a7f6c8a42005b279c05600c3677cc84faf Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sat, 5 Dec 2020 12:20:41 -0800 Subject: [PATCH] Add chibicc This program popped up on Hacker News recently. It's the only modern compiler I've ever seen that doesn't have dependencies and is easily modified. So I added all of the missing GNU extensions I like to use which means it might be possible soon to build on non-Linux and have third party not vendor gcc binaries. --- Makefile | 8 +- ape/lib/apm.h | 2 +- ape/lib/pc.h | 4 +- build/config.mk | 2 +- dsp/mpeg/mp2.c | 2 +- dsp/mpeg/mpeg.h | 8 +- dsp/scale/gyarados.c | 1 - dsp/tty/ttyraster.c | 12 +- examples/cp.c | 2 +- examples/examples.mk | 2 +- examples/invtsc.c | 13 +- examples/nesemu1.cc | 2 +- examples/now.c | 34 - examples/unbourne.c | 30 +- libc/assert.h | 2 +- libc/bits/atomic.h | 2 +- libc/bits/avxintrin.internal.h | 6 +- libc/bits/emmintrin.internal.h | 8 +- libc/bits/xmmintrin.internal.h | 4 +- libc/calls/fileexists.c | 19 +- libc/calls/fstat-nt.c | 2 +- libc/calls/internal.h | 4 +- libc/calls/isatty.c | 2 +- libc/calls/struct/sigaction.h | 2 +- libc/calls/struct/siginfo.h | 2 +- libc/calls/xnutrampoline.c | 6 +- libc/conv/conv.h | 2 +- libc/conv/imaxabs.c | 2 +- .../divmax.S => libc/conv/imaxabs.thunk.S | 15 +- libc/conv/strtoimax.c | 12 +- libc/crypto/rijndael.h | 6 +- libc/fmt/pflink.h | 15 +- libc/integral/c.inc | 42 +- libc/integral/lp64arg.inc | 63 +- libc/intrin/macros.h | 2 +- libc/isystem/pthread.h | 12 +- libc/isystem/windows.h | 8 +- libc/linux/exit.h | 2 +- libc/log/asan.c | 8 +- libc/log/bsd.h | 20 +- libc/log/check.h | 16 +- libc/log/die.c | 2 +- libc/log/err.c | 2 +- libc/log/errx.c | 2 +- libc/log/log.h | 12 +- libc/log/oncrash.c | 8 +- libc/log/ubsan.internal.h | 8 +- libc/log/verr.c | 2 +- libc/log/verrx.c | 2 +- libc/nexgen32e/bsf.h | 2 + libc/nexgen32e/bsr.h | 2 + libc/nexgen32e/cescapec.S | 24 +- tool/tags/keywords.c => libc/nexgen32e/ctz.c | 16 +- libc/nexgen32e/ffs.S | 2 +- libc/nexgen32e/ffsl.S | 2 +- libc/nexgen32e/khalfcache3.S | 64 + libc/nexgen32e/loadxmm.S | 2 +- libc/nexgen32e/memcpy.S | 2 +- libc/nexgen32e/savexmm.S | 2 +- libc/nexgen32e/strstr-sse42.S | 17 +- libc/nt/runtime.h | 2 +- libc/nt/struct/context.h | 4 +- libc/nt/thread.h | 2 +- libc/runtime/gc.h | 2 +- libc/runtime/internal.h | 8 +- libc/runtime/interruptiblecall.c | 2 +- libc/runtime/print.greg.c | 2 +- libc/runtime/runtime.h | 64 +- libc/runtime/valist.c | 51 + libc/runtime/valist.h | 17 + libc/runtime/winmain.greg.c | 2 +- libc/stdio/g_stderr.c | 2 +- libc/stdio/g_stdin.c | 2 +- libc/stdio/g_stdout.c | 2 +- libc/stdio/mkstemp.c | 4 +- libc/str/endswith16.c | 24 +- libc/str/startswith16.c | 24 +- libc/str/str.h | 9 +- libc/str/strncpy.thunk.S | 24 + libc/str/strpbrk.c | 2 +- libc/str/strpbrk16.c | 26 +- libc/str/strspn.c | 2 +- libc/str/strspn16.c | 22 +- libc/str/strstr.c | 29 +- libc/str/wcsendswith.c | 24 +- libc/str/wcspbrk.c | 26 +- libc/str/wcsspn.c | 22 +- libc/str/wcsstartswith.c | 24 +- libc/testlib/benchrunner.c | 4 +- libc/testlib/formatfloat.c | 7 +- libc/testlib/testlib.h | 2 +- libc/testlib/testlib.mk | 2 +- libc/testlib/testrunner.c | 2 +- libc/x/x.h | 4 +- libc/x/x.mk | 2 +- libc/x/xdtoa.c | 11 +- test/dsp/core/dct_test.c | 88 - test/dsp/core/illumination_test.c | 12 +- test/dsp/core/inv3_test.c | 6 +- test/dsp/tty/windex_test.c | 8 +- test/libc/conv/strtoimax_test.c | 25 +- test/libc/fmt/test.mk | 3 +- test/libc/math/round_test.c | 16 +- test/libc/release/test.mk | 3 +- test/libc/{alg => str}/strstr_test.c | 0 test/libc/str/test.mk | 1 + test/libc/tinymath/powl_test.c | 1 - test/libc/tinymath/round_test.c | 24 +- test/libc/tinymath/sinl_test.c | 15 +- test/libc/tinymath/test.mk | 3 +- test/libc/x/test.mk | 2 +- test/tool/build/lib/pty_test.c | 4 +- third_party/chibicc/{LICENSE => NOTICE} | 1 + third_party/chibicc/README.cosmo | 30 + third_party/chibicc/README.md | 134 + third_party/chibicc/asm.c | 751 ++ third_party/chibicc/cast.c | 179 + third_party/chibicc/chibicc.c | 377 +- third_party/chibicc/chibicc.h | 537 +- third_party/chibicc/chibicc.mk | 131 +- third_party/chibicc/codegen.c | 1890 ++-- third_party/chibicc/fpclassify.c | 145 + third_party/chibicc/hashmap.c | 24 +- third_party/chibicc/parse.c | 1521 +-- third_party/chibicc/preprocess.c | 587 +- third_party/chibicc/strarray.c | 2 - third_party/chibicc/test/alignof_test.c | 103 + third_party/chibicc/test/alloca_test.c | 29 + third_party/chibicc/test/arith_test.c | 341 + third_party/chibicc/test/asm_test.c | 132 + third_party/chibicc/test/attribute_test.c | 160 + third_party/chibicc/test/bitfield_test.c | 128 + third_party/chibicc/test/builtin_test.c | 242 + third_party/chibicc/test/cast_test.c | 80 + third_party/chibicc/test/common.c | 195 + third_party/chibicc/test/compat_test.c | 18 + third_party/chibicc/test/complit_test.c | 31 + third_party/chibicc/test/const_test.c | 23 + third_party/chibicc/test/constexpr_test.c | 181 + third_party/chibicc/test/control_test.c | 542 ++ third_party/chibicc/test/decl_test.c | 51 + third_party/chibicc/test/enum_test.c | 50 + third_party/chibicc/test/extern_test.c | 24 + third_party/chibicc/test/float_test.c | 92 + third_party/chibicc/test/function_test.c | 534 ++ third_party/chibicc/test/generic_test.c | 10 + third_party/chibicc/test/include1.h | 5 + third_party/chibicc/test/include2.h | 1 + third_party/chibicc/test/include3.h | 1 + third_party/chibicc/test/include4.h | 1 + third_party/chibicc/test/initializer_test.c | 793 ++ third_party/chibicc/test/int128_test.c | 8183 +++++++++++++++++ third_party/chibicc/test/line_test.c | 20 + third_party/chibicc/test/literal_test.c | 108 + third_party/chibicc/test/macro_test.c | 413 + third_party/chibicc/test/offsetof_test.c | 17 + third_party/chibicc/test/pointer_test.c | 202 + third_party/chibicc/test/pragma-once_test.c | 9 + third_party/chibicc/test/sizeof_test.c | 113 + third_party/chibicc/test/string_test.c | 105 + third_party/chibicc/test/struct_test.c | 379 + third_party/chibicc/test/test.h | 11 + third_party/chibicc/test/test.mk | 100 + third_party/chibicc/test/tls_test.c.todo | 18 + third_party/chibicc/test/typedef_test.c | 49 + third_party/chibicc/test/typeof_test.c | 29 + third_party/chibicc/test/unicode_test.c | 138 + third_party/chibicc/test/union_test.c | 132 + third_party/chibicc/test/usualconv_test.c | 58 + third_party/chibicc/test/varargs_test.c | 52 + third_party/chibicc/test/variable_test.c | 244 + third_party/chibicc/test/vector_test.c | 56 + third_party/chibicc/test/vla_test.c | 86 + third_party/chibicc/tokenize.c | 196 +- third_party/chibicc/type.c | 64 +- third_party/chibicc/unicode.c | 71 +- third_party/compiler_rt/int_util.h | 2 +- third_party/dlmalloc/dlmalloc.c | 2 +- third_party/dtoa/dtoa.c | 5848 ------------ third_party/dtoa/dtoa.h | 18 - third_party/dtoa/dtoa.mk | 62 - third_party/dtoa/g_fmt.c | 114 - third_party/dtoa/strtod.c | 531 -- third_party/duktape/duk_config.h | 2 +- third_party/gdtoa/dmisc.c | 2 +- third_party/gdtoa/dtoa.c | 2 +- third_party/gdtoa/g_Qfmt.c | 2 +- third_party/gdtoa/g_Qfmt_p.c | 2 +- third_party/gdtoa/g__fmt.c | 2 +- third_party/gdtoa/g_ddfmt.c | 2 +- third_party/gdtoa/g_ddfmt_p.c | 2 +- third_party/gdtoa/g_dfmt.c | 2 +- third_party/gdtoa/g_dfmt_p.c | 2 +- third_party/gdtoa/g_ffmt.c | 2 +- third_party/gdtoa/g_ffmt_p.c | 2 +- third_party/gdtoa/g_xLfmt.c | 2 +- third_party/gdtoa/g_xLfmt_p.c | 2 +- third_party/gdtoa/g_xfmt.c | 2 +- third_party/gdtoa/g_xfmt_p.c | 2 +- third_party/gdtoa/gdtoa.c | 2 +- .../gdtoa/{gdtoaimp.h => gdtoa.internal.h} | 5 +- third_party/gdtoa/gethex.c | 2 +- third_party/gdtoa/gmisc.c | 2 +- third_party/gdtoa/hd_init.c | 2 +- third_party/gdtoa/hexnan.c | 2 +- third_party/gdtoa/misc.c | 2 +- third_party/gdtoa/smisc.c | 2 +- third_party/gdtoa/strtoIQ.c | 2 +- third_party/gdtoa/strtoId.c | 2 +- third_party/gdtoa/strtoIdd.c | 2 +- third_party/gdtoa/strtoIf.c | 2 +- third_party/gdtoa/strtoIg.c | 2 +- third_party/gdtoa/strtoIx.c | 2 +- third_party/gdtoa/strtoIxL.c | 2 +- third_party/gdtoa/strtod.c | 2 +- third_party/gdtoa/strtodI.c | 2 +- third_party/gdtoa/strtodg.c | 2 +- third_party/gdtoa/strtodnrp.c | 2 +- third_party/gdtoa/strtof.c | 2 +- third_party/gdtoa/strtold.c | 37 +- third_party/gdtoa/strtopQ.c | 2 +- third_party/gdtoa/strtopd.c | 2 +- third_party/gdtoa/strtopdd.c | 2 +- third_party/gdtoa/strtopf.c | 2 +- third_party/gdtoa/strtopx.c | 2 +- third_party/gdtoa/strtopxL.c | 2 +- third_party/gdtoa/strtorQ.c | 2 +- third_party/gdtoa/strtord.c | 2 +- third_party/gdtoa/strtordd.c | 2 +- third_party/gdtoa/strtorf.c | 2 +- third_party/gdtoa/strtorx.c | 2 +- third_party/gdtoa/strtorxL.c | 2 +- third_party/gdtoa/sum.c | 2 +- third_party/gdtoa/ulp.c | 2 +- third_party/lemon/lemon.c | 2 +- third_party/lemon/lemon.mk | 2 +- third_party/m4/extern.h | 2 +- third_party/stb/stb_image.c | 4 +- third_party/third_party.mk | 1 - third_party/zlib/crcfold.c | 2 +- tool/build/blinkenlights.c | 9 +- tool/build/build.mk | 2 +- tool/build/calculator.c | 19 +- tool/build/calculator.ctest | 2 +- tool/build/coefficients.c | 4 +- tool/build/img2code.c | 4 +- tool/build/lib/machine.h | 4 +- tool/build/lib/ssefloat.c | 4 +- tool/build/lib/ssefloat.h | 4 +- tool/build/lib/throw.h | 12 +- tool/build/lz4toasm.c | 2 +- tool/build/mkdeps.c | 2 +- tool/build/runit.c | 2 +- tool/build/runitd.c | 2 +- tool/build/zipobj.c | 2 +- tool/calc/calc.c | 38 +- tool/calc/calc.h | 2 +- tool/calc/calc.mk | 2 +- tool/calc/calc.y | 1 - tool/cc/c11.l | 193 - tool/cc/c11.y | 535 -- tool/cc/cc.mk | 11 - tool/decode/decode.mk | 2 +- tool/decode/mkcombos.c | 2 +- tool/decode/mkwides.c | 2 +- tool/decode/x86opinfo.c | 2 +- tool/decode/x87.c | 5 +- tool/emacs/cosmo-c-keywords.el | 4 +- tool/emacs/cosmo-cpp-constants.el | 7 + tool/emacs/cosmo-stuff.el | 38 +- tool/emacs/key.py | 4 +- tool/net/echoserver.c | 2 +- tool/net/greenbean.c | 2 +- tool/net/redbean.c | 2 +- tool/tags/keywords.gperf | 161 - tool/tags/keywords.inc | 516 -- tool/tags/tags.c | 343 - tool/tags/tags.h | 25 - tool/tags/tags.mk | 74 - tool/tags/tags.y | 436 - tool/tool.mk | 4 +- tool/viz/bing.c | 2 +- tool/viz/derasterize.c | 4 +- tool/viz/double2int.c | 2 +- tool/viz/fold.c | 2 +- tool/viz/generatematrix.c | 8 +- tool/viz/invertblocks.c | 2 +- tool/viz/lib/formatmatrix-double.c | 6 +- tool/viz/lib/vizlib.mk | 2 +- tool/viz/life.c | 2 +- tool/viz/magikarp.c | 2 +- tool/viz/memzoom.c | 4 +- tool/viz/printimage.c | 2 +- tool/viz/printpixel.c | 1 - tool/viz/printvideo.c | 4 +- tool/viz/rgbtoxterm.c | 2 +- tool/viz/tabalign.c | 2 +- tool/viz/viz.mk | 2 +- 298 files changed, 19493 insertions(+), 11950 deletions(-) delete mode 100644 examples/now.c rename third_party/dtoa/divmax.S => libc/conv/imaxabs.thunk.S (89%) rename tool/tags/keywords.c => libc/nexgen32e/ctz.c (86%) create mode 100644 libc/nexgen32e/khalfcache3.S create mode 100644 libc/runtime/valist.c create mode 100644 libc/runtime/valist.h create mode 100644 libc/str/strncpy.thunk.S delete mode 100644 test/dsp/core/dct_test.c rename test/libc/{alg => str}/strstr_test.c (100%) rename third_party/chibicc/{LICENSE => NOTICE} (95%) create mode 100644 third_party/chibicc/README.cosmo create mode 100644 third_party/chibicc/README.md create mode 100644 third_party/chibicc/asm.c create mode 100644 third_party/chibicc/cast.c create mode 100644 third_party/chibicc/fpclassify.c create mode 100644 third_party/chibicc/test/alignof_test.c create mode 100644 third_party/chibicc/test/alloca_test.c create mode 100644 third_party/chibicc/test/arith_test.c create mode 100644 third_party/chibicc/test/asm_test.c create mode 100644 third_party/chibicc/test/attribute_test.c create mode 100644 third_party/chibicc/test/bitfield_test.c create mode 100644 third_party/chibicc/test/builtin_test.c create mode 100644 third_party/chibicc/test/cast_test.c create mode 100644 third_party/chibicc/test/common.c create mode 100644 third_party/chibicc/test/compat_test.c create mode 100644 third_party/chibicc/test/complit_test.c create mode 100644 third_party/chibicc/test/const_test.c create mode 100644 third_party/chibicc/test/constexpr_test.c create mode 100644 third_party/chibicc/test/control_test.c create mode 100644 third_party/chibicc/test/decl_test.c create mode 100644 third_party/chibicc/test/enum_test.c create mode 100644 third_party/chibicc/test/extern_test.c create mode 100644 third_party/chibicc/test/float_test.c create mode 100644 third_party/chibicc/test/function_test.c create mode 100644 third_party/chibicc/test/generic_test.c create mode 100644 third_party/chibicc/test/include1.h create mode 100644 third_party/chibicc/test/include2.h create mode 100644 third_party/chibicc/test/include3.h create mode 100644 third_party/chibicc/test/include4.h create mode 100644 third_party/chibicc/test/initializer_test.c create mode 100644 third_party/chibicc/test/int128_test.c create mode 100644 third_party/chibicc/test/line_test.c create mode 100644 third_party/chibicc/test/literal_test.c create mode 100644 third_party/chibicc/test/macro_test.c create mode 100644 third_party/chibicc/test/offsetof_test.c create mode 100644 third_party/chibicc/test/pointer_test.c create mode 100644 third_party/chibicc/test/pragma-once_test.c create mode 100644 third_party/chibicc/test/sizeof_test.c create mode 100644 third_party/chibicc/test/string_test.c create mode 100644 third_party/chibicc/test/struct_test.c create mode 100644 third_party/chibicc/test/test.h create mode 100644 third_party/chibicc/test/test.mk create mode 100644 third_party/chibicc/test/tls_test.c.todo create mode 100644 third_party/chibicc/test/typedef_test.c create mode 100644 third_party/chibicc/test/typeof_test.c create mode 100644 third_party/chibicc/test/unicode_test.c create mode 100644 third_party/chibicc/test/union_test.c create mode 100644 third_party/chibicc/test/usualconv_test.c create mode 100644 third_party/chibicc/test/varargs_test.c create mode 100644 third_party/chibicc/test/variable_test.c create mode 100644 third_party/chibicc/test/vector_test.c create mode 100644 third_party/chibicc/test/vla_test.c delete mode 100644 third_party/dtoa/dtoa.c delete mode 100644 third_party/dtoa/dtoa.h delete mode 100644 third_party/dtoa/dtoa.mk delete mode 100644 third_party/dtoa/g_fmt.c delete mode 100644 third_party/dtoa/strtod.c rename third_party/gdtoa/{gdtoaimp.h => gdtoa.internal.h} (99%) delete mode 100644 tool/cc/c11.l delete mode 100644 tool/cc/c11.y delete mode 100644 tool/cc/cc.mk delete mode 100644 tool/tags/keywords.gperf delete mode 100644 tool/tags/keywords.inc delete mode 100644 tool/tags/tags.c delete mode 100644 tool/tags/tags.h delete mode 100644 tool/tags/tags.mk delete mode 100644 tool/tags/tags.y diff --git a/Makefile b/Makefile index 5e5e4245..3747d16e 100644 --- a/Makefile +++ b/Makefile @@ -115,7 +115,6 @@ include third_party/dlmalloc/dlmalloc.mk # │ include libc/mem/mem.mk # │ include libc/ohmyplus/ohmyplus.mk # │ include libc/zipos/zipos.mk # │ -include third_party/dtoa/dtoa.mk # │ include third_party/gdtoa/gdtoa.mk # │ include libc/time/time.mk # │ include libc/alg/alg.mk # │ @@ -140,6 +139,7 @@ include libc/dns/dns.mk # │ include libc/crypto/crypto.mk # │ include net/http/http.mk #─┘ include third_party/chibicc/chibicc.mk +include third_party/chibicc/test/test.mk include third_party/lemon/lemon.mk include third_party/linenoise/linenoise.mk include third_party/editline/editline.mk @@ -160,13 +160,11 @@ include tool/build/emucrt/emucrt.mk include tool/build/emubin/emubin.mk include tool/build/build.mk include tool/calc/calc.mk -include tool/tags/tags.mk include tool/decode/lib/decodelib.mk include tool/decode/decode.mk include tool/hash/hash.mk include tool/net/net.mk include tool/viz/viz.mk -include tool/cc/cc.mk include tool/tool.mk include test/libc/alg/test.mk include test/libc/tinymath/test.mk @@ -278,7 +276,7 @@ COSMOPOLITAN_OBJECTS = \ LIBC_ZIPOS \ THIRD_PARTY_COMPILER_RT \ THIRD_PARTY_DLMALLOC \ - THIRD_PARTY_DTOA \ + THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_MUSL \ THIRD_PARTY_REGEX @@ -311,7 +309,7 @@ COSMOPOLITAN_HEADERS = \ LIBC_X \ LIBC_ZIPOS \ THIRD_PARTY_DLMALLOC \ - THIRD_PARTY_DTOA \ + THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_MUSL \ THIRD_PARTY_REGEX diff --git a/ape/lib/apm.h b/ape/lib/apm.h index 544e23b2..1e467624 100644 --- a/ape/lib/apm.h +++ b/ape/lib/apm.h @@ -53,7 +53,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) -void apmoff(void) noreturn; +void apmoff(void) wontreturn; #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* APE_LIB_APM_H_ */ diff --git a/ape/lib/pc.h b/ape/lib/pc.h index 991bc7c2..6ff8c85c 100644 --- a/ape/lib/pc.h +++ b/ape/lib/pc.h @@ -197,7 +197,7 @@ struct IdtDescriptor { struct thatispacked PageTable { uint64_t p[512]; -} aligned(PAGESIZE); +} forcealign(PAGESIZE); extern struct PageTable g_pml4t; extern struct GlobalDescriptorTable gdt; @@ -211,7 +211,7 @@ extern struct SmapEntry e820map_xlm[XLM_E820_SIZE / sizeof(struct SmapEntry)]; extern uint64_t g_ptsp; extern uint64_t g_ptsp_xlm; -void bootdr(char drive) noreturn; +void bootdr(char drive) wontreturn; void smapsort(struct SmapEntry *); uint64_t *__getpagetableentry(int64_t, unsigned, struct PageTable *, diff --git a/build/config.mk b/build/config.mk index 18e77b0c..e7988b7f 100644 --- a/build/config.mk +++ b/build/config.mk @@ -138,7 +138,7 @@ CONFIG_CCFLAGS += \ -fno-align-loops TARGET_ARCH ?= \ - -march=k8-sse3 + -msse3 endif diff --git a/dsp/mpeg/mp2.c b/dsp/mpeg/mp2.c index d9c8f88e..5d056390 100644 --- a/dsp/mpeg/mp2.c +++ b/dsp/mpeg/mp2.c @@ -266,7 +266,7 @@ struct plm_audio_t { float D[1024]; float V[1024]; float U[32]; -} aligned(64); +} forcealign(64); typedef plm_audio_t plm_audio_t; diff --git a/dsp/mpeg/mpeg.h b/dsp/mpeg/mpeg.h index e29de64c..26b9984a 100644 --- a/dsp/mpeg/mpeg.h +++ b/dsp/mpeg/mpeg.h @@ -77,12 +77,12 @@ struct plm_samples_t { double time; unsigned int count; #ifdef PLM_AUDIO_SEPARATE_CHANNELS - float left[PLM_AUDIO_SAMPLES_PER_FRAME] aligned(32); - float right[PLM_AUDIO_SAMPLES_PER_FRAME] aligned(32); + float left[PLM_AUDIO_SAMPLES_PER_FRAME] forcealign(32); + float right[PLM_AUDIO_SAMPLES_PER_FRAME] forcealign(32); #else - float interleaved[PLM_AUDIO_SAMPLES_PER_FRAME * 2] aligned(32); + float interleaved[PLM_AUDIO_SAMPLES_PER_FRAME * 2] forcealign(32); #endif -} aligned(32); +} forcealign(32); typedef struct plm_samples_t plm_samples_t; diff --git a/dsp/scale/gyarados.c b/dsp/scale/gyarados.c index 586d6ebd..873e9fc9 100644 --- a/dsp/scale/gyarados.c +++ b/dsp/scale/gyarados.c @@ -33,7 +33,6 @@ #include "libc/str/str.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" #include "tool/viz/lib/knobs.h" /** diff --git a/dsp/tty/ttyraster.c b/dsp/tty/ttyraster.c index 93fe971c..aa1d36cb 100644 --- a/dsp/tty/ttyraster.c +++ b/dsp/tty/ttyraster.c @@ -611,8 +611,8 @@ static struct Pick PickBlockUnicodeAnsi(struct TtyRgb tl, struct TtyRgb tr, struct TtyRgb bl2 = GetQuant(bl); struct TtyRgb br2 = GetQuant(br); unsigned i, p1, p2; - uint16_t picks1[96] aligned(32); - uint16_t picks2[32] aligned(32); + uint16_t picks1[96] forcealign(32); + uint16_t picks2[32] forcealign(32); memset(picks1, 0x79, sizeof(picks1)); memset(picks2, 0x79, sizeof(picks2)); PickUnicode(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2); @@ -625,7 +625,7 @@ static struct Pick PickBlockUnicodeAnsi(struct TtyRgb tl, struct TtyRgb tr, static struct Pick PickBlockUnicodeTrue(struct TtyRgb tl, struct TtyRgb tr, struct TtyRgb bl, struct TtyRgb br) { unsigned i; - uint16_t picks[96] aligned(32); + uint16_t picks[96] forcealign(32); memset(picks, 0x79, sizeof(picks)); PickUnicode(picks, tl, tr, bl, br, tl, tr, bl, br); i = windex(picks, 96); @@ -648,8 +648,8 @@ static struct Pick PickBlockCp437Ansi(struct TtyRgb tl, struct TtyRgb tr, struct TtyRgb bl2 = GetQuant(bl); struct TtyRgb br2 = GetQuant(br); unsigned i, p1, p2; - uint16_t picks1[32] aligned(32); - uint16_t picks2[32] aligned(32); + uint16_t picks1[32] forcealign(32); + uint16_t picks2[32] forcealign(32); memset(picks1, 0x79, sizeof(picks1)); memset(picks2, 0x79, sizeof(picks2)); PickCp437(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2); @@ -662,7 +662,7 @@ static struct Pick PickBlockCp437Ansi(struct TtyRgb tl, struct TtyRgb tr, static struct Pick PickBlockCp437True(struct TtyRgb tl, struct TtyRgb tr, struct TtyRgb bl, struct TtyRgb br) { unsigned i; - uint16_t picks[32] aligned(32); + uint16_t picks[32] forcealign(32); memset(picks, 0x79, sizeof(picks)); PickCp437(picks, tl, tr, bl, br, tl, tr, bl, br); return kPicksCp437[windex(picks, 32)]; diff --git a/examples/cp.c b/examples/cp.c index 99bcdb67..bab5dd66 100644 --- a/examples/cp.c +++ b/examples/cp.c @@ -42,7 +42,7 @@ FLAGS\n\ int flags; bool force; -noreturn void PrintUsage(int rc, FILE *f) { +wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "%s%s%s", "Usage: ", program_invocation_name, USAGE); exit(rc); } diff --git a/examples/examples.mk b/examples/examples.mk index 48c64fdd..2ca26f53 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -72,7 +72,7 @@ EXAMPLES_DIRECTDEPS = \ LIBC_ZIPOS \ THIRD_PARTY_COMPILER_RT \ THIRD_PARTY_DLMALLOC \ - THIRD_PARTY_DTOA \ + THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_MUSL \ THIRD_PARTY_STB \ diff --git a/examples/invtsc.c b/examples/invtsc.c index c4d9b77f..bda7e306 100644 --- a/examples/invtsc.c +++ b/examples/invtsc.c @@ -18,7 +18,7 @@ #include "libc/sysv/consts/sig.h" #include "libc/time/time.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" /** * @fileoverview Measure CPU clock mystery constants. @@ -52,15 +52,18 @@ long double GetSample(void) { void MeasureNanosecondsPerAlwaysRunningTimerCycle(void) { int i; - long double avg, samp; + long double avg, samp, elapsed; start_ = now(); for (i = 1, avg = 1.0L; !isdone_; ++i) { samp = GetSample(); avg += (samp - avg) / i; dsleep(kInterval); - printf("1c = %sns (last=%sns spent=%ss)\n", g_fmt(dtoabuf_[0], (double)avg), - g_fmt(dtoabuf_[1], (double)samp), - g_fmt(dtoabuf_[2], (double)(now() - start_))); + elapsed = now() - start_; + g_xfmt_p(dtoabuf_[0], &avg, 15, 32, 0); + g_xfmt_p(dtoabuf_[1], &samp, 15, 32, 0); + g_xfmt_p(dtoabuf_[2], &elapsed, 15, 32, 0); + printf("1c = %sns (last=%sns spent=%ss)\n", dtoabuf_[0], dtoabuf_[1], + dtoabuf_[2]); } } diff --git a/examples/nesemu1.cc b/examples/nesemu1.cc index 84d02c23..f7b81f5c 100644 --- a/examples/nesemu1.cc +++ b/examples/nesemu1.cc @@ -1774,7 +1774,7 @@ Press enter to continue without sound: ", for (;;) CPU::Op(); } -noreturn void PrintUsage(int rc, FILE* f) { +wontreturn void PrintUsage(int rc, FILE* f) { fprintf(f, "%s%s%s", "Usage: ", program_invocation_name, USAGE); exit(rc); } diff --git a/examples/now.c b/examples/now.c deleted file mode 100644 index 424708c9..00000000 --- a/examples/now.c +++ /dev/null @@ -1,34 +0,0 @@ -#if 0 -/*─────────────────────────────────────────────────────────────────╗ -│ To the extent possible under law, Justine Tunney has waived │ -│ all copyright and related or neighboring rights to this file, │ -│ as it is written in the following disclaimers: │ -│ • http://unlicense.org/ │ -│ • http://creativecommons.org/publicdomain/zero/1.0/ │ -╚─────────────────────────────────────────────────────────────────*/ -#endif -#include "libc/bits/bits.h" -#include "libc/bits/safemacros.internal.h" -#include "libc/calls/calls.h" -#include "libc/dce.h" -#include "libc/stdio/stdio.h" -#include "libc/sysv/consts/clock.h" -#include "libc/time/time.h" -#include "third_party/dtoa/dtoa.h" - -char dtoabuf_[3][32]; - -static long double avg; - -int main(int argc, char *argv[]) { - long double t2, t1 = nowl(); - dsleep(0.3); - for (;;) { - t2 = nowl(); - printf("%s %s avg=%s\n", g_fmt(dtoabuf_[0], t2), - g_fmt(dtoabuf_[1], t2 - t1), g_fmt(dtoabuf_[2], avg)); - t1 = t2; - dsleep(0.3); - } - return 0; -} diff --git a/examples/unbourne.c b/examples/unbourne.c index ba715e4d..d4ee6c23 100644 --- a/examples/unbourne.c +++ b/examples/unbourne.c @@ -141,7 +141,7 @@ #include "libc/sysv/consts/rlim.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/w.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" #include "third_party/musl/passwd.h" #undef CEOF @@ -1602,7 +1602,7 @@ static inline void sigclearmask(void) { * just do a longjmp to the exception handler. The type of exception is * stored in the global variable "exception". */ -noreturn static void exraise(int e) { +wontreturn static void exraise(int e) { if (vforked) _exit(exitstatus); INTOFF; exception = e; @@ -1617,7 +1617,7 @@ noreturn static void exraise(int e) { * are held using the INTOFF macro. (The test for iflag is just * defensive programming.) */ -noreturn static void onint(void) { +wontreturn static void onint(void) { intpending = 0; sigclearmask(); if (!(rootshell && iflag)) { @@ -1896,20 +1896,20 @@ printfesque(1) static void sh_warnx(const char *fmt, ...) { * is not NULL then error prints an error message using printf style * formatting. It then raises the error exception. */ -noreturn static void exverror(int cond, const char *msg, va_list ap) { +wontreturn static void exverror(int cond, const char *msg, va_list ap) { exvwarning(msg, ap); flushall(); exraise(cond); } -noreturn static void exerror(int cond, const char *msg, ...) { +wontreturn static void exerror(int cond, const char *msg, ...) { va_list ap; va_start(ap, msg); exverror(cond, msg, ap); va_end(ap); } -noreturn static void sh_error(const char *msg, ...) { +wontreturn static void sh_error(const char *msg, ...) { va_list ap; exitstatus = 2; va_start(ap, msg); @@ -1917,16 +1917,16 @@ noreturn static void sh_error(const char *msg, ...) { va_end(ap); } -noreturn static void badnum(const char *s) { +wontreturn static void badnum(const char *s) { sh_error(illnum, s); } -noreturn static void synerror(const char *msg) { +wontreturn static void synerror(const char *msg) { errlinno = plinno; sh_error("Syntax error: %s", msg); } -noreturn static void yyerror(const char *s) { +wontreturn static void yyerror(const char *s) { sh_error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); } @@ -1935,7 +1935,7 @@ noreturn static void yyerror(const char *s) { * argument is the token that is expected, or -1 if more than one type * of token can occur at this point. */ -noreturn static void synexpect(int token) { +wontreturn static void synexpect(int token) { char msg[64]; if (token >= 0) { fmtstr(msg, 64, "%s unexpected (expecting %s)", tokname[lasttoken], tokname[token]); @@ -1945,7 +1945,7 @@ noreturn static void synexpect(int token) { synerror(msg); } -noreturn static void varunset(const char *end, const char *var_, const char *umsg, int varflags) { +wontreturn static void varunset(const char *end, const char *var_, const char *umsg, int varflags) { const char *msg; const char *tail; tail = nullstr; @@ -2096,7 +2096,7 @@ static char *nodesavestr(s) char *s; return rtn; } -noreturn static void shellexec(char **, const char *, int); +wontreturn static void shellexec(char **, const char *, int); static char **listvars(int, int, char ***); static char *argstr(char *p, int flag); static char *conv_escape(char *, int *); @@ -3175,7 +3175,7 @@ out: return exitstatus; } -noreturn static void evaltreenr(union node *n, int flags) { +wontreturn static void evaltreenr(union node *n, int flags) { evaltree(n, flags); abort(); } @@ -3876,7 +3876,7 @@ static int eprintlist(struct output *out, struct strlist *sp, int sep) { * Exec a program. Never returns. If you change this routine, you may * have to change the find_command routine as well. */ -noreturn static void shellexec(char **argv, const char *path, int idx) { +wontreturn static void shellexec(char **argv, const char *path, int idx) { char *cmdname; int e; char **envp; @@ -9316,7 +9316,7 @@ static void setinteractive(int on) { /* * Called to exit the shell. */ -noreturn static void exitshell(void) { +wontreturn static void exitshell(void) { struct jmploc loc; char *p; savestatus = exitstatus; diff --git a/libc/assert.h b/libc/assert.h index 0d6bcfa6..74f1ea59 100644 --- a/libc/assert.h +++ b/libc/assert.h @@ -3,7 +3,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void __assert_fail(const char *, const char *, int) hidden noreturn relegated; +void __assert_fail(const char *, const char *, int) hidden wontreturn relegated; #ifdef NDEBUG #define __ASSERT_FAIL(EXPR, FILE, LINE) diff --git a/libc/bits/atomic.h b/libc/bits/atomic.h index 0c7db3df..9cb5d557 100644 --- a/libc/bits/atomic.h +++ b/libc/bits/atomic.h @@ -45,7 +45,7 @@ COSMOPOLITAN_C_START_ struct AtomicFlag { uint32_t __cacheline[16]; /* Intel V.O §9.4.6 */ -} aligned(64); +} forcealign(64); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/bits/avxintrin.internal.h b/libc/bits/avxintrin.internal.h index 5071bcdd..4bca0220 100644 --- a/libc/bits/avxintrin.internal.h +++ b/libc/bits/avxintrin.internal.h @@ -7,9 +7,9 @@ typedef float __m256 _Vector_size(32) mayalias; typedef double __m256d _Vector_size(32) mayalias; typedef long long __m256i _Vector_size(32) mayalias; -typedef float __m256_u _Vector_size(32) aligned(1) mayalias; -typedef double __m256d_u _Vector_size(32) aligned(1) mayalias; -typedef long long __m256i_u _Vector_size(32) aligned(1) mayalias; +typedef float __m256_u _Vector_size(32) forcealign(1) mayalias; +typedef double __m256d_u _Vector_size(32) forcealign(1) mayalias; +typedef long long __m256i_u _Vector_size(32) forcealign(1) mayalias; typedef double __v4df _Vector_size(32); typedef float __v8sf _Vector_size(32); diff --git a/libc/bits/emmintrin.internal.h b/libc/bits/emmintrin.internal.h index b1a9bde7..154e7a05 100644 --- a/libc/bits/emmintrin.internal.h +++ b/libc/bits/emmintrin.internal.h @@ -16,12 +16,12 @@ typedef short __v8hi _Vector_size(16); typedef unsigned short __v8hu _Vector_size(16); typedef double __v2df _Vector_size(16); -typedef double __m128d _Vector_size(16) aligned(16); -typedef double __m128d_u _Vector_size(16) aligned(1); +typedef double __m128d _Vector_size(16) forcealign(16); +typedef double __m128d_u _Vector_size(16) forcealign(1); typedef long long __v2di _Vector_size(16); -typedef long long __m128i _Vector_size(16) aligned(16); -typedef long long __m128i_u _Vector_size(16) aligned(1); +typedef long long __m128i _Vector_size(16) forcealign(16); +typedef long long __m128i_u _Vector_size(16) forcealign(1); typedef unsigned long long __v2du _Vector_size(16); struct thatispacked mayalias __usi128ma { diff --git a/libc/bits/xmmintrin.internal.h b/libc/bits/xmmintrin.internal.h index ef48c169..45786c88 100644 --- a/libc/bits/xmmintrin.internal.h +++ b/libc/bits/xmmintrin.internal.h @@ -35,8 +35,8 @@ typedef int __v4si _Vector_size(16); typedef unsigned int __v4su _Vector_size(16); typedef float __v4sf _Vector_size(16); -typedef float __m128 _Vector_size(16) aligned(16) mayalias; -typedef float __m128_u _Vector_size(16) aligned(1) mayalias; +typedef float __m128 _Vector_size(16) forcealign(16) mayalias; +typedef float __m128_u _Vector_size(16) forcealign(1) mayalias; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § it's a trap! » sse » simd ops ─╬─│┼ diff --git a/libc/calls/fileexists.c b/libc/calls/fileexists.c index 4ef29df4..8543b128 100644 --- a/libc/calls/fileexists.c +++ b/libc/calls/fileexists.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/internal.h" #include "libc/calls/struct/stat.h" #include "libc/dce.h" #include "libc/errno.h" @@ -33,12 +34,18 @@ * function. The stat() function may be used to differentiate them. */ bool fileexists(const char *path) { - /* TODO(jart): Use fast path on NT? */ + int rc, olderr; struct stat st; - int olderr = errno; - int rc = stat(path, &st); - if (rc == -1 && (errno == ENOENT || errno == ENOTDIR)) { - errno = olderr; + uint16_t path16[PATH_MAX]; + if (!IsWindows()) { + olderr = errno; + rc = stat(path, &st); + if (rc == -1 && (errno == ENOENT || errno == ENOTDIR)) { + errno = olderr; + } + return rc != -1; + } else { + if (__mkntpath(path, path16) == -1) return -1; + return GetFileAttributes(path16) != -1u; } - return rc != -1; } diff --git a/libc/calls/fstat-nt.c b/libc/calls/fstat-nt.c index 2773ad47..5b53e3e6 100644 --- a/libc/calls/fstat-nt.c +++ b/libc/calls/fstat-nt.c @@ -34,8 +34,8 @@ textwindows int fstat$nt(int64_t handle, struct stat *st) { int filetype; uint64_t actualsize; - struct NtByHandleFileInformation wst; struct NtFileCompressionInfo fci; + struct NtByHandleFileInformation wst; if (GetFileInformationByHandle(handle, &wst)) { memset(st, 0, sizeof(*st)); filetype = GetFileType(handle); diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 4bfb7fc5..eb04a344 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -198,12 +198,12 @@ i32 tunefd$sysv(i32, i32, i32, i32) hidden; u32 fprot2nt(i32, i32) hidden; u32 prot2nt(i32, i32) privileged; void __restore_rt() hidden; -void __sigenter$xnu(void *, i32, i32, void *, void *) hidden noreturn; +void __sigenter$xnu(void *, i32, i32, void *, void *) hidden wontreturn; int utimensat$xnu(int, const char *, const struct timespec *, int) hidden; int nanosleep$xnu(const struct timespec *, struct timespec *) hidden; void stat2linux(void *) hidden; void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *, - const struct __darwin_ucontext *) hidden noreturn; + const struct __darwin_ucontext *) hidden wontreturn; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼ diff --git a/libc/calls/isatty.c b/libc/calls/isatty.c index 39dabfa6..1002046c 100644 --- a/libc/calls/isatty.c +++ b/libc/calls/isatty.c @@ -27,7 +27,7 @@ * @asyncsignalsafe */ bool32 isatty(int fd) { - char buf[sizeof(uint16_t) * 4] aligned(2); + char buf[sizeof(uint16_t) * 4] forcealign(2); if (!IsWindows()) { return ioctl$sysv(fd, TIOCGWINSZ, &buf) != -1; } else { diff --git a/libc/calls/struct/sigaction.h b/libc/calls/struct/sigaction.h index baa84161..eff89319 100644 --- a/libc/calls/struct/sigaction.h +++ b/libc/calls/struct/sigaction.h @@ -14,7 +14,7 @@ struct sigaction { /* cosmo abi */ void (*sa_restorer)(void); struct sigset sa_mask; int64_t __pad; -} aligned(8); +} forcealign(8); #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_H_ */ diff --git a/libc/calls/struct/siginfo.h b/libc/calls/struct/siginfo.h index 2b35275e..403a0846 100644 --- a/libc/calls/struct/siginfo.h +++ b/libc/calls/struct/siginfo.h @@ -49,7 +49,7 @@ struct siginfo { }; char __ignoreme[128 - 2 * sizeof(int32_t) - sizeof(int64_t)]; }; -} aligned(8); +} forcealign(8); typedef struct siginfo siginfo_t; diff --git a/libc/calls/xnutrampoline.c b/libc/calls/xnutrampoline.c index b2ad0125..e984eb88 100644 --- a/libc/calls/xnutrampoline.c +++ b/libc/calls/xnutrampoline.c @@ -425,9 +425,9 @@ static void xnussefpustate2linux(struct FpuState *fs, memcpy(fs->st, &xnufs->__fpu_stmm0, (8 + 16) * sizeof(uint128_t)); } -noreturn void xnutrampoline(void *fn, int infostyle, int sig, - const struct __darwin_siginfo *xnuinfo, - const struct __darwin_ucontext *xnuctx) { +wontreturn void xnutrampoline(void *fn, int infostyle, int sig, + const struct __darwin_siginfo *xnuinfo, + const struct __darwin_ucontext *xnuctx) { /* note: this function impl can't access static memory */ intptr_t ax; struct Goodies { diff --git a/libc/conv/conv.h b/libc/conv/conv.h index 0f842dda..6f419b64 100644 --- a/libc/conv/conv.h +++ b/libc/conv/conv.h @@ -97,7 +97,7 @@ double RoundDecimalPlaces(double, double, double (*)(double)); #endif #ifndef __STRICT_ANSI__ -intmax_t __imaxabs(intmax_t) asm("imaxabs") libcesque pureconst; +intmax_t __imaxabs(intmax_t) libcesque pureconst; #define imaxabs(x) __imaxabs(x) #endif /* !ANSI */ diff --git a/libc/conv/imaxabs.c b/libc/conv/imaxabs.c index c5f88f34..da364479 100644 --- a/libc/conv/imaxabs.c +++ b/libc/conv/imaxabs.c @@ -20,6 +20,6 @@ #include "libc/conv/conv.h" #include "libc/macros.h" -intmax_t imaxabs(intmax_t x) { +intmax_t(imaxabs)(intmax_t x) { return ABS(x); } diff --git a/third_party/dtoa/divmax.S b/libc/conv/imaxabs.thunk.S similarity index 89% rename from third_party/dtoa/divmax.S rename to libc/conv/imaxabs.thunk.S index e5733ad6..6a77a518 100644 --- a/third_party/dtoa/divmax.S +++ b/libc/conv/imaxabs.thunk.S @@ -18,16 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ -/ Avoid dtoa needing .data section. - .bss - .align 4 -dtoa_divmax: - .zero 4 - .endobj dtoa_divmax,globl - .previous - - .init.start 202,_init_dtoa_divmax - movb $2,dtoa_divmax(%rip) - .init.end 202,_init_dtoa_divmax +__imaxabs: + jmp imaxabs + .endfn __imaxabs,globl diff --git a/libc/conv/strtoimax.c b/libc/conv/strtoimax.c index 877a8e76..0c6f116c 100644 --- a/libc/conv/strtoimax.c +++ b/libc/conv/strtoimax.c @@ -37,10 +37,10 @@ * @see strtoumax */ intmax_t strtoimax(const char *s, char **endptr, int base) { + bool neg; uintmax_t x; intmax_t res; unsigned diglet, bits; - bool neg, islong, isunsigned; x = 0; bits = 0; @@ -104,8 +104,6 @@ intmax_t strtoimax(const char *s, char **endptr, int base) { } } - if ((isunsigned = *s == 'u' || *s == 'U')) s++; - if ((islong = *s == 'l' || *s == 'L')) s++; if (endptr) *endptr = s; if (neg) { @@ -114,13 +112,5 @@ intmax_t strtoimax(const char *s, char **endptr, int base) { res = x; } - if (isunsigned) { - if (islong) { - res = (uint64_t)res; - } else { - res = (uint32_t)res; - } - } - return res; } diff --git a/libc/crypto/rijndael.h b/libc/crypto/rijndael.h index 87a6236f..647fdf20 100644 --- a/libc/crypto/rijndael.h +++ b/libc/crypto/rijndael.h @@ -28,7 +28,7 @@ COSMOPOLITAN_C_START_ Performance (New Hardware) ~20 ns ~40 ns ~400 ns Performance (Old Hardware) ~400 ns ~40 ns ~400 ns */ -typedef uint32_t aes_block_t _Vector_size(16) aligned(16); +typedef uint32_t aes_block_t _Vector_size(16) forcealign(16); struct Rijndael { union { @@ -47,8 +47,8 @@ aes_block_t unrijndael(uint32_t, aes_block_t, const struct Rijndael *); │ cosmopolitan § cryptography » implementation details ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -extern const uint8_t kAesSbox[256] aligned(64); -extern const uint8_t kAesSboxInverse[256] aligned(64); +extern const uint8_t kAesSbox[256] forcealign(64); +extern const uint8_t kAesSboxInverse[256] forcealign(64); aes_block_t InvMixColumns(aes_block_t) hidden; diff --git a/libc/fmt/pflink.h b/libc/fmt/pflink.h index 278a63a3..fa5392ec 100644 --- a/libc/fmt/pflink.h +++ b/libc/fmt/pflink.h @@ -2,7 +2,7 @@ #define COSMOPOLITAN_LIBC_FMT_PFLINK_H_ #include "libc/dce.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) -#ifndef __STRICT_ANSI__ +#if !defined(__STRICT_ANSI__) && !defined(__chibicc__) /** * @fileoverview builtin+preprocessor+linker tricks for printf/scanf. @@ -65,6 +65,19 @@ #else #define PFLINK(FMT) FMT #define SFLINK(FMT) FMT +asm(".pushsection .yoink\n\t" + "nop\tntoa(%rip)\n\t" + "nop\tftoa(%rip)\n\t" + "nop\tkCp437(%rip)\n\t" + "nop\tstrerror(%rip)\n\t" + "nop\tstrnwidth(%rip)\n\t" + "nop\tstrnwidth16(%rip)\n\t" + "nop\twcsnwidth(%rip)\n\t" + "nop\tmalloc(%rip)\n\t" + "nop\tcalloc(%rip)\n\t" + "nop\tfree_s(%rip)\n\t" + "nop\t__grow(%rip)\n\t" + ".popsection"); #endif /* __STRICT_ANSI__ */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_FMT_PFLINK_H_ */ diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 9f74143e..e45a64f6 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -2,6 +2,14 @@ #define __attribute__(x) #endif +#ifndef __cplusplus +#define COSMOPOLITAN_C_START_ +#define COSMOPOLITAN_C_END_ +#define COSMOPOLITAN_CXX_START_ +#define COSMOPOLITAN_CXX_END_ +#define COSMOPOLITAN_CXX_USING_ +#endif + #if defined(__STRICT_ANSI__) && __STDC_VERSION__ + 0 < 201112 #define asm __asm__ #endif @@ -67,18 +75,6 @@ } while (0) #endif -#if defined(__STRICT_ANSI__) || \ - (!defined(__GNUC__) && !__has_builtin(constant_p) && \ - !defined(__builtin_constant_p)) -#define __builtin_constant_p(x) 0 -#endif - -#if defined(__STRICT_ANSI__) || \ - (!defined(__GNUC__) && !__has_builtin(choose_expr) && \ - !defined(__builtin_choose_expr)) -#define __builtin_choose_expr(x, a, b) ((x) ? (long)(a) : (long)(b)) -#endif - #if __STDC_VERSION__ + 0 < 201112 #define ____Static_assert(x, y) A##B #define ___Static_assert(x, y) ____Static_assert(x, y) @@ -195,7 +191,7 @@ typedef int64_t intmax_t; typedef uint64_t uintmax_t; #endif -#ifdef __GNUC__ +#ifndef __chibicc__ #define va_list __builtin_va_list #define va_arg(ap, type) __builtin_va_arg(ap, type) #define va_copy(dest, src) __builtin_va_copy(dest, src) @@ -230,11 +226,11 @@ typedef uint64_t uintmax_t; /** * Aligns automatic or static variable. */ -#ifndef aligned +#ifndef forcealign #ifndef __STRICT_ANSI__ -#define aligned(bytes) __attribute__((__aligned__(bytes))) +#define forcealign(bytes) __attribute__((__aligned__(bytes))) #else -#define aligned(bytes) +#define forcealign(bytes) #endif #endif @@ -291,13 +287,13 @@ typedef uint64_t uintmax_t; #endif #endif -#ifndef noreturn +#ifndef wontreturn #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__noreturn__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 208) -#define noreturn __attribute__((__noreturn__)) +#define wontreturn __attribute__((__noreturn__)) #else -#define noreturn +#define wontreturn #endif #endif @@ -1067,13 +1063,5 @@ typedef uint64_t uintmax_t; STATIC_YOINK_SOURCE(__BASE_FILE__); #endif -#ifndef __cplusplus -#define COSMOPOLITAN_CXX_START_ -#define COSMOPOLITAN_CXX_END_ -#define COSMOPOLITAN_CXX_USING_ -#define COSMOPOLITAN_C_START_ -#define COSMOPOLITAN_C_END_ -#endif - #define MACHINE_CODE_ANALYSIS_BEGIN_ #define MACHINE_CODE_ANALYSIS_END_ diff --git a/libc/integral/lp64arg.inc b/libc/integral/lp64arg.inc index daa91e41..ece9f466 100644 --- a/libc/integral/lp64arg.inc +++ b/libc/integral/lp64arg.inc @@ -1,50 +1,17 @@ -typedef struct { - unsigned int gp_offset; - unsigned int fp_offset; - void *overflow_arg_area; - void *reg_save_area; -} __va_elem; - -typedef __va_elem va_list[1]; - -#define va_start(ap, last) \ - do { \ - *(ap) = *(__va_elem *)__va_area__; \ - } while (0) - -#define va_end(ap) - -static inline void *__va_arg_mem(__va_elem *ap, int sz, int align) { - void *p = ap->overflow_arg_area; - if (align > 8) p = (void *)(((unsigned long)p + 15) / 16 * 16); - ap->overflow_arg_area = (void *)(((unsigned long)p + sz + 7) / 8 * 8); - return p; -} - -static inline void *__va_arg_gp(__va_elem *ap, int sz, int align) { - if (ap->gp_offset >= 48) return __va_arg_mem(ap, sz, align); - void *r = ap->reg_save_area + ap->gp_offset; - ap->gp_offset += 8; - return r; -} - -static inline void *__va_arg_fp(__va_elem *ap, int sz, int align) { - if (ap->fp_offset >= 112) return __va_arg_mem(ap, sz, align); - void *r = ap->reg_save_area + ap->fp_offset; - ap->fp_offset += 8; - return r; -} - -#define va_arg(ap, ty) \ - ({ \ - int klass = __builtin_reg_class(ty); \ - *(ty *)(klass == 0 \ - ? __va_arg_gp(ap, sizeof(ty), _Alignof(ty)) \ - : klass == 1 ? __va_arg_fp(ap, sizeof(ty), _Alignof(ty)) \ - : __va_arg_mem(ap, sizeof(ty), _Alignof(ty))); \ - }) - -#define va_copy(dest, src) ((dest)[0] = (src)[0]) +#include "libc/runtime/valist.h" #define __GNUC_VA_LIST 1 -typedef va_list __gnuc_va_list; +#define __gnuc_va_list va_list + +#define va_end(AP) +#define va_copy(DST, SRC) ((DST)[0] = (SRC)[0]) +#define va_start(AP, LAST) \ + do { \ + *(AP) = *(struct __va *)__va_area__; \ + } while (0) + +#define va_arg(AP, TYPE) \ + (*(TYPE *)__va_arg(AP, sizeof(TYPE), _Alignof(TYPE), \ + __builtin_reg_class(TYPE))) + +typedef struct __va va_list[1]; diff --git a/libc/intrin/macros.h b/libc/intrin/macros.h index 35257446..17a8426d 100644 --- a/libc/intrin/macros.h +++ b/libc/intrin/macros.h @@ -9,7 +9,7 @@ #if defined(__x86_64__) && !defined(__STRICT_ANSI__) -typedef char __intrin_xmm_t _Vector_size(16) aligned(16) mayalias; +typedef char __intrin_xmm_t _Vector_size(16) forcealign(16) mayalias; #define INTRIN_SSEVEX_X_X_X_(PURE, ISA, OP, FLAGS, A, B, C) \ do { \ diff --git a/libc/isystem/pthread.h b/libc/isystem/pthread.h index d73e9736..f80b3072 100644 --- a/libc/isystem/pthread.h +++ b/libc/isystem/pthread.h @@ -5,12 +5,12 @@ #define PTHREAD_ONCE_INIT 0 -#define PTHREAD_MUTEX_NORMAL 0 -#define PTHREAD_MUTEX_DEFAULT 0 -#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_DEFAULT 0 +#define PTHREAD_MUTEX_RECURSIVE 1 #define PTHREAD_MUTEX_ERRORCHECK 2 -#define PTHREAD_MUTEX_STALLED 0 -#define PTHREAD_MUTEX_ROBUST 1 +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 /* clang-format off */ #define PTHREAD_MUTEX_INITIALIZER {{{0}}} @@ -65,7 +65,7 @@ typedef struct { } __u; } pthread_rwlock_t; -noreturn void pthread_exit(void *); +wontreturn void pthread_exit(void *); pureconst pthread_t pthread_self(void); int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); diff --git a/libc/isystem/windows.h b/libc/isystem/windows.h index 68ad2772..2d07481a 100644 --- a/libc/isystem/windows.h +++ b/libc/isystem/windows.h @@ -110,13 +110,13 @@ #define PWSTR WCHAR* #define PZPWSTR PWSTR* #define PCZPWSTR CONST PWSTR* -#define LPUWSTR WCHAR aligned(1)* -#define PUWSTR WCHAR aligned(1)* +#define LPUWSTR WCHAR forcealign(1)* +#define PUWSTR WCHAR forcealign(1)* #define LPCWSTR CONST WCHAR* #define PCWSTR CONST WCHAR* #define PZPCWSTR PCWSTR* -#define LPCUWSTR CONST WCHAR aligned(1)* -#define PCUWSTR CONST WCHAR aligned(1)* +#define LPCUWSTR CONST WCHAR forcealign(1)* +#define PCUWSTR CONST WCHAR forcealign(1)* #define PCHAR CHAR* #define LPCH CHAR* #define PCH CHAR* diff --git a/libc/linux/exit.h b/libc/linux/exit.h index e5479f2e..185c2eef 100644 --- a/libc/linux/exit.h +++ b/libc/linux/exit.h @@ -3,7 +3,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -forceinline noreturn long LinuxExit(long rc) { +forceinline wontreturn long LinuxExit(long rc) { asm volatile("syscall" : /* no outputs */ : "a"(0xE7), "D"(rc) diff --git a/libc/log/asan.c b/libc/log/asan.c index 580eca4b..2506973c 100644 --- a/libc/log/asan.c +++ b/libc/log/asan.c @@ -147,7 +147,7 @@ static const char *__asan_describe_access_poison(int c) { } } -static noreturn void __asan_die(const char *msg, size_t size) { +static wontreturn void __asan_die(const char *msg, size_t size) { write(STDERR_FILENO, msg, size); __die(); } @@ -163,7 +163,7 @@ static char *__asan_report_start(char *p) { return stpcpy(p, ": "); } -static noreturn void __asan_report_deallocate_fault(void *addr, int c) { +static wontreturn void __asan_report_deallocate_fault(void *addr, int c) { char *p, ibuf[21], buf[256]; p = __asan_report_start(buf); p = stpcpy(p, __asan_dscribe_free_poison(c)); @@ -175,8 +175,8 @@ static noreturn void __asan_report_deallocate_fault(void *addr, int c) { __asan_die(buf, p - buf); } -static noreturn void __asan_report_memory_fault(uint8_t *addr, int size, - const char *kind) { +static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size, + const char *kind) { char *p, ibuf[21], buf[256]; p = __asan_report_start(buf); p = stpcpy(p, __asan_describe_access_poison(*(char *)SHADOW((intptr_t)addr))); diff --git a/libc/log/bsd.h b/libc/log/bsd.h index a46fb908..10cf2071 100644 --- a/libc/log/bsd.h +++ b/libc/log/bsd.h @@ -8,23 +8,23 @@ COSMOPOLITAN_C_START_ │ cosmopolitan § logging » berkeley logger ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -void err(int, const char *, ...) printfesque(2) noreturn; -void errx(int, const char *, ...) printfesque(2) noreturn; -void verr(int, const char *, va_list) paramsnonnull((3)) noreturn; -void verrx(int, const char *, va_list) paramsnonnull((3)) noreturn; +void err(int, const char *, ...) printfesque(2) wontreturn; +void errx(int, const char *, ...) printfesque(2) wontreturn; +void verr(int, const char *, va_list) paramsnonnull((3)) wontreturn; +void verrx(int, const char *, va_list) paramsnonnull((3)) wontreturn; void vwarn(const char *, va_list) paramsnonnull((2)); void vwarnx(const char *, va_list) paramsnonnull((2)); void warn(const char *, ...) printfesque(1); void warnx(const char *, ...) printfesque(1); -#define err(EVAL, FMT, ...) (err)(EVAL, PFLINK(FMT), ##__VA_ARGS__) +#define err(EVAL, FMT, ...) (err)(EVAL, PFLINK(FMT), ##__VA_ARGS__) #define errx(EVAL, FMT, ...) (errx)(EVAL, PFLINK(FMT), ##__VA_ARGS__) -#define verr(EVAL, FMT, VA) (verr)(EVAL, PFLINK(FMT), VA) +#define verr(EVAL, FMT, VA) (verr)(EVAL, PFLINK(FMT), VA) #define verrx(EVAL, FMT, VA) (verrx)(EVAL, PFLINK(FMT), VA) -#define vwarn(FMT, VA) (vwarn)(PFLINK(FMT), VA) -#define vwarnx(FMT, VA) (vwarnx)(PFLINK(FMT), VA) -#define warn(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__) -#define warnx(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__) +#define vwarn(FMT, VA) (vwarn)(PFLINK(FMT), VA) +#define vwarnx(FMT, VA) (vwarnx)(PFLINK(FMT), VA) +#define warn(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__) +#define warnx(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__) COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/log/check.h b/libc/log/check.h index a8eef092..38ef2636 100644 --- a/libc/log/check.h +++ b/libc/log/check.h @@ -84,15 +84,15 @@ COSMOPOLITAN_C_START_ void __check_fail(const char *, const char *, uint64_t, const char *, uint64_t, const char *, const char *, int, const char *, - ...) relegated noreturn; + ...) relegated wontreturn; -void __check_fail_eq(uint64_t, uint64_t) relegated noreturn; -void __check_fail_ne(uint64_t, uint64_t) relegated noreturn; -void __check_fail_le(uint64_t, uint64_t) relegated noreturn; -void __check_fail_lt(uint64_t, uint64_t) relegated noreturn; -void __check_fail_ge(uint64_t, uint64_t) relegated noreturn; -void __check_fail_gt(uint64_t, uint64_t) relegated noreturn; -void __check_fail_aligned(unsigned, uint64_t) relegated noreturn; +void __check_fail_eq(uint64_t, uint64_t) relegated wontreturn; +void __check_fail_ne(uint64_t, uint64_t) relegated wontreturn; +void __check_fail_le(uint64_t, uint64_t) relegated wontreturn; +void __check_fail_lt(uint64_t, uint64_t) relegated wontreturn; +void __check_fail_ge(uint64_t, uint64_t) relegated wontreturn; +void __check_fail_gt(uint64_t, uint64_t) relegated wontreturn; +void __check_fail_aligned(unsigned, uint64_t) relegated wontreturn; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/log/die.c b/libc/log/die.c index 36055221..984b6bb3 100644 --- a/libc/log/die.c +++ b/libc/log/die.c @@ -28,7 +28,7 @@ /** * Aborts process after printing details on its current state. */ -relegated noreturn void __die(void) { +relegated wontreturn void __die(void) { static bool once; if (!once) { once = true; diff --git a/libc/log/err.c b/libc/log/err.c index 5f9ba961..a95c4d53 100644 --- a/libc/log/err.c +++ b/libc/log/err.c @@ -19,7 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/bsd.h" -noreturn void(err)(int eval, const char *fmt, ...) { +wontreturn void(err)(int eval, const char *fmt, ...) { va_list va; va_start(va, fmt); (verr)(eval, fmt, va); diff --git a/libc/log/errx.c b/libc/log/errx.c index 670a1cfc..e3feeb70 100644 --- a/libc/log/errx.c +++ b/libc/log/errx.c @@ -19,7 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/bsd.h" -noreturn void(errx)(int eval, const char *fmt, ...) { +wontreturn void(errx)(int eval, const char *fmt, ...) { va_list va; va_start(va, fmt); (verrx)(eval, fmt, va); diff --git a/libc/log/log.h b/libc/log/log.h index 5285c75d..a873b8a4 100644 --- a/libc/log/log.h +++ b/libc/log/log.h @@ -33,10 +33,10 @@ typedef struct FILE FILE; extern FILE *g_logfile; -void perror(const char *) relegated; /* print the last system error */ -void __die(void) relegated noreturn; /* print backtrace and abort() */ -void meminfo(int); /* shows malloc statistics &c. */ -void memsummary(int); /* light version of same thing */ +void perror(const char *) relegated; /* print the last system error */ +void __die(void) relegated wontreturn; /* print backtrace and abort() */ +void meminfo(int); /* shows malloc statistics &c. */ +void memsummary(int); /* light version of same thing */ uint16_t getttycols(uint16_t); int getttysize(int, struct winsize *) paramsnonnull(); bool isterminalinarticulate(void) nosideeffect; @@ -218,8 +218,8 @@ void fverbosef(ARGS, ...) asm("flogf") ATTR relegated libcesque; void vfverbosef(ARGS, va_list) asm("vflogf") ATTRV relegated libcesque; void fdebugf(ARGS, ...) asm("flogf") ATTR relegated libcesque; void vfdebugf(ARGS, va_list) asm("vflogf") ATTRV relegated libcesque; -void ffatalf(ARGS, ...) asm("flogf") ATTR relegated noreturn libcesque; -void vffatalf(ARGS, va_list) asm("vflogf") ATTRV relegated noreturn libcesque; +void ffatalf(ARGS, ...) asm("flogf") ATTR relegated wontreturn libcesque; +void vffatalf(ARGS, va_list) asm("vflogf") ATTRV relegated wontreturn libcesque; #undef ARGS #undef ATTR #undef ATTRV diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index 94f32d89..4bc735ab 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -51,17 +51,17 @@ STATIC_YOINK("stoa"); struct siginfo; -static const char kGregOrder[17] aligned(1) = { +static const char kGregOrder[17] forcealign(1) = { 13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, }; -static const char kGregNames[17][4] aligned(1) = { +static const char kGregNames[17][4] forcealign(1) = { "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "RDI", "RSI", "RBP", "RBX", "RDX", "RAX", "RCX", "RSP", "RIP", }; -static const char kGodHatesFlags[12] aligned(1) = "CVPRAKZSTIDO"; -static const char kCrashSigNames[8][5] aligned(1) = { +static const char kGodHatesFlags[12] forcealign(1) = "CVPRAKZSTIDO"; +static const char kCrashSigNames[8][5] forcealign(1) = { "QUIT", "FPE", "ILL", "SEGV", "TRAP", "ABRT", "BUS"}; int kCrashSigs[8]; diff --git a/libc/log/ubsan.internal.h b/libc/log/ubsan.internal.h index 21f92efa..f3cc3499 100644 --- a/libc/log/ubsan.internal.h +++ b/libc/log/ubsan.internal.h @@ -98,13 +98,13 @@ struct UbsanShiftOutOfBoundsData { }; void __ubsan_abort(const struct UbsanSourceLocation *, - const char *) relegated hidden noreturn; + const char *) relegated hidden wontreturn; void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *, - uintptr_t) relegated hidden noreturn; + uintptr_t) relegated hidden wontreturn; void ___ubsan_handle_type_mismatch_v1(struct UbsanTypeMismatchInfoClang *, - uintptr_t) relegated hidden noreturn; + uintptr_t) relegated hidden wontreturn; void __ubsan_handle_float_cast_overflow(void *, - void *) relegated hidden noreturn; + void *) relegated hidden wontreturn; #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_UBSAN_H_ */ diff --git a/libc/log/verr.c b/libc/log/verr.c index 81da2125..37d2daa2 100644 --- a/libc/log/verr.c +++ b/libc/log/verr.c @@ -23,7 +23,7 @@ #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -noreturn void(verr)(int eval, const char *fmt, va_list va) { +wontreturn void(verr)(int eval, const char *fmt, va_list va) { fprintf(stderr, "%s: %s%s%s[%m]: ", program_invocation_name, RED2, "ERROR", RESET); if (fmt) (vfprintf)(stderr, fmt, va); diff --git a/libc/log/verrx.c b/libc/log/verrx.c index ce86db5b..de8b147e 100644 --- a/libc/log/verrx.c +++ b/libc/log/verrx.c @@ -23,7 +23,7 @@ #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -noreturn void(verrx)(int eval, const char *fmt, va_list va) { +wontreturn void(verrx)(int eval, const char *fmt, va_list va) { fprintf(stderr, "%s: %s%s%s: ", program_invocation_name, RED2, "ERROR", RESET); if (fmt) (vfprintf)(stderr, fmt, va); diff --git a/libc/nexgen32e/bsf.h b/libc/nexgen32e/bsf.h index 7d161522..beaf2732 100644 --- a/libc/nexgen32e/bsf.h +++ b/libc/nexgen32e/bsf.h @@ -22,9 +22,11 @@ int bsfl(long); int bsfll(long long); int bsfmax(uintmax_t); +#ifdef __GNUC__ #define bsf(u) __builtin_ctz(u) #define bsfl(u) __builtin_ctzl(u) #define bsfll(u) __builtin_ctzll(u) +#endif COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/nexgen32e/bsr.h b/libc/nexgen32e/bsr.h index b0b640e2..74492e03 100644 --- a/libc/nexgen32e/bsr.h +++ b/libc/nexgen32e/bsr.h @@ -22,9 +22,11 @@ int bsrl(long); int bsrll(long long); int bsrmax(uintmax_t); +#ifdef __GNUC__ #define bsr(u) ((sizeof(int) * 8 - 1) ^ __builtin_clz(u)) #define bsrl(u) ((sizeof(long) * 8 - 1) ^ __builtin_clzl(u)) #define bsrll(u) ((sizeof(long long) * 8 - 1) ^ __builtin_clzll(u)) +#endif COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/nexgen32e/cescapec.S b/libc/nexgen32e/cescapec.S index 2ff8ea00..39bf5b73 100644 --- a/libc/nexgen32e/cescapec.S +++ b/libc/nexgen32e/cescapec.S @@ -36,32 +36,32 @@ cescapec: movzbl %cl,%ecx jmp *cescapectab(,%rcx,8) .Lanchorpoint: -.LBEL: mov $'a,%ah +.LBEL: mov $'a',%ah ret -.LBS: mov $'b,%ah +.LBS: mov $'b',%ah ret -.LHT: mov $'t,%ah +.LHT: mov $'t',%ah ret -.LLF: mov $'n,%ah +.LLF: mov $'n',%ah ret -.LVT: mov $'v,%ah +.LVT: mov $'v',%ah ret -.LFF: mov $'f,%ah +.LFF: mov $'f',%ah ret -.LCR: mov $'r,%ah +.LCR: mov $'r',%ah ret -.LDQ: mov $'\",%ah +.LDQ: mov $'\"',%ah ret -.LSQ: mov $'\',%ah +.LSQ: mov $'\'',%ah ret -.LBSL: mov $'\\,%ah +.LBSL: mov $'\\',%ah ret #ifdef __STRICT_ANSI__ -.LQM: mov $'?,%ah +.LQM: mov $'?',%ah ret .LESC: #elif defined(__GNUC__) -.LESC: mov $'e,%ah +.LESC: mov $'e',%ah ret .LQM: #endif diff --git a/tool/tags/keywords.c b/libc/nexgen32e/ctz.c similarity index 86% rename from tool/tags/keywords.c rename to libc/nexgen32e/ctz.c index 1406b62a..baa121f0 100644 --- a/tool/tags/keywords.c +++ b/libc/nexgen32e/ctz.c @@ -17,17 +17,9 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "tool/tags/keywords.inc" -#include "tool/tags/tags.h" +#include "libc/math.h" +#include "libc/nexgen32e/nexgen32e.h" -/** - * Returns small number for HTTP header, or -1 if not found. - */ -int GetKeyword(const char *str, size_t len) { - const struct KeywordSlot *slot; - if ((slot = LookupKeyword(str, len))) { - return slot->code; - } else { - return -1; - } +bool ctz(double x, double y) { + return __builtin_islessgreater(x, y); } diff --git a/libc/nexgen32e/ffs.S b/libc/nexgen32e/ffs.S index 375aea08..39be2372 100644 --- a/libc/nexgen32e/ffs.S +++ b/libc/nexgen32e/ffs.S @@ -41,7 +41,7 @@ ffs: .leafprologue bsf %edi,%eax or $-1,%edx cmovz %edx,%eax - add $1,%eax + inc %eax .leafepilogue .endfn ffs,globl .source __FILE__ diff --git a/libc/nexgen32e/ffsl.S b/libc/nexgen32e/ffsl.S index dac385dd..44327c06 100644 --- a/libc/nexgen32e/ffsl.S +++ b/libc/nexgen32e/ffsl.S @@ -41,7 +41,7 @@ ffsl: .leafprologue bsf %rdi,%rax or $-1,%edx cmovz %edx,%eax - add $1,%eax + inc %eax .leafepilogue .endfn ffsl,globl .alias ffsl,ffsll diff --git a/libc/nexgen32e/khalfcache3.S b/libc/nexgen32e/khalfcache3.S new file mode 100644 index 00000000..82744b84 --- /dev/null +++ b/libc/nexgen32e/khalfcache3.S @@ -0,0 +1,64 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.h" + +/ Half size of level 3 cache in bytes. + .initbss 202,_init_kHalfCache3 +kHalfCache3: + .quad 0 + .endobj kHalfCache3,globl + .previous + + .init.start 202,_init_kHalfCache3 + cmpl $3,kCpuids(%rip) + jbe 3f + xor %r8d,%r8d + mov $4,%r8d +1: mov %r8d,%eax + mov %r8d,%ecx + push %rbx + cpuid + mov %ebx,%r9d + pop %rbx + test $31,%al + je 3f + cmp $99,%al + jne 2f + mov %r9d,%eax + mov %r9d,%edx + inc %ecx + shr $12,%r9d + shr $22,%eax + and $0x0fff,%edx + and $0x03ff,%r9d + inc %eax + inc %edx + imul %edx,%eax + imul %ecx,%eax + lea 1(%r9),%ecx + imul %ecx,%eax + jmp 4f +2: inc %r8d + jmp 1b +3: mov $0x00400000,%eax +4: shr %eax + stosq + .init.end 202,_init_kHalfCache3 + .source __FILE__ diff --git a/libc/nexgen32e/loadxmm.S b/libc/nexgen32e/loadxmm.S index 14ed8372..e2cd61c9 100644 --- a/libc/nexgen32e/loadxmm.S +++ b/libc/nexgen32e/loadxmm.S @@ -22,7 +22,7 @@ / Loads XMM registers from buffer. / -/ @param %rdi points to &(aligned(16) uint8_t[256])[128] +/ @param %rdi points to &(forcealign(16) uint8_t[256])[128] / @note modern cpus have out-of-order execution engines loadxmm:.leafprologue movaps -0x80(%rdi),%xmm0 diff --git a/libc/nexgen32e/memcpy.S b/libc/nexgen32e/memcpy.S index a2ac30d8..89e553ca 100644 --- a/libc/nexgen32e/memcpy.S +++ b/libc/nexgen32e/memcpy.S @@ -112,7 +112,7 @@ MemCpy: .leafprologue .L1: mov (%rsi),%cl mov %cl,(%rdi) jmp .L0 -.Lerms: cmp $4*1024*1024,%rdx # TODO: getcachesize() +.Lerms: cmp kHalfCache3(%rip),%rdx ja .Lnts push %rdi push %rsi diff --git a/libc/nexgen32e/savexmm.S b/libc/nexgen32e/savexmm.S index a7739267..bec5a671 100644 --- a/libc/nexgen32e/savexmm.S +++ b/libc/nexgen32e/savexmm.S @@ -22,7 +22,7 @@ / Stores XMM registers to buffer. / -/ @param %rdi points to &(aligned(16) uint8_t[256])[128] +/ @param %rdi points to &(forcealign(16) uint8_t[256])[128] / @note modern cpus have out-of-order execution engines savexmm:.leafprologue movaps %xmm0,-0x80(%rdi) diff --git a/libc/nexgen32e/strstr-sse42.S b/libc/nexgen32e/strstr-sse42.S index 9e30ed9f..4750de8f 100644 --- a/libc/nexgen32e/strstr-sse42.S +++ b/libc/nexgen32e/strstr-sse42.S @@ -28,6 +28,21 @@ / @return rax is pointer to substring or NULL / @asyncsignalsafe strstr$sse42: - .strstr .Lequalordered + .leafprologue + mov %rdi,%rax + xor %ecx,%ecx +0: mov $-16,%rdx +1: add $16,%rdx + movaps (%rsi,%rdx),%xmm0 +2: add %rcx,%rax + lea (%rax,%rdx),%rdi + pcmpistri $.Lequalordered,(%rdi),%xmm0 +3: ja 2b # !CF (no match) && !ZF (need NUL-term) + jnc 4f # !CF (no match) && ZF (NUL-terminator) + jno 0b # !OF ← CF && CX!=0 (matched at offset) + jns 1b # !SF ← NUL ∉ XMM1 (need to match more) + jmp 5f # youtu.be/nVk1DjMtLWs +4: xor %eax,%eax +5: .leafepilogue .endfn strstr$sse42,globl,hidden .source __FILE__ diff --git a/libc/nt/runtime.h b/libc/nt/runtime.h index cb5a858c..282ecf90 100644 --- a/libc/nt/runtime.h +++ b/libc/nt/runtime.h @@ -33,7 +33,7 @@ bool32 WriteFile(int64_t hFile, const void *lpBuffer, struct NtOverlapped *opt_lpOverlapped); bool32 TerminateProcess(int64_t hProcess, uint32_t uExitCode); int64_t GetCurrentProcess(void) pureconst; -void ExitProcess(uint32_t uExitCode) noreturn; +void ExitProcess(uint32_t uExitCode) wontreturn; uint32_t GetLastError(void) nosideeffect; bool32 CloseHandle(int64_t hObject) nothrow nocallback; intptr_t GetStdHandle(int64_t nStdHandle) nosideeffect; diff --git a/libc/nt/struct/context.h b/libc/nt/struct/context.h index d15dceb6..1be8f2df 100644 --- a/libc/nt/struct/context.h +++ b/libc/nt/struct/context.h @@ -5,7 +5,7 @@ struct NtM128A { uint64_t Low; int64_t High; -} aligned(16); +} forcealign(16); struct NtXmmSaveArea32 { uint16_t ControlWord; @@ -53,7 +53,7 @@ struct NtContext { uint64_t LastBranchFromRip; uint64_t LastExceptionToRip; uint64_t LastExceptionFromRip; -} aligned(16); +} forcealign(16); #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_NT_STRUCT_CONTEXT_H_ */ diff --git a/libc/nt/thread.h b/libc/nt/thread.h index f8901295..70077781 100644 --- a/libc/nt/thread.h +++ b/libc/nt/thread.h @@ -37,7 +37,7 @@ int64_t CreateThread(struct NtSecurityAttributes *lpThreadAttributes, void *lpParameter, uint32_t dwCreationFlags, uint32_t *opt_lpThreadId); -void ExitThread(uint32_t dwExitCode) noreturn; +void ExitThread(uint32_t dwExitCode) wontreturn; int64_t GetCurrentThread(void); uint32_t GetCurrentThreadId(void); uint64_t SetThreadAffinityMask(int64_t hThread, uintptr_t dwThreadAffinityMask); diff --git a/libc/runtime/gc.h b/libc/runtime/gc.h index ef8bee5a..46aec7c4 100644 --- a/libc/runtime/gc.h +++ b/libc/runtime/gc.h @@ -25,7 +25,7 @@ COSMOPOLITAN_C_START_ /** * Same as longjmp() but runs gc() / defer() destructors. */ -void gclongjmp(jmp_buf, int) nothrow noreturn paramsnonnull(); +void gclongjmp(jmp_buf, int) nothrow wontreturn paramsnonnull(); /** * Calls FN(ARG) when function returns. diff --git a/libc/runtime/internal.h b/libc/runtime/internal.h index a5a12866..d70024cf 100644 --- a/libc/runtime/internal.h +++ b/libc/runtime/internal.h @@ -19,10 +19,10 @@ extern hidden void *g_stacktop; void _init(void) hidden; void _piro(int) hidden; void *__cxa_finalize(void *) hidden; -void _executive(int, char **, char **, long (*)[2]) hidden noreturn; -void __stack_chk_fail(void) noreturn relegated; -void __stack_chk_fail_local(void) noreturn relegated hidden; -void _jmpstack(void *, void *, ...) hidden noreturn; +void _executive(int, char **, char **, long (*)[2]) hidden wontreturn; +void __stack_chk_fail(void) wontreturn relegated; +void __stack_chk_fail_local(void) wontreturn relegated hidden; +void _jmpstack(void *, void *, ...) hidden wontreturn; long _setstack(void *, void *, ...) hidden; int GetDosArgv(const char16_t *, char *, size_t, char **, size_t) hidden; Elf64_Ehdr *MapElfRead(const char *, struct MappedFile *) hidden; diff --git a/libc/runtime/interruptiblecall.c b/libc/runtime/interruptiblecall.c index 6a605b81..619d63ab 100644 --- a/libc/runtime/interruptiblecall.c +++ b/libc/runtime/interruptiblecall.c @@ -29,7 +29,7 @@ STATIC_YOINK("_init_onntconsoleevent"); static struct InterruptibleCall *g_interruptiblecall; -noreturn static void interruptcall(int sig) { +wontreturn static void interruptcall(int sig) { longjmp(g_interruptiblecall->jb, 1); unreachable; } diff --git a/libc/runtime/print.greg.c b/libc/runtime/print.greg.c index 8d5e51b9..6995d855 100644 --- a/libc/runtime/print.greg.c +++ b/libc/runtime/print.greg.c @@ -32,7 +32,7 @@ static privileged void __print$nt(const void *data, size_t len) { int64_t hand; uint32_t wrote; - char xmm[256] aligned(16); + char xmm[256] forcealign(16); savexmm(&xmm[128]); hand = __imp_GetStdHandle(kNtStdErrorHandle); __imp_WriteFile(hand, data, len, &wrote, NULL); diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index d464b0ab..423a3e32 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -6,45 +6,45 @@ COSMOPOLITAN_C_START_ │ cosmopolitan § runtime ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -typedef long jmp_buf[8] aligned(CACHELINE); +typedef long jmp_buf[8] forcealign(CACHELINE); -extern int g_argc; /* CRT */ -extern char **g_argv; /* CRT */ -extern char **environ; /* CRT */ -extern unsigned long *g_auxv; /* CRT */ -extern char *program_invocation_name; /* RII */ -extern char *program_invocation_short_name; /* RII */ -extern uint64_t g_syscount; /* RII */ -extern const uint64_t kStartTsc; /* RII */ -extern const char kTmpPath[]; /* RII */ -extern const char kNtSystemDirectory[]; /* RII */ -extern const char kNtWindowsDirectory[]; /* RII */ -extern unsigned char _base[] aligned(PAGESIZE); /* αpε */ -extern unsigned char _ehead[] aligned(PAGESIZE); /* αpε */ -extern unsigned char _etext[] aligned(PAGESIZE); /* αpε */ -extern unsigned char _edata[] aligned(PAGESIZE); /* αpε */ -extern unsigned char _end[] aligned(PAGESIZE); /* αpε */ -extern unsigned char _ereal; /* αpε */ -extern unsigned char __privileged_start; /* αpε */ -extern unsigned char __test_start; /* αpε */ -extern unsigned char __ro; /* αpε */ -extern unsigned char *__relo_start[]; /* αpε */ -extern unsigned char *__relo_end[]; /* αpε */ -extern uint8_t __zip_start[]; /* αpε */ -extern uint8_t __zip_end[]; /* αpε */ +extern int g_argc; /* CRT */ +extern char **g_argv; /* CRT */ +extern char **environ; /* CRT */ +extern unsigned long *g_auxv; /* CRT */ +extern char *program_invocation_name; /* RII */ +extern char *program_invocation_short_name; /* RII */ +extern uint64_t g_syscount; /* RII */ +extern const uint64_t kStartTsc; /* RII */ +extern const char kTmpPath[]; /* RII */ +extern const char kNtSystemDirectory[]; /* RII */ +extern const char kNtWindowsDirectory[]; /* RII */ +extern unsigned char _base[] forcealign(PAGESIZE); /* αpε */ +extern unsigned char _ehead[] forcealign(PAGESIZE); /* αpε */ +extern unsigned char _etext[] forcealign(PAGESIZE); /* αpε */ +extern unsigned char _edata[] forcealign(PAGESIZE); /* αpε */ +extern unsigned char _end[] forcealign(PAGESIZE); /* αpε */ +extern unsigned char _ereal; /* αpε */ +extern unsigned char __privileged_start; /* αpε */ +extern unsigned char __test_start; /* αpε */ +extern unsigned char __ro; /* αpε */ +extern unsigned char *__relo_start[]; /* αpε */ +extern unsigned char *__relo_end[]; /* αpε */ +extern uint8_t __zip_start[]; /* αpε */ +extern uint8_t __zip_end[]; /* αpε */ long missingno(); void mcount(void); unsigned long getauxval(unsigned long); void *mapanon(size_t) vallocesque attributeallocsize((1)); int setjmp(jmp_buf) libcesque returnstwice paramsnonnull(); -void longjmp(jmp_buf, int) libcesque noreturn paramsnonnull(); -void exit(int) noreturn; -void _exit(int) libcesque noreturn; -void _Exit(int) libcesque noreturn; -void abort(void) noreturn noinstrument; -void panic(void) noreturn noinstrument privileged; -void triplf(void) noreturn noinstrument privileged; +void longjmp(jmp_buf, int) libcesque wontreturn paramsnonnull(); +void exit(int) wontreturn; +void _exit(int) libcesque wontreturn; +void _Exit(int) libcesque wontreturn; +void abort(void) wontreturn noinstrument; +void panic(void) wontreturn noinstrument privileged; +void triplf(void) wontreturn noinstrument privileged; int __cxa_atexit(void *, void *, void *) libcesque; int atfork(void *, void *) libcesque; int atexit(void (*)(void)) libcesque; diff --git a/libc/runtime/valist.c b/libc/runtime/valist.c new file mode 100644 index 00000000..57f64511 --- /dev/null +++ b/libc/runtime/valist.c @@ -0,0 +1,51 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/valist.h" + +static void *__va_arg_mem(struct __va *ap, unsigned long sz, unsigned align) { + void *r = ap->overflow_arg_area; + if (align > 8) r = (void *)(((unsigned long)r + 15) / 16 * 16); + ap->overflow_arg_area = (void *)(((unsigned long)r + sz + 7) / 8 * 8); + return r; +} + +void *__va_arg(struct __va *ap, unsigned long sz, unsigned align, unsigned k) { + void *r; + switch (k) { + case 0: + if (ap->gp_offset < 48) { + r = (char *)ap->reg_save_area + ap->gp_offset; + ap->gp_offset += 8; + return r; + } else { + return __va_arg_mem(ap, sz, align); + } + case 1: + if (ap->fp_offset < 112) { + r = (char *)ap->reg_save_area + ap->fp_offset; + ap->fp_offset += 8; + return r; + } else { + return __va_arg_mem(ap, sz, align); + } + default: + return __va_arg_mem(ap, sz, align); + } +} diff --git a/libc/runtime/valist.h b/libc/runtime/valist.h new file mode 100644 index 00000000..28ffc9f5 --- /dev/null +++ b/libc/runtime/valist.h @@ -0,0 +1,17 @@ +#ifndef COSMOPOLITAN_LIBC_RUNTIME_VALIST_H_ +#define COSMOPOLITAN_LIBC_RUNTIME_VALIST_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct __va { + unsigned int gp_offset; + unsigned int fp_offset; + void *overflow_arg_area; + void *reg_save_area; +}; + +void *__va_arg(struct __va *, unsigned long, unsigned, unsigned); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_RUNTIME_VALIST_H_ */ diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index c5eff670..48cd378b 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -119,7 +119,7 @@ static textwindows char *AllocateMemory(void *addr, size_t size, int64_t *h) { kNtNumaNoPreferredNode); } -static textwindows noreturn void WinMainNew(void) { +static textwindows wontreturn void WinMainNew(void) { int64_t h; size_t size; int i, count; diff --git a/libc/stdio/g_stderr.c b/libc/stdio/g_stderr.c index 7f25f1fb..d4871277 100644 --- a/libc/stdio/g_stderr.c +++ b/libc/stdio/g_stderr.c @@ -24,7 +24,7 @@ STATIC_YOINK("_init_g_stderr"); FILE *stderr; hidden FILE g_stderr; -hidden unsigned char g_stderr_buf[BUFSIZ] aligned(PAGESIZE); +hidden unsigned char g_stderr_buf[BUFSIZ] forcealign(PAGESIZE); static textstartup void _init_g_stderr2() { _fflushregister(stderr); diff --git a/libc/stdio/g_stdin.c b/libc/stdio/g_stdin.c index a0f65956..63249d96 100644 --- a/libc/stdio/g_stdin.c +++ b/libc/stdio/g_stdin.c @@ -24,7 +24,7 @@ STATIC_YOINK("_init_g_stdin"); FILE *stdin; hidden FILE g_stdin; -hidden unsigned char g_stdin_buf[BUFSIZ] aligned(PAGESIZE); +hidden unsigned char g_stdin_buf[BUFSIZ] forcealign(PAGESIZE); static textstartup void g_stdin_init() { _fflushregister(stdin); diff --git a/libc/stdio/g_stdout.c b/libc/stdio/g_stdout.c index 251807e0..2ef26577 100644 --- a/libc/stdio/g_stdout.c +++ b/libc/stdio/g_stdout.c @@ -27,7 +27,7 @@ STATIC_YOINK("_init_g_stdout"); FILE *stdout; hidden FILE g_stdout; -hidden unsigned char g_stdout_buf[BUFSIZ] aligned(PAGESIZE); +hidden unsigned char g_stdout_buf[BUFSIZ] forcealign(PAGESIZE); static textstartup void _init_g_stdout2() { struct FILE *sf; diff --git a/libc/stdio/mkstemp.c b/libc/stdio/mkstemp.c index a2103175..bd672f43 100644 --- a/libc/stdio/mkstemp.c +++ b/libc/stdio/mkstemp.c @@ -19,4 +19,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/temp.h" -int mkstemp(char *template) { return mkostempsm(template, 0, 0, 0600); } +int mkstemp(char *template) { + return mkostempsm(template, 0, 0, 0600); +} diff --git a/libc/str/endswith16.c b/libc/str/endswith16.c index de930973..cabbf2cc 100644 --- a/libc/str/endswith16.c +++ b/libc/str/endswith16.c @@ -19,14 +19,16 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -#undef char -#undef endswith -#undef strlen -#undef strnlen - -#define char char16_t -#define endswith endswith16 -#define strlen strlen16 -#define strnlen strnlen16 - -#include "libc/str/endswith.c" +/** + * Returns true if s has suffix. + * + * @param s is a NUL-terminated string + * @param suffix is also NUL-terminated + */ +bool endswith16(const char16_t *s, const char16_t *suffix) { + size_t n, m; + n = strlen16(s); + m = strlen16(suffix); + if (m > n) return false; + return memcmp(s + n - m, suffix, m * sizeof(char16_t)) == 0; +} diff --git a/libc/str/startswith16.c b/libc/str/startswith16.c index af0d17b6..178d4c81 100644 --- a/libc/str/startswith16.c +++ b/libc/str/startswith16.c @@ -19,14 +19,16 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -#undef char -#undef startswith -#undef strlen -#undef strncmp - -#define char char16_t -#define startswith startswith16 -#define strlen strlen16 -#define strncmp strncmp16 - -#include "libc/str/startswith.c" +/** + * Returns true if s has prefix. + * + * @param s is a NUL-terminated string + * @param prefix is also NUL-terminated + */ +bool startswith16(const char16_t *s, const char16_t *prefix) { + for (;;) { + if (!*prefix) return true; + if (!*s) return false; + if (*s++ != *prefix++) return false; + } +} diff --git a/libc/str/str.h b/libc/str/str.h index 1191ca3d..238e3b63 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -238,8 +238,8 @@ char *strsignal(int) returnsnonnull libcesque; ╚────────────────────────────────────────────────────────────────────────────│*/ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) -char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque; -#define strncpy(DEST, SRC, N) _strncpy(DEST, SRC, N) /* pacify bad warning */ +char *__strncpy(char *, const char *, size_t) memcpyesque; +#define strncpy(DEST, SRC, N) __strncpy(DEST, SRC, N) /* pacify bad warning */ #define explicit_bzero(STR, BYTES) \ do { \ @@ -318,7 +318,7 @@ char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque; size_t SiZe = (SIZE); \ size_t Rcx; \ asm("rep movsb" \ - : "=D"(Rdi), "=S"(Rsi), "=D"(Rcx), "=m"(*(char(*)[SiZe])(Dest)) \ + : "=D"(Rdi), "=S"(Rsi), "=c"(Rcx), "=m"(*(char(*)[SiZe])(Dest)) \ : "0"(Dest), "1"(Src), "2"(SiZe), "m"(*(const char(*)[SiZe])(Src)) \ : "cc"); \ Rdi; \ @@ -351,9 +351,6 @@ char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque; #endif /* hosted/sse2/unbloat */ -size_t _strlen(const char *s) asm("strlen") strlenesque; -void *_memchr(const void *, int, size_t) asm("memchr") strlenesque; - #endif /* __GNUC__ && !__STRICT_ANSI__ */ COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/str/strncpy.thunk.S b/libc/str/strncpy.thunk.S new file mode 100644 index 00000000..3fc23217 --- /dev/null +++ b/libc/str/strncpy.thunk.S @@ -0,0 +1,24 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.h" + +__strncpy: + jmp strncpy + .endfn __strncpy,globl diff --git a/libc/str/strpbrk.c b/libc/str/strpbrk.c index 690abf92..facc59f5 100644 --- a/libc/str/strpbrk.c +++ b/libc/str/strpbrk.c @@ -24,7 +24,7 @@ * Returns pointer to first byte matching any in accept, or NULL. * @asyncsignalsafe */ -char *(strpbrk)(const char *s, const char *accept) { +char *strpbrk(const char *s, const char *accept) { size_t i; if (accept[0]) { if (!accept[1]) { diff --git a/libc/str/strpbrk16.c b/libc/str/strpbrk16.c index 8e56fee9..8ae8d60d 100644 --- a/libc/str/strpbrk16.c +++ b/libc/str/strpbrk16.c @@ -20,10 +20,22 @@ #include "libc/nexgen32e/hascharacter.internal.h" #include "libc/str/str.h" -#undef strpbrk -#define char char16_t -#define HasCharacter HasCharacter16 -#define strpbrk strpbrk16 -#define strchr(x, y) strchr16(x, y) - -#include "libc/str/strpbrk.c" +/** + * Returns pointer to first byte matching any in accept, or NULL. + * @asyncsignalsafe + */ +char16_t *strpbrk16(const char16_t *s, const char16_t *accept) { + size_t i; + if (accept[0]) { + if (!accept[1]) { + return strchr16(s, accept[0]); + } else { + for (i = 0; s[i]; ++i) { + if (HasCharacter16(s[i], accept)) { + return (/*unconst*/ char16_t *)&s[i]; + } + } + } + } + return NULL; +} diff --git a/libc/str/strspn.c b/libc/str/strspn.c index 7a13deaf..f6b0b4d4 100644 --- a/libc/str/strspn.c +++ b/libc/str/strspn.c @@ -27,7 +27,7 @@ * @see strcspn(), strtok_r() * @asyncsignalsafe */ -size_t(strspn)(const char *s, const char *accept) { +size_t strspn(const char *s, const char *accept) { size_t i; for (i = 0; s[i]; ++i) { if (!HasCharacter(s[i], accept)) { diff --git a/libc/str/strspn16.c b/libc/str/strspn16.c index b3649efa..96e704e0 100644 --- a/libc/str/strspn16.c +++ b/libc/str/strspn16.c @@ -20,9 +20,19 @@ #include "libc/nexgen32e/hascharacter.internal.h" #include "libc/str/str.h" -#undef strspn -#define char char16_t -#define HasCharacter HasCharacter16 -#define strspn strspn16 - -#include "libc/str/strspn.c" +/** + * Returns prefix length, consisting of chars in accept. + * + * @param accept is nul-terminated character set + * @see strcspn(), strtok_r() + * @asyncsignalsafe + */ +size_t strspn16(const char16_t *s, const char16_t *accept) { + size_t i; + for (i = 0; s[i]; ++i) { + if (!HasCharacter16(s[i], accept)) { + break; + } + } + return i; +} diff --git a/libc/str/strstr.c b/libc/str/strstr.c index ac49df17..d3b69595 100644 --- a/libc/str/strstr.c +++ b/libc/str/strstr.c @@ -18,7 +18,6 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/alg.h" -#include "libc/dce.h" #include "libc/nexgen32e/x86feature.h" #include "libc/str/internal.h" #include "libc/str/str.h" @@ -32,22 +31,26 @@ * @asyncsignalsafe * @see memmem() */ -char *(strstr)(const char *haystack, const char *needle) { +char *strstr(const char *haystack, const char *needle) { + size_t i; if (needle[0]) { if (needle[1]) { - if (!((intptr_t)needle & 0xf) && X86_HAVE(SSE4_2)) { - return strstr$sse42(haystack, needle); - } else { - size_t needlelen; - alignas(16) char needle2[64]; - needlelen = strlen(needle); - if (needlelen < 64 && X86_HAVE(SSE4_2)) { - memcpy(needle2, needle, (needlelen + 1) * sizeof(char)); - return strstr$sse42(haystack, needle2); - } else { - return tinystrstr(haystack, needle); + for (;;) { +#if 0 /* todo: fix me */ + if (!((uintptr_t)haystack & 15) && X86_HAVE(SSE4_2) && + (((uintptr_t)needle + strlen(needle)) & 0xfff) <= 0xff0) { + return strstr$sse42(haystack, needle); } +#endif + for (i = 0;;) { + if (!needle[i]) return haystack; + if (!haystack[i]) break; + if (needle[i] != haystack[i]) break; + ++i; + } + if (!*haystack++) break; } + return NULL; } else { return strchr(haystack, needle[0]); } diff --git a/libc/str/wcsendswith.c b/libc/str/wcsendswith.c index 045a8edd..890b88b9 100644 --- a/libc/str/wcsendswith.c +++ b/libc/str/wcsendswith.c @@ -19,14 +19,16 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -#undef char -#undef endswith -#undef strlen -#undef strnlen - -#define char wchar_t -#define endswith wcsendswith -#define strlen wcslen -#define strnlen wcsnlen - -#include "libc/str/endswith.c" +/** + * Returns true if s has suffix. + * + * @param s is a NUL-terminated string + * @param suffix is also NUL-terminated + */ +bool wcsendswith(const wchar_t *s, const wchar_t *suffix) { + size_t n, m; + n = wcslen(s); + m = wcslen(suffix); + if (m > n) return false; + return memcmp(s + n - m, suffix, m * sizeof(wchar_t)) == 0; +} diff --git a/libc/str/wcspbrk.c b/libc/str/wcspbrk.c index 540b435c..0ef9aefd 100644 --- a/libc/str/wcspbrk.c +++ b/libc/str/wcspbrk.c @@ -20,10 +20,22 @@ #include "libc/nexgen32e/hascharacter.internal.h" #include "libc/str/str.h" -#undef strpbrk -#define char wchar_t -#define HasCharacter HasCharacterWide -#define strpbrk wcspbrk -#define strchr(x, y) wcschr(x, y) - -#include "libc/str/strpbrk.c" +/** + * Returns pointer to first byte matching any in accept, or NULL. + * @asyncsignalsafe + */ +wchar_t *wcspbrk(const wchar_t *s, const wchar_t *accept) { + size_t i; + if (accept[0]) { + if (!accept[1]) { + return wcschr(s, accept[0]); + } else { + for (i = 0; s[i]; ++i) { + if (HasCharacterWide(s[i], accept)) { + return (/*unconst*/ wchar_t *)&s[i]; + } + } + } + } + return NULL; +} diff --git a/libc/str/wcsspn.c b/libc/str/wcsspn.c index 967b66bb..e2bb288e 100644 --- a/libc/str/wcsspn.c +++ b/libc/str/wcsspn.c @@ -20,9 +20,19 @@ #include "libc/nexgen32e/hascharacter.internal.h" #include "libc/str/str.h" -#undef strspn -#define char wchar_t -#define HasCharacter HasCharacterWide -#define strspn wcsspn - -#include "libc/str/strspn.c" +/** + * Returns prefix length, consisting of chars in accept. + * + * @param accept is nul-terminated character set + * @see strcspn(), strtok_r() + * @asyncsignalsafe + */ +size_t wcsspn(const wchar_t *s, const wchar_t *accept) { + size_t i; + for (i = 0; s[i]; ++i) { + if (!HasCharacterWide(s[i], accept)) { + break; + } + } + return i; +} diff --git a/libc/str/wcsstartswith.c b/libc/str/wcsstartswith.c index 50c1e5c9..087b32d8 100644 --- a/libc/str/wcsstartswith.c +++ b/libc/str/wcsstartswith.c @@ -19,14 +19,16 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -#undef char -#undef startswith -#undef strlen -#undef strncmp - -#define char wchar_t -#define startswith wcsstartswith -#define strlen wcslen -#define strncmp wcsncmp - -#include "libc/str/startswith.c" +/** + * Returns true if s has prefix. + * + * @param s is a NUL-terminated string + * @param prefix is also NUL-terminated + */ +bool wcsstartswith(const wchar_t *s, const wchar_t *prefix) { + for (;;) { + if (!*prefix) return true; + if (!*s) return false; + if (*s++ != *prefix++) return false; + } +} diff --git a/libc/testlib/benchrunner.c b/libc/testlib/benchrunner.c index 6604b0c6..04df8fff 100644 --- a/libc/testlib/benchrunner.c +++ b/libc/testlib/benchrunner.c @@ -25,8 +25,8 @@ #include "libc/sysv/consts/mlock.h" #include "libc/testlib/testlib.h" -double g_avx2_juiceup_doubles_[4] aligned(32); -unsigned long long g_avx2_juiceup_quadwords_[4] aligned(32); +double g_avx2_juiceup_doubles_[4] forcealign(32); +unsigned long long g_avx2_juiceup_quadwords_[4] forcealign(32); void testlib_benchwarmup(void) { /* get mathematical parts of cpu juiced up */ diff --git a/libc/testlib/formatfloat.c b/libc/testlib/formatfloat.c index 18cd5dde..d97aa6e8 100644 --- a/libc/testlib/formatfloat.c +++ b/libc/testlib/formatfloat.c @@ -20,11 +20,12 @@ #include "libc/fmt/fmt.h" #include "libc/mem/mem.h" #include "libc/testlib/testlib.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" testonly char *testlib_formatfloat(long double x) { - char dtoabuf[32]; + char buf[32]; char *str = malloc(256); - sprintf(str, "%Lf (%s)", x, g_fmt(dtoabuf, x)); + g_xfmt_p(buf, &x, 15, sizeof(buf), 0); + sprintf(str, "%Lf (%s)", x, buf); return str; } diff --git a/libc/testlib/testlib.h b/libc/testlib/testlib.h index 8e4a903a..6ca22fbd 100644 --- a/libc/testlib/testlib.h +++ b/libc/testlib/testlib.h @@ -350,7 +350,7 @@ void testlib_runfixtures(testfn_t *, testfn_t *, const struct TestFixture *, const struct TestFixture *); int testlib_countfixtures(const struct TestFixture *, const struct TestFixture *); -void testlib_abort(void) noreturn relegated; +void testlib_abort(void) wontreturn relegated; bool testlib_strequals(size_t, const void *, const void *) nosideeffect; bool testlib_strnequals(size_t, const void *, const void *, size_t) nosideeffect; diff --git a/libc/testlib/testlib.mk b/libc/testlib/testlib.mk index 2044a9f8..1e9b1ff2 100644 --- a/libc/testlib/testlib.mk +++ b/libc/testlib/testlib.mk @@ -99,7 +99,7 @@ LIBC_TESTLIB_A_DIRECTDEPS = \ LIBC_UNICODE \ LIBC_X \ LIBC_ZIPOS \ - THIRD_PARTY_DTOA + THIRD_PARTY_GDTOA LIBC_TESTLIB_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_TESTLIB_A_DIRECTDEPS),$($(x)))) diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index 4836ee85..ae40f7a1 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -35,7 +35,7 @@ void testlib_finish(void) { } } -noreturn void testlib_abort(void) { +wontreturn void testlib_abort(void) { testlib_finish(); exit(MIN(255, g_testlib_failed)); unreachable; diff --git a/libc/x/x.h b/libc/x/x.h index 476feb48..087b7ccb 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -28,8 +28,8 @@ int xwrite(int, const void *, uint64_t); │ cosmopolitan § eXtended apis » memory ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -void xdie(void) noreturn; -char *xdtoa(double) _XMAL; +void xdie(void) wontreturn; +char *xdtoa(long double) _XMAL; char *xasprintf(const char *, ...) printfesque(1) paramsnonnull((1)) _XMAL; char *xvasprintf(const char *, va_list) _XPNN _XMAL; char *xgetline(struct FILE *) _XPNN mallocesque; diff --git a/libc/x/x.mk b/libc/x/x.mk index db5f5a24..f494697e 100644 --- a/libc/x/x.mk +++ b/libc/x/x.mk @@ -43,7 +43,7 @@ LIBC_X_A_DIRECTDEPS = \ LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ - THIRD_PARTY_DTOA + THIRD_PARTY_GDTOA LIBC_X_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_X_A_DIRECTDEPS),$($(x)))) diff --git a/libc/x/xdtoa.c b/libc/x/xdtoa.c index 626e0461..c52c8a94 100644 --- a/libc/x/xdtoa.c +++ b/libc/x/xdtoa.c @@ -19,14 +19,15 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/mem/mem.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" /** * Converts double to string w/ high-accuracy the easy way. * - * @see gc(), free() + * @return string that needs to be free'd */ -char *xdtoa(double d) { - char buf[32]; - return xstrdup(g_fmt(buf, d)); +char *xdtoa(long double d) { + char *p = xmalloc(32); + g_xfmt_p(p, &d, 16, 32, 2); + return p; } diff --git a/test/dsp/core/dct_test.c b/test/dsp/core/dct_test.c deleted file mode 100644 index 9e767607..00000000 --- a/test/dsp/core/dct_test.c +++ /dev/null @@ -1,88 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "dsp/core/core.h" -#include "libc/math.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/testlib/ezbench.h" -#include "libc/testlib/testlib.h" -#include "libc/time/time.h" -#include "tool/viz/lib/formatstringtable-testlib.h" - -TEST(dct, test) { - float M[8][8] /* clang-format off */ = { - {.509804, .513725, .094118, .219608, .027451, .294118, .172549, .658824}, - {.019608, .070588, .196078, .015686, .172549, .458824, .713725, .294118}, - {.380392, .341176, .235294, .737255, .741176, .968627, .607843, .12549}, - {.560784, .843137, .639216, .929412, .756863, .113725, .643137, .435294}, - {.878431, .576471, .737255, .356863, .8, .878431, .682353, .866667}, - {.780392, .070588, .866667, .607843, .792157, .47451, .427451, .043137}, - {.133333, .976471, .698039, .662745, .035294, .207843, .831373, .627451}, - {.313725, .580392, .858824, .631373, .784314, .972549, .27451, .94902}, - } /* clang-format on */; - dctjpeg(M); - EXPECT_FLTMATRIXEQ(5, rint, 8, 8, M, "\n\ -32.86666 -1.46274 -1.4456 -.43895 -1.17255 .19084 .05736 .01672\n\ --9.41551 -2.72135 3.7228 5.47448 .74604 .91144 -1.22542 -.41829\n\ --6.32875 -4.21755 4.42546 -3.86307 -1.93691 -2.1173 1.00377 -1.0752\n\ --2.58232 3.67887 5.65331 -.25753 .89732 1.09837 .93163 .61133\n\ - 4.23922 1.36747 3.29469 -1.63407 2.78039 -3.0021 .7602 -.21367\n\ - -.11643 3.93022 .80678 -3.70514 .13347 .54381 -2.15087 -.52343\n\ - .64248 1.19093 -2.94494 2.66037 1.6624 .04414 .99807 .00514\n\ - .61622 -.76318 .75918 .41939 -.38075 -.30623 .09867 -.19237"); -} - -/* TEST(dct, test2) { */ -/* float M[8][8] /\* clang-format off *\/ = { */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* {.5,.5,.5,.5,.5,.5,.5,.5}, */ -/* } /\* clang-format on *\/; */ -/* dctjpeg(M); */ -/* EXPECT_FLTMATRIXEQ(5, rint, 8, 8, M, "\n\ */ -/* 32.86666 -1.46274 -1.4456 -.43895 -1.17255 .19084 .05736 .01672\n\ */ -/* -9.41551 -2.72135 3.7228 5.47448 .74604 .91144 -1.22542 -.41829\n\ */ -/* -6.32875 -4.21755 4.42546 -3.86307 -1.93691 -2.1173 1.00377 -1.0752\n\ */ -/* -2.58232 3.67887 5.65331 -.25753 .89732 1.09837 .93163 .61133\n\ */ -/* 4.23922 1.36747 3.29469 -1.63407 2.78039 -3.0021 .7602 -.21367\n\ */ -/* -.11643 3.93022 .80678 -3.70514 .13347 .54381 -2.15087 -.52343\n\ */ -/* .64248 1.19093 -2.94494 2.66037 1.6624 .04414 .99807 .00514\n\ */ -/* .61622 -.76318 .75918 .41939 -.38075 -.30623 .09867 -.19237"); */ -/* } */ - -BENCH(dct, bench) { - float M[8][8] /* clang-format off */ = { - {.101961, .486275, .082353, .082353, .937255, .321569, .14902, .270588}, - {.384314, .062745, .152941, .003922, .921569, .015686, .247059, 0}, - {.760784, .023529, .411765, .443137, .862745, .85098, .435294, .631373}, - {.309804, .141176, .54902, .984314, .478431, .6, .364706, .643137}, - {.780392, .811765, .458824, .964706, .439216, .941176, .321569, .313725}, - {.596078, .207843, .133333, .345098, .278431, .192157, .52549, .627451}, - {.952941, .090196, .290196, .717647, .686275, .713725, .54902, .411765}, - {.109804, .121569, .403922, .27451, .470588, .007843, .168627, .105882}, - } /* clang-format on */; - void *data = tgc(tmalloc(sizeof(M))); - EZBENCH2("dct", memcpy(data, M, sizeof(M)), EXPROPRIATE(dctjpeg(data))); -} diff --git a/test/dsp/core/illumination_test.c b/test/dsp/core/illumination_test.c index b9034fbf..b80bd738 100644 --- a/test/dsp/core/illumination_test.c +++ b/test/dsp/core/illumination_test.c @@ -29,18 +29,18 @@ TEST(GetChromaticAdaptationMatrix, testSuperiorIlluminationBannedInCalifornia) { double M[3][3]; GetChromaticAdaptationMatrix(M, kIlluminantD65, kIlluminantA); EXPECT_DBLMATRIXEQ(5, rint, 3, 3, M, "\n\ -1.21646 .11099 -.15493\n\ - .15333 .91523 -.056\n\ --.02395 .0359 .31475"); + 1.2165 .11099 -.15493\n\ + .15333 .91523 -.055995\n\ +-.023947 .035898 .31475"); } TEST(GetChromaticAdaptationMatrix, testD65ToD50_soWeCanCieLab) { double M[3][3]; GetChromaticAdaptationMatrix(M, kIlluminantD65, kIlluminantD50); EXPECT_DBLMATRIXEQ(6, rint, 3, 3, M, "\n\ -1.047811 .022887 -.050127\n\ - .029542 .990484 -.017049\n\ --.009234 .015044 .752132"); + 1.04781 .0228866 -.050127\n\ + .0295424 .990484 -.0170491\n\ +-.00923449 .0150436 .752132"); } BENCH(GetChromaticAdaptationMatrix, bench) { diff --git a/test/dsp/core/inv3_test.c b/test/dsp/core/inv3_test.c index 3cd54be0..da22ebb4 100644 --- a/test/dsp/core/inv3_test.c +++ b/test/dsp/core/inv3_test.c @@ -28,9 +28,9 @@ TEST(inv3, test) { double M[3][3]; inv3(M, kBradford, det3(kBradford)); EXPECT_DBLMATRIXEQ(7, rint, 3, 3, M, "\n\ - .9869929 -.1470543 .1599627\n\ - .4323053 .5183603 .0492912\n\ --.0085287 .0400428 .9684867"); + .9869929 -.1470543 .1599627\n\ + .4323053 .5183603 .04929123\n\ +-.008528665 .04004282 .9684867"); } BENCH(inv3, bench) { diff --git a/test/dsp/tty/windex_test.c b/test/dsp/tty/windex_test.c index 5e874981..712a1560 100644 --- a/test/dsp/tty/windex_test.c +++ b/test/dsp/tty/windex_test.c @@ -31,7 +31,7 @@ unsigned windex$k8(short *, size_t) hidden; unsigned windex$avx2(short *, size_t) hidden; unsigned windex$sse4(short *, size_t) hidden; -const short kW[64] aligned(32) = { +const short kW[64] forcealign(32) = { 8281, 3883, 1365, 1786, 9006, 3681, 5563, 8013, 5787, 9063, 2923, 3564, 6122, 32, 1436, 0741, 7957, 9219, 1320, 2083, 1904, 8905, 2465, 9122, 9563, 1290, 4474, 3988, 9920, 8325, 1088, 2915, 33, @@ -40,13 +40,13 @@ const short kW[64] aligned(32) = { 1730, 2041, 7707, 5096, 6876, 1324, 1242, 5283, 0x7fff, }; -const short kW2[32] aligned(32) = { +const short kW2[32] forcealign(32) = { 8281, 1, 1365, 1786, 9006, 3681, 5563, 8013, 5787, 9063, 2923, 3564, 6122, 32, 1436, 0741, 7957, 9219, 1320, 2083, 1904, 8905, 2465, 9122, 9563, 1290, 4474, 3988, 9920, 8325, 1088, 2915, }; -const short kW3[64] aligned(32) = { +const short kW3[64] forcealign(32) = { 8281, 0x7fff, 1365, 1786, 9006, 3681, 5563, 8013, 5787, 9063, 2923, 3564, 6122, 32, 1436, 0741, 7957, 9219, 1320, 2083, 1904, 8905, 2465, 9122, 9563, 1290, 4474, 3988, 9920, 8325, 1088, 2915, 33, @@ -64,7 +64,7 @@ const short kW3[64] aligned(32) = { }) TEST(windex, testRealWorldPicks) { - const short kPicks[96] aligned(32) = { + const short kPicks[96] forcealign(32) = { 103, 85, 145, 146, 121, 103, 145, 187, 146, 189, 121, 103, 139, 121, 63, 105, 105, 147, 60, 103, 103, 146, 121, 103, 139, 121, 139, 121, 157, 139, diff --git a/test/libc/conv/strtoimax_test.c b/test/libc/conv/strtoimax_test.c index 3e637e37..8afb4122 100644 --- a/test/libc/conv/strtoimax_test.c +++ b/test/libc/conv/strtoimax_test.c @@ -21,10 +21,21 @@ #include "libc/conv/conv.h" #include "libc/testlib/testlib.h" -TEST(strtoimax, testZero) { EXPECT_EQ(0, strtoimax("0", NULL, 0)); } -TEST(strtoimax, testDecimal) { EXPECT_EQ(-123, strtoimax("-123", NULL, 0)); } -TEST(strtoimax, testHex) { EXPECT_EQ(-255, strtoimax("-0xff", NULL, 0)); } -TEST(strtoimax, testOctal) { EXPECT_EQ(-123, strtoimax("-0173", NULL, 0)); } +TEST(strtoimax, testZero) { + EXPECT_EQ(0, strtoimax("0", NULL, 0)); +} + +TEST(strtoimax, testDecimal) { + EXPECT_EQ(-123, strtoimax("-123", NULL, 0)); +} + +TEST(strtoimax, testHex) { + EXPECT_EQ(-255, strtoimax("-0xff", NULL, 0)); +} + +TEST(strtoimax, testOctal) { + EXPECT_EQ(-123, strtoimax("-0173", NULL, 0)); +} TEST(strtoimax, testLimits) { EXPECT_EQ( @@ -35,12 +46,6 @@ TEST(strtoimax, testLimits) { strtoimax("0x7fffffffffffffffffffffffffffffff", NULL, 0)); } -TEST(strtoimax, testZeroExtend) { - EXPECT_EQ(-1, strtoimax("-1", NULL, 0)); - EXPECT_EQ(0xffffffff, strtoimax("-1u", NULL, 0)); - EXPECT_EQ(0xffffffffffffffff, strtoimax("-1ul", NULL, 0)); -} - TEST(strtoimax, testTwosBane) { EXPECT_EQ(((uintmax_t)0x8000000000000000) << 64 | 0x0000000000000000, strtoimax("0x80000000000000000000000000000000", NULL, 0)); diff --git a/test/libc/fmt/test.mk b/test/libc/fmt/test.mk index d917a7b8..b72b6aa0 100644 --- a/test/libc/fmt/test.mk +++ b/test/libc/fmt/test.mk @@ -34,7 +34,8 @@ TEST_LIBC_FMT_DIRECTDEPS = \ LIBC_SYSV \ LIBC_TESTLIB \ LIBC_UNICODE \ - LIBC_X + LIBC_X \ + THIRD_PARTY_GDTOA TEST_LIBC_FMT_DEPS := \ $(call uniq,$(foreach x,$(TEST_LIBC_FMT_DIRECTDEPS),$($(x)))) diff --git a/test/libc/math/round_test.c b/test/libc/math/round_test.c index 740902c0..5fa65779 100644 --- a/test/libc/math/round_test.c +++ b/test/libc/math/round_test.c @@ -33,10 +33,10 @@ TEST(round, test) { TEST(round, testCornerCases) { EXPECT_STREQ("-0", gc(xdtoa(round(-0.0)))); - EXPECT_STREQ("nan", gc(xdtoa(round(NAN)))); - EXPECT_STREQ("-nan", gc(xdtoa(round(-NAN)))); - EXPECT_STREQ("inf", gc(xdtoa(round(INFINITY)))); - EXPECT_STREQ("-inf", gc(xdtoa(round(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(round(NAN)))); + EXPECT_STREQ("-NAN", gc(xdtoa(round(-NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(round(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(round(-INFINITY)))); } TEST(lround, test) { @@ -60,10 +60,10 @@ TEST(roundf, test) { TEST(roundf, testCornerCases) { EXPECT_STREQ("-0", gc(xdtoa(roundf(-0.0)))); - EXPECT_STREQ("nan", gc(xdtoa(roundf(NAN)))); - EXPECT_STREQ("-nan", gc(xdtoa(roundf(-NAN)))); - EXPECT_STREQ("inf", gc(xdtoa(roundf(INFINITY)))); - EXPECT_STREQ("-inf", gc(xdtoa(roundf(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(roundf(NAN)))); + EXPECT_STREQ("-NAN", gc(xdtoa(roundf(-NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(roundf(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(roundf(-INFINITY)))); } TEST(lroundf, test) { diff --git a/test/libc/release/test.mk b/test/libc/release/test.mk index 11f50589..5871e55b 100644 --- a/test/libc/release/test.mk +++ b/test/libc/release/test.mk @@ -20,10 +20,11 @@ o/$(MODE)/test/libc/release/smoke.com: \ -o $@ \ -Os \ -static \ - -fno-pie \ -no-pie \ + -fno-pie \ -nostdlib \ -nostdinc \ + -Wl,--gc-sections \ -Wl,--oformat=binary \ -Wl,-z,max-page-size=0x1000 \ -Wl,-T,o/$(MODE)/ape/ape.lds \ diff --git a/test/libc/alg/strstr_test.c b/test/libc/str/strstr_test.c similarity index 100% rename from test/libc/alg/strstr_test.c rename to test/libc/str/strstr_test.c diff --git a/test/libc/str/test.mk b/test/libc/str/test.mk index 1f6a1985..c09588ed 100644 --- a/test/libc/str/test.mk +++ b/test/libc/str/test.mk @@ -25,6 +25,7 @@ TEST_LIBC_STR_CHECKS = \ TEST_LIBC_STR_DIRECTDEPS = \ LIBC_CALLS_HEFTY \ + LIBC_ALG \ LIBC_FMT \ LIBC_NEXGEN32E \ LIBC_STDIO \ diff --git a/test/libc/tinymath/powl_test.c b/test/libc/tinymath/powl_test.c index 3210a133..d2280b1a 100644 --- a/test/libc/tinymath/powl_test.c +++ b/test/libc/tinymath/powl_test.c @@ -23,7 +23,6 @@ #include "libc/testlib/testlib.h" #include "libc/tinymath/tinymath.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" TEST(powl, testLongDouble) { /* .4248496805467504836322459796959084815827285786480897 */ diff --git a/test/libc/tinymath/round_test.c b/test/libc/tinymath/round_test.c index bbb03a69..cdf0f98e 100644 --- a/test/libc/tinymath/round_test.c +++ b/test/libc/tinymath/round_test.c @@ -34,18 +34,18 @@ FIXTURE(intrin, disableHardwareExtensions) { TEST(round, testCornerCases) { EXPECT_STREQ("-0", gc(xdtoa(tinymath_round(-0.0)))); - EXPECT_STREQ("nan", gc(xdtoa(tinymath_round(NAN)))); - EXPECT_STREQ("-nan", gc(xdtoa(tinymath_round(-NAN)))); - EXPECT_STREQ("inf", gc(xdtoa(tinymath_round(INFINITY)))); - EXPECT_STREQ("-inf", gc(xdtoa(tinymath_round(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(tinymath_round(NAN)))); + EXPECT_STREQ("-NAN", gc(xdtoa(tinymath_round(-NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(tinymath_round(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(tinymath_round(-INFINITY)))); } TEST(roundl, testCornerCases) { EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundl(-0.0)))); - EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundl(NAN)))); - EXPECT_STREQ("-nan", gc(xdtoa(tinymath_roundl(-NAN)))); - EXPECT_STREQ("inf", gc(xdtoa(tinymath_roundl(INFINITY)))); - EXPECT_STREQ("-inf", gc(xdtoa(tinymath_roundl(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(tinymath_roundl(NAN)))); + EXPECT_STREQ("-NAN", gc(xdtoa(tinymath_roundl(-NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(tinymath_roundl(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(tinymath_roundl(-INFINITY)))); } TEST(round, test) { @@ -149,10 +149,10 @@ TEST(rintl, test) { TEST(roundf, testCornerCases) { EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundf(-0.0)))); - EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundf(NAN)))); - EXPECT_STREQ("-nan", gc(xdtoa(tinymath_roundf(-NAN)))); - EXPECT_STREQ("inf", gc(xdtoa(tinymath_roundf(INFINITY)))); - EXPECT_STREQ("-inf", gc(xdtoa(tinymath_roundf(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(tinymath_roundf(NAN)))); + EXPECT_STREQ("-NAN", gc(xdtoa(tinymath_roundf(-NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(tinymath_roundf(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(tinymath_roundf(-INFINITY)))); } TEST(lroundf, test) { diff --git a/test/libc/tinymath/sinl_test.c b/test/libc/tinymath/sinl_test.c index 74cf6c45..dae00826 100644 --- a/test/libc/tinymath/sinl_test.c +++ b/test/libc/tinymath/sinl_test.c @@ -18,25 +18,26 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/math.h" +#include "libc/runtime/gc.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" -#include "third_party/dtoa/dtoa.h" +#include "libc/x/x.h" char buf[32]; TEST(sinl, testLongDouble) { - EXPECT_STREQ(".479425538604203", g_fmt(buf, sinl(0.5))); - EXPECT_STREQ("-.479425538604203", g_fmt(buf, sinl(-0.5))); + EXPECT_STREQ(".479425538604203", gc(xdtoa(sinl(.5)))); + EXPECT_STREQ("-.479425538604203", gc(xdtoa(sinl(-.5)))); } TEST(sinl, testDouble) { - EXPECT_STREQ(".479425538604203", g_fmt(buf, sin(0.5))); - EXPECT_STREQ("-.479425538604203", g_fmt(buf, sin(-0.5))); + EXPECT_STREQ(".479425538604203", gc(xdtoa(sin(.5)))); + EXPECT_STREQ("-.479425538604203", gc(xdtoa(sin(-.5)))); } TEST(sinl, testFloat) { - EXPECT_STARTSWITH(".4794255", g_fmt(buf, sinf(0.5f))); - EXPECT_STARTSWITH("-.4794255", g_fmt(buf, sinf(-0.5f))); + EXPECT_STARTSWITH(".4794255", gc(xdtoa(sinf(.5f)))); + EXPECT_STARTSWITH("-.4794255", gc(xdtoa(sinf(-.5f)))); } BENCH(sinl, bench) { diff --git a/test/libc/tinymath/test.mk b/test/libc/tinymath/test.mk index 787c6516..67efa43c 100644 --- a/test/libc/tinymath/test.mk +++ b/test/libc/tinymath/test.mk @@ -32,8 +32,7 @@ TEST_LIBC_TINYMATH_DIRECTDEPS = \ LIBC_NEXGEN32E \ LIBC_STUBS \ LIBC_TESTLIB \ - LIBC_X \ - THIRD_PARTY_DTOA + LIBC_X TEST_LIBC_TINYMATH_DEPS := \ $(call uniq,$(foreach x,$(TEST_LIBC_TINYMATH_DIRECTDEPS),$($(x)))) diff --git a/test/libc/x/test.mk b/test/libc/x/test.mk index caf36385..d6dda24d 100644 --- a/test/libc/x/test.mk +++ b/test/libc/x/test.mk @@ -34,7 +34,7 @@ TEST_LIBC_X_DIRECTDEPS = \ LIBC_X \ LIBC_STUBS \ LIBC_TESTLIB \ - THIRD_PARTY_DTOA + THIRD_PARTY_GDTOA TEST_LIBC_X_DEPS := \ $(call uniq,$(foreach x,$(TEST_LIBC_X_DIRECTDEPS),$($(x)))) diff --git a/test/tool/build/lib/pty_test.c b/test/tool/build/lib/pty_test.c index 080f26e6..f5fd5ee3 100644 --- a/test/tool/build/lib/pty_test.c +++ b/test/tool/build/lib/pty_test.c @@ -37,7 +37,7 @@ char *render(struct Pty *pty) { return b.p; } -const char widelatin[] aligned(16) = "\ +const char widelatin[] forcealign(16) = "\ A-BCDEFGHIJKLMNOPQRSTUVWXYZ\r\n\ ab-cdefghijklmnopqrstuvwxyz\r\n\ 012-3456789\r\n\ @@ -82,7 +82,7 @@ TEST(pty, testFunWidth) { FreePty(pty); } -const char hyperion[] aligned(16) = "\ +const char hyperion[] forcealign(16) = "\ Fanatics have their dreams, wherewith they weave \ A paradise for a sect; the savage too \ From forth the loftiest fashion of his sleep \ diff --git a/third_party/chibicc/LICENSE b/third_party/chibicc/NOTICE similarity index 95% rename from third_party/chibicc/LICENSE rename to third_party/chibicc/NOTICE index 2d1fd940..5516c8c6 100644 --- a/third_party/chibicc/LICENSE +++ b/third_party/chibicc/NOTICE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2019 Rui Ueyama +Copyright (c) 2020 Justine Alexandra Roberts Tunney Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/third_party/chibicc/README.cosmo b/third_party/chibicc/README.cosmo new file mode 100644 index 00000000..c0498641 --- /dev/null +++ b/third_party/chibicc/README.cosmo @@ -0,0 +1,30 @@ +chibicc is the simplest/tiniest/hackable/readable c11 compiler in the +world that can build projects like python but goes 2x slower than gcc +with 2x the code size, because it doesn't optimize or color registers +although it can compile code at 5x the speed and could be even faster +which is great, considering it's a 220kb αcτµαlly pδrταblε εxεcµταblε + +local enhancements + +- support __asm__ +- support __int128 +- support __vector_size__ +- support __builtin_memcpy +- support __builtin_constant_p, __builtin_likely, etc. +- support __builtin_isunordered, __builtin_islessgreater, etc. +- support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc. +- support __constructor__, __destructor__, __section__, __cold__, etc. +- improve error messages to trace macro expansions +- reduce #lines of generated assembly by a third +- reduce #bytes of generated binary by a third + +local bug fixes + +- fix 64-bit bug in generated code for struct bitfields + +local changes + +- use tabs in generated output +- generated code no longer assumes red zone +- emit .size directives for function definitions +- use fisttp long double conversions if built w/ -msse3 diff --git a/third_party/chibicc/README.md b/third_party/chibicc/README.md new file mode 100644 index 00000000..e700a19a --- /dev/null +++ b/third_party/chibicc/README.md @@ -0,0 +1,134 @@ +# chibicc: A Small C Compiler + +(The old master has moved to +[historical/old](https://github.com/rui314/chibicc/tree/historical/old) +branch. This is a new one uploaded in September 2020.) + +chibicc is yet another small C compiler that implements most C11 +features. Even though it still probably falls into the "toy compilers" +category just like other small compilers do, chibicc can compile several +real-world programs, including [Git](https://git-scm.com/), +[SQLite](https://sqlite.org) and +[libpng](http://www.libpng.org/pub/png/libpng.html), without making +modifications to the compiled programs. Generated executables of these +programs pass their corresponding test suites. So, chibicc actually +supports a wide variety of C11 features and is able to compile hundreds of +thousands of lines of real-world C code correctly. + +chibicc is developed as the reference implementation for a book I'm +currently writing about the C compiler and the low-level programming. +The book covers the vast topic with an incremental approach; in the first +chapter, readers will implement a "compiler" that accepts just a single +number as a "language", which will then gain one feature at a time in each +section of the book until the language that the compiler accepts matches +what the C11 spec specifies. I took this incremental approach from [the +paper](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) by Abdulaziz +Ghuloum. + +Each commit of this project corresponds to a section of the book. For this +purpose, not only the final state of the project but each commit was +carefully written with readability in mind. Readers should be able to learn +how a C language feature can be implemented just by reading one or a few +commits of this project. For example, this is how +[while](https://github.com/rui314/chibicc/commit/773115ab2a9c4b96f804311b95b20e9771f0190a), +[[]](https://github.com/rui314/chibicc/commit/75fbd3dd6efde12eac8225d8b5723093836170a5), +[?:](https://github.com/rui314/chibicc/commit/1d0e942fd567a35d296d0f10b7693e98b3dd037c), +and [thread-local +variable](https://github.com/rui314/chibicc/commit/79644e54cc1805e54428cde68b20d6d493b76d34) +are implemented. If you have plenty of spare time, it might be fun to read +it from the [first +commit](https://github.com/rui314/chibicc/commit/0522e2d77e3ab82d3b80a5be8dbbdc8d4180561c). + +If you like this project, please consider purchasing a copy of the book +when it becomes available! 😀 I publish the source code here to give people +early access to it, because I was planing to do that anyway with a +permissive open-source license after publishing the book. If I don't charge +for the source code, it doesn't make much sense to me to keep it private. I +hope to publish the book in 2021. + +I pronounce chibicc as _chee bee cee cee_. "chibi" means "mini" or +"small" in Japanese. "cc" stands for C compiler. + +## Status + +Features that are often missing in a small compiler but supported by +chibicc include (but not limited to): + +- Preprocessor +- long double (x87 80-bit floting point numbers) +- Bit-field +- alloca() +- Variable-length array +- Thread-local variable +- Atomic variable +- Common symbol +- Designated initializer +- L, u, U and u8 string literals + +chibicc does not support digraphs, trigraphs, complex numbers, K&R-style +function prototype, and inline assembly. + +chibicc outputs a simple but nice error message when it finds an error in +source code. + +There's no optimization pass. chibicc emits terrible code which is probably +twice or more slower than GCC's output. I have a plan to add an +optimization pass once the frontend is done. + +## Internals + +chibicc consists of the following stages: + +- Tokenize: A tokenizer takes a string as an input, breaks it into a list + of tokens and returns them. + +- Preprocess: A preprocessor takes as an input a list of tokens and output + a new list of macro-expanded tokens. It interprets preprocessor + directives while expanding macros. + +- Parse: A recursive descendent parser constructs abstract syntax trees + from the output of the preprocessor. It also adds a type to each AST + node. + +- Codegen: A code generator emits an assembly text for given AST nodes. + +## Contributing + +When I find a bug in this compiler, I go back to the original commit that +introduced the bug and rewrite the commit history as if there were no such +bug from the beginning. This is an unusual way of fixing bugs, but as a a +part of a book, it is important to keep every commit bug-free. + +Thus, I do not take pull requests in this repo. You can send me a pull +request if you find a bug, but it is very likely that I will read your +patch and then apply that to my previous commits by rewriting history. I'll +credit your name somewhere, but your changes will be rewritten by me before +submitted to this repository. + +Also, please assume that I will occasionally force-push my local repository +to this public one to rewrite history. If you clone this project and make +local commits on top of it, your changes will have to be rebased by hand +when I force-push new commits. + +## About the Author + +I'm Rui Ueyama. I'm the creator of [8cc](https://github.com/rui314/8cc), +which is a hobby C compiler, and also the original creator of the current +version of [LLVM lld](https://lld.llvm.org) linker, which is a +production-quality linker used by various operating systems and large-scale +build systems. + +## References + +- [tcc](https://bellard.org/tcc/): A small C compiler written by Fabrice + Bellard. I learned a lot from this compiler, but the design of tcc and + chibicc are different. In particular, tcc is a one-pass compiler, while + chibicc is a multi-pass one. + +- [lcc](https://github.com/drh/lcc): Another small C compiler. The creators + wrote a [book](https://sites.google.com/site/lccretargetablecompiler/) + about the internals of lcc, which I found a good resource to see how a + compiler is implemented. + +- [An Incremental Approach to Compiler + Construction](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) diff --git a/third_party/chibicc/asm.c b/third_party/chibicc/asm.c new file mode 100644 index 00000000..a461276c --- /dev/null +++ b/third_party/chibicc/asm.c @@ -0,0 +1,751 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or 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. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/chibicc/chibicc.h" + +#define PRECIOUS 0b1111000000101000 // bx,bp,r12-r15 + +static const char kGreg[4][16][5] = { + {"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", + "r11b", "r12b", "r13b", "r14b", "r15b"}, + {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", + "r11w", "r12w", "r13w", "r14w", "r15w"}, + {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", + "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"}, + {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15"}, +}; + +StaticAsm *staticasms; + +static void DecodeAsmConstraints(AsmOperand *op) { + int i; + char c; + for (i = 0;;) { + switch ((c = op->str[i++])) { + case '\0': + case ',': // alternative group + return; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': // reference + case '=': // output + case '+': // output and input + op->flow = c; + break; + case 'm': // memory + case 'o': // memory offsetable + op->type |= kAsmMem; + op->regmask |= 0b1111111111111111; + break; + case 'i': // int literal, c/asm constexpr, ld embedding + case 'n': // integer literal or compiler constexpr? + case 's': // integer constexpr but not literal (or known at link time?) + case 'M': // i∊[0,3] for index scaling, e.g. "mov\t(?,?,1<<%0),?" + case 'I': // i∊[0,31] 5 bits for 32-bit shifts + case 'J': // i∊[0,63] 6 bits for 64-bit shifts + case 'N': // i∊[0,255] in/out immediate byte + case 'K': // i∊[-128,127] signed byte integer + case 'Z': // i∊[0,2³²) for zero-extending + case 'L': // i∊{0xFF,0xFFFF,0xFFFFFFFF} + op->type |= kAsmImm; + break; + case 'a': // ax + op->regmask |= 0b0000000000000001; + op->type |= kAsmReg; + break; + case 'c': // cx + op->regmask |= 0b0000000000000010; + op->type |= kAsmReg; + break; + case 'd': // dx + op->regmask |= 0b0000000000000100; + op->type |= kAsmReg; + break; + case 'b': // bx + op->regmask |= 0b0000000000001000; + op->type |= kAsmReg; + break; + case 'S': // si + op->regmask |= 0b0000000001000000; + op->type |= kAsmReg; + break; + case 'D': // di + op->regmask |= 0b0000000010000000; + op->type |= kAsmReg; + break; + case 'r': // general register + op->regmask |= 0b1111111111111111; + op->type |= kAsmReg; + break; + case 'q': // greg lo-byte accessible + op->regmask |= 0b1111111111111111; + op->type |= kAsmReg; + break; + case 'Q': // greg hi-byte accessible + op->regmask |= 0b0000000000001111; + op->type |= kAsmReg; + break; + case 'U': // greg call-clobbered + op->regmask |= 0b0000111111000111; + op->type |= kAsmReg; + break; + case 'R': // greg all models + op->regmask |= 0b0000000011111111; + op->type |= kAsmReg; + break; + case 'l': // index register + op->regmask |= 0b1111111111101111; + op->type |= kAsmReg; + break; + case 'y': // mmx + op->type |= kAsmMmx; + op->regmask |= 0b0000000011111111; + break; + case 'x': // xmm + op->type |= kAsmXmm; + op->regmask |= 0b1111111111111111; + break; + case 'g': // rmi + op->type |= kAsmImm | kAsmMem | kAsmReg; + op->regmask |= 0b1111111111111111; + break; + case 'X': // anything + op->type |= kAsmImm | kAsmMem | kAsmReg | kAsmXmm | kAsmFpu | kAsmRaw; + op->regmask |= 0b1111111111111111; + op->x87mask |= 0b11111111; + break; + case 't': // %st + op->type |= kAsmFpu; + op->x87mask |= 0b00000001; + break; + case 'u': // %st(1) + op->type |= kAsmFpu; + op->x87mask |= 0b00000010; + break; + case 'f': // %st(0..7) + op->type |= kAsmFpu; + op->x87mask |= 0b11111111; + break; + case 'A': // ax+dx + error_tok(op->tok, "ax dx constraint not implemented"); + case '@': // flags + if (op->flow != '=' || strlen(op->str + i) < 3 || + (op->str[i] != 'c' || op->str[i + 1] != 'c')) { + error_tok(op->tok, "invalid flag constraint"); + } + if (!is_integer(op->node->ty) || op->node->ty->size != 1) { + error_tok(op->node->tok, "invalid output flag type"); + } + op->type = kAsmFlag; + op->predicate = i + 2; + return; + default: + break; + } + } +} + +static bool IsLvalue(AsmOperand *op) { + switch (op->node->kind) { + case ND_VAR: + case ND_DEREF: + case ND_MEMBER: + case ND_VLA_PTR: + return true; + default: + return false; + } +} + +static bool CanUseReg(Node *n) { + return is_integer(n->ty) || n->ty->kind == TY_PTR; +} + +static bool CanUseXmm(Node *n) { + return n->ty->kind == TY_FLOAT || n->ty->kind == TY_DOUBLE || + n->ty->kind == TY_PTR || + (n->ty->kind == TY_ARRAY && n->ty->size == 16); +} + +static bool CanUseMmx(Node *n) { + return n->ty->kind == TY_FLOAT || n->ty->kind == TY_DOUBLE || + n->ty->kind == TY_PTR || (n->ty->kind == TY_ARRAY && n->ty->size == 8); +} + +static int PickAsmReferenceType(AsmOperand *op, AsmOperand *ref) { + switch (ref->type) { + case kAsmImm: + case kAsmMem: + error_tok(op->tok, "bad reference"); + case kAsmReg: + if (!CanUseReg(op->node)) { + error_tok(op->tok, "expected integral expression"); + } + op->regmask = 0; + return ref->type; + case kAsmXmm: + if (!CanUseXmm(op->node)) { + error_tok(op->tok, "expected xmm expression"); + } + return ref->type; + case kAsmFpu: + if (op->node->ty->kind != TY_LDOUBLE) { + error_tok(op->tok, "expected long double expression"); + } + op->x87mask = 0; + return ref->type; + default: + UNREACHABLE(); + } +} + +static int PickAsmOperandType(Asm *a, AsmOperand *op) { + if (op->flow == '=' || op->flow == '+') { + op->type &= ~kAsmImm; + if (!IsLvalue(op)) error_tok(op->tok, "lvalue required"); + } + if ((op->type & kAsmImm) && is_const_expr(op->node)) { + op->val = eval2(op->node, &op->label); + return kAsmImm; + } + if ((op->type & kAsmMem) && op->node->ty->kind != TY_VOID) return kAsmMem; + if ((op->type & kAsmFpu) && op->node->ty->kind == TY_LDOUBLE) return kAsmFpu; + if ((op->type & kAsmXmm) && CanUseXmm(op->node)) return kAsmXmm; + if ((op->type & kAsmMmx) && CanUseMmx(op->node)) return kAsmMmx; + if ((op->type & kAsmReg) && CanUseReg(op->node)) return kAsmReg; + if (op->type & kAsmFlag) return kAsmFlag; + if (op->type & kAsmRaw) return kAsmRaw; + error_tok(op->tok, "constraint mismatch"); +} + +static Token *ParseAsmOperand(Asm *a, AsmOperand *op, Token *tok) { + int i; + op->tok = tok; + op->str = ConsumeStringLiteral(&tok, tok); + tok = skip(tok, "("); + op->node = expr(&tok, tok); + add_type(op->node); + DecodeAsmConstraints(op); + if (isdigit(op->flow)) { + if ((i = op->flow - '0') >= a->n) error_tok(op->tok, "bad reference"); + op->type = PickAsmReferenceType(op, a->ops + i); + } else { + op->type = PickAsmOperandType(a, op); + } + return skip(tok, ")"); +} + +static Token *ParseAsmOperands(Asm *a, Token *tok) { + if (EQUAL(tok, ":")) return tok; + for (;;) { + if (a->n == ARRAYLEN(a->ops)) { + error_tok(tok, "too many asm operands"); + } + tok = ParseAsmOperand(a, &a->ops[a->n], tok); + ++a->n; + if (!EQUAL(tok, ",")) break; + tok = skip(tok, ","); + } + return tok; +} + +static void CouldNotAllocateRegister(AsmOperand *op) { + error_tok(op->tok, "could not allocate register"); +} + +static void PickAsmRegisters(Asm *a) { + int i, j, m, regset, xmmset, x87sts; + regset = 0b0000111111000111; // exclude bx,sp,bp,r12-r15 + xmmset = 0b1111111111111111; + x87sts = 0b0000000011111111; + regset ^= regset & a->regclob; // don't allocate from clobber list + xmmset ^= xmmset & a->xmmclob; + x87sts ^= x87sts & a->x87clob; + for (j = 1; j <= 16; ++j) { // iterate from most to least restrictive + for (i = 0; i < a->n; ++i) { + switch (a->ops[i].type) { + case kAsmMem: + case kAsmReg: + if (!(m = a->ops[i].regmask)) break; + if (popcnt(m) != j) break; + if (!(m &= regset)) CouldNotAllocateRegister(&a->ops[i]); + regset &= ~(1 << (a->ops[i].reg = bsf(m))); + a->ops[i].regmask = 0; + break; + case kAsmXmm: + if (!(m = a->ops[i].regmask)) break; + if (!(m &= xmmset)) CouldNotAllocateRegister(&a->ops[i]); + xmmset &= ~(1 << (a->ops[i].reg = bsf(m))); + a->ops[i].regmask = 0; + break; + case kAsmFpu: + if (!(m = a->ops[i].x87mask)) break; + if (popcnt(m) != j) break; + if (!(m &= x87sts)) CouldNotAllocateRegister(&a->ops[i]); + x87sts &= ~(1 << (a->ops[i].reg = bsf(m))); + a->ops[i].x87mask = 0; + break; + default: + a->ops[i].regmask = 0; + a->ops[i].x87mask = 0; + break; + } + } + } + for (i = 0; i < a->n; ++i) { + assert(!a->ops[i].regmask); + assert(!a->ops[i].x87mask); + } +} + +static void MarkUsedAsmOperands(Asm *a) { + char c, *p; + if (!a->isgnu) return; + for (p = a->str; (c = *p++);) { + if (c == '%') { + if (!(c = *p++)) error_tok(a->tok, "unexpected nul"); + if (c == '%') continue; + if (!isdigit(c)) { + if (!(c = *p++)) error_tok(a->tok, "unexpected nul"); + if (!isdigit(c)) { + error_tok(a->tok, "bad asm specifier"); + } + } + a->ops[c - '0'].isused = true; + } + } +} + +static int GetIndexOfRegisterName(const char *s) { + int i, j; + for (i = 0; i < 16; ++i) { + for (j = 0; j < 4; ++j) { + if (!strcmp(s, kGreg[j][i])) { + return i; + } + } + } + return -1; +} + +static Token *ParseAsmClobbers(Asm *a, Token *tok) { + int i; + char *s; + Token *stok; + for (;;) { + stok = tok; + s = ConsumeStringLiteral(&tok, tok); + if (*s == '%') ++s; + if (!strcmp(s, "cc")) { + a->flagclob = true; + } else if ((i = GetIndexOfRegisterName(s)) != -1) { + a->regclob |= 1 << i; + } else if (startswith(s, "xmm") && isdigit(s[3]) && + (!s[4] || isdigit(s[4]))) { + i = s[3] - '0'; + if (s[4]) { + i *= 10; + i += s[4] - '0'; + } + i &= 15; + a->xmmclob |= 1 << i; + } else if (!strcmp(s, "st")) { + a->x87clob |= 1; + } else if (startswith(s, "st(") && isdigit(s[3]) && s[4] == ')') { + i = s[3] - '0'; + i &= 7; + a->x87clob |= 1 << i; + } else { + error_tok(stok, "unknown clobber register"); + } + if (!EQUAL(tok, ",")) break; + tok = skip(tok, ","); + } + return tok; +} + +// parses ansi c11 asm statement officially defined as follows +// +// asm-stmt = "asm" ("volatile" | "inline")* "(" string-literal ")" +// +// gnu c defines a notation for inputs, outputs, and clobbers, e.g. +// +// asm("foo %1,%0" +// : "=r"(x) +// : "r"(x) +// : "cc"); +// +Asm *asm_stmt(Token **rest, Token *tok) { + Asm *a = calloc(1, sizeof(Asm)); + tok = tok->next; + while (EQUAL(tok, "volatile") || EQUAL(tok, "inline")) tok = tok->next; + tok = skip(tok, "("); + a->tok = tok; + a->str = ConsumeStringLiteral(&tok, tok); + if (!EQUAL(tok, ")")) { + a->isgnu = true; + tok = skip(tok, ":"); + tok = ParseAsmOperands(a, tok); + if (!EQUAL(tok, ")")) { + tok = skip(tok, ":"); + tok = ParseAsmOperands(a, tok); + if (!EQUAL(tok, ")")) { + tok = skip(tok, ":"); + tok = ParseAsmClobbers(a, tok); + } + } + } + PickAsmRegisters(a); + MarkUsedAsmOperands(a); + *rest = skip(tok, ")"); + return a; +} + +static void PrintAsmConstant(AsmOperand *op) { + if (op->label) { + fprintf(output_stream, "%s%+ld", *op->label, op->val); + } else { + fprintf(output_stream, "%ld", op->val); + } +} + +static void EmitAsmSpecifier(AsmOperand *op, int q, int z) { + if (!q) { + switch (op->type) { + case kAsmImm: + fputc('$', output_stream); + PrintAsmConstant(op); + break; + case kAsmMem: + fprintf(output_stream, "(%%%s)", kGreg[3][op->reg]); + break; + case kAsmReg: + fprintf(output_stream, "%%%s", kGreg[z][op->reg]); + break; + case kAsmXmm: + fprintf(output_stream, "%%xmm%d", op->reg); + break; + case kAsmFpu: + fprintf(output_stream, "%%st(%d)", op->reg); + break; + case kAsmRaw: + fprintf(output_stream, "%.*s", op->node->tok->len, op->node->tok->loc); + break; + default: + UNREACHABLE(); + } + } else { + switch (q) { + case 'h': // hi byte + fprintf(output_stream, "%%%ch", "acdb"[op->reg]); + break; + case 'b': // lo byte + fprintf(output_stream, "%%%s", kGreg[0][op->reg]); + break; + case 'w': // word + fprintf(output_stream, "%%%s", kGreg[1][op->reg]); + break; + case 'k': // dword + fprintf(output_stream, "%%%s", kGreg[2][op->reg]); + break; + case 'q': // qword + fprintf(output_stream, "%%%s", kGreg[3][op->reg]); + break; + case 'z': // print suffix + fprintf(output_stream, "%c", "bwlq"[z]); + break; + case 'p': // print raw + fprintf(output_stream, "%.*s", op->node->tok->len, op->node->tok->loc); + break; + case 'a': // print address + PrintAsmConstant(op); + break; + case 'c': // print constant w/o punctuation + PrintAsmConstant(op); + break; + case 'P': // print w/ @plt + PrintAsmConstant(op); + fprintf(output_stream, "@plt"); + break; + case 'l': // print label w/o punctuation + if (!op->label) { + error_tok(op->tok, "qualifier expected label"); + } + fprintf(output_stream, "%s", *op->label); + break; + case 'V': // print register w/o punctuation + if (op->type != kAsmReg) { + error_tok(op->tok, "qualifier expected register"); + } + fprintf(output_stream, "%s", kGreg[z][op->reg]); + break; + default: + error_tok(op->tok, "bad asm qualifier %%%`'c", q); + } + } +} + +static char *HandleAsmSpecifier(Asm *a, char *p) { + int c, i, q, z; + if (!(c = *p++)) error_tok(a->tok, "unexpected nul"); + if (c == '%') { + fputc('%', output_stream); + return p; + } + if (c == '=') { + fprintf(output_stream, "%d", count()); + return p; + } + if (isdigit(c)) { + q = '\0'; + } else { + q = c; + if (!(c = *p++)) error_tok(a->tok, "unexpected nul"); + if (!isdigit(c)) { + error_tok(a->tok, "bad asm specifier at offset %d", p - a->str); + } + } + if ((i = c - '0') >= a->n) { + error_tok(a->tok, "bad asm reference at offset %d", p - a->str); + } + z = bsr(a->ops[i].node->ty->size); + if (z > 3 && a->ops[i].type == kAsmReg) { + error_tok(a->tok, "bad asm op size"); + } + EmitAsmSpecifier(&a->ops[i], q, z); + return p; +} + +static void EmitAsmText(Asm *a) { + char c, *p; + if (a->isgnu) { + flushln(); + fprintf(output_stream, "\t"); + for (p = a->str;;) { + switch ((c = *p++)) { + case '\0': + fputc('\n', output_stream); + return; + case '%': + p = HandleAsmSpecifier(a, p); + break; + default: + fputc(c, output_stream); + break; + } + } + } else { + println("\t%s", a->str); + } +} + +static void PushAsmInput(AsmOperand *op) { + gen_expr(op->node); + push(); +} + +static void PushAsmInputs(Asm *a) { + int i; + for (i = 0; i < a->n; ++i) { + if (a->ops[i].flow == '=') continue; + switch (a->ops[i].type) { + case kAsmReg: + PushAsmInput(&a->ops[i]); + break; + case kAsmMem: + if (a->ops[i].isused) { + PushAsmInput(&a->ops[i]); + } + break; + case kAsmXmm: + gen_expr(a->ops[i].node); + println("\tsub\t$16,%%rsp"); + switch (a->ops[i].node->ty->kind) { + case TY_FLOAT: + case TY_DOUBLE: + println("\tmovdqu\t%%xmm0,(%%rsp)"); + break; + default: + println("\tmovdqu\t(%%rax),%%xmm0"); + println("\tmovdqu\t%%xmm0,(%%rsp)"); + break; + } + break; + case kAsmMmx: + gen_expr(a->ops[i].node); + println("\tsub\t$8,%%rsp"); + switch (a->ops[i].node->ty->kind) { + case TY_FLOAT: + case TY_DOUBLE: + println("\tmovq\t%%mm0,(%%rsp)"); + break; + default: + println("\tmovq\t(%%rax),%%mm0"); + println("\tmovq\t%%mm0,(%%rsp)"); + break; + } + break; + case kAsmFpu: /* TODO: How does this work in non-simple case? */ + gen_expr(a->ops[i].node); + println("\tsub\t$16,%%rsp"); + println("\tfstpt\t(%%rsp)"); + break; + default: + break; + } + } +} + +static void PopAsmInput(Asm *a, AsmOperand *op) { + if (isdigit(op->flow)) { + popreg(kGreg[3][a->ops[op->flow - '0'].reg]); + } else { + popreg(kGreg[3][op->reg]); + } +} + +static void PopAsmInputs(Asm *a) { + int i; + for (i = a->n; i--;) { + if (a->ops[i].flow == '=') continue; + switch (a->ops[i].type) { + case kAsmReg: + PopAsmInput(a, &a->ops[i]); + break; + case kAsmMem: + if (a->ops[i].isused) { + PopAsmInput(a, &a->ops[i]); + } + break; + case kAsmXmm: + println("\tmovdqu\t(%%rsp),%%xmm%d", a->ops[i].reg); + println("\tadd\t$16,%%rsp"); + break; + case kAsmMmx: + println("\tmovq\t(%%rsp),%%mm%d", a->ops[i].reg); + println("\tadd\t$8,%%rsp"); + break; + case kAsmFpu: /* TODO: How does this work in non-simple case? */ + println("\tfldt\t(%%rsp)"); + println("\tadd\t$16,%%rsp"); + break; + default: + break; + } + } +} + +static void StoreAsmOutputs(Asm *a) { + int i, z, x0, x1; + for (i = 0; i < a->n; ++i) { + if (a->ops[i].flow == '=' || a->ops[i].flow == '+') { + switch (a->ops[i].type) { + case kAsmFlag: + gen_addr(a->ops[i].node); + println("\tset%s\t(%%rax)", a->ops[i].str + a->ops[i].predicate); + break; + case kAsmReg: + if (a->ops[i].reg) { + gen_addr(a->ops[i].node); + z = bsr(a->ops[i].node->ty->size); + if (z > 3) error_tok(a->tok, "bad asm out size"); + println("\tmov\t%%%s,(%%rax)", kGreg[z][a->ops[i].reg]); + } else { + println("\tpush\t%%rbx"); + push(); + pop("%rbx"); + gen_addr(a->ops[i].node); + println("\tmov\t%%rbx,(%%rax)"); + println("\tpop\t%%rbx"); + } + break; + case kAsmXmm: + gen_addr(a->ops[i].node); + switch (a->ops[i].node->ty->kind) { + case TY_FLOAT: + println("\tmovss\t%%xmm%d,(%%rax)", a->ops[i].reg); + break; + case TY_DOUBLE: + println("\tmovsd\t%%xmm%d,(%%rax)", a->ops[i].reg); + break; + default: + println("\tmovdqu\t%%xmm%d,(%%rax)", a->ops[i].reg); + break; + } + break; + case kAsmMmx: + gen_addr(a->ops[i].node); + switch (a->ops[i].node->ty->kind) { + case TY_FLOAT: + println("\tmovss\t%%mm%d,(%%rax)", a->ops[i].reg); + break; + case TY_DOUBLE: + println("\tmovsd\t%%mm%d,(%%rax)", a->ops[i].reg); + break; + default: + println("\tmovq\t%%mm%d,(%%rax)", a->ops[i].reg); + break; + } + break; + case kAsmFpu: /* TODO: How does this work in non-simple case? */ + gen_addr(a->ops[i].node); + println("\tfstpt\t(%%rax)"); + break; + default: + break; + } + } + } +} + +static void PushClobbers(Asm *a) { + int i, regs = a->regclob & PRECIOUS; + while (regs) { + i = bsf(regs); + pushreg(kGreg[3][i]); + regs &= ~(1 << i); + } +} + +static void PopClobbers(Asm *a) { + int i, regs = a->regclob & PRECIOUS; + while (regs) { + i = bsr(regs); + popreg(kGreg[3][i]); + regs &= ~(1 << i); + } +} + +// generates shocking horrible code for parsed asm statement +void gen_asm(Asm *a) { + PushAsmInputs(a); + print_loc(a->tok->file->file_no, a->tok->line_no); + PopAsmInputs(a); + PushClobbers(a); + EmitAsmText(a); + StoreAsmOutputs(a); + PopClobbers(a); +} diff --git a/third_party/chibicc/cast.c b/third_party/chibicc/cast.c new file mode 100644 index 00000000..ab2afc48 --- /dev/null +++ b/third_party/chibicc/cast.c @@ -0,0 +1,179 @@ +#include "third_party/chibicc/chibicc.h" + +#define REDZONE(X) \ + "sub\t$16,%rsp\n" \ + "\t" X "\n" \ + "\tadd\t$16,%rsp" + +#define PUSHPOPRAX(X) \ + "push\t%rax\n" \ + "\t" X "\n" \ + "\tpop\t%rax" + +#ifdef __SSE3__ +#define FIST(X) REDZONE("fistt" X) +#else +#define FIST(X) \ + REDZONE("fnstcw\t8(%rsp)\n" \ + "\tmovzwl\t8(%rsp),%eax\n" \ + "\tor\t$12,%ah\n" \ + "\tmov\t%ax,10(%rsp)\n" \ + "\tfldcw\t10(%rsp)\n" \ + "\tfist" X "\n" \ + "\tfldcw\t8(%rsp)") +#endif + +#define u64f64 \ + "test\t%rax,%rax\n" \ + "\tjs\t1f\n" \ + "\tpxor\t%xmm0,%xmm0\n" \ + "\tcvtsi2sd %rax,%xmm0\n" \ + "\tjmp\t2f\n" \ + "1:\n" \ + "\tmov\t%rax,%rdi\n" \ + "\tand\t$1,%eax\n" \ + "\tpxor\t%xmm0,%xmm0\n" \ + "\tshr\t%rdi\n" \ + "\tor\t%rax,%rdi\n" \ + "\tcvtsi2sd %rdi,%xmm0\n" \ + "\taddsd\t%xmm0,%xmm0\n" \ + "2:" + +#define u64f80 \ + PUSHPOPRAX("fildq\t(%rsp)\n" \ + "\ttest\t%rax,%rax\n" \ + "\tjns\t1f\n" \ + "\tmov\t$0x5f800000,(%rsp)\n" \ + "\tfadds\t(%rsp)\n" \ + "1:") + +#define i32i8 "movsbl\t%al,%eax" +#define i32u8 "movzbl\t%al,%eax" +#define i32i16 "cwtl" +#define i32u16 "movzwl\t%ax,%eax" +#define i32f32 "cvtsi2ssl %eax,%xmm0" +#define i32i64 "cltq" +#define i32f64 "cvtsi2sdl %eax,%xmm0" +#define u32i64 "mov\t%eax,%eax" +#define i64f32 "cvtsi2ssq %rax,%xmm0" +#define i64f64 "cvtsi2sdq %rax,%xmm0" +#define f32i32 "cvttss2sil %xmm0,%eax" +#define f32u32 "cvttss2siq %xmm0,%rax" +#define f32i64 "cvttss2siq %xmm0,%rax" +#define f32u64 "cvttss2siq %xmm0,%rax" +#define f32f64 "cvtss2sd %xmm0,%xmm0" +#define f64i32 "cvttsd2sil %xmm0,%eax" +#define f64u32 "cvttsd2siq %xmm0,%rax" +#define f64i64 "cvttsd2siq %xmm0,%rax" +#define f64u64 "cvttsd2siq %xmm0,%rax" +#define f64f32 "cvtsd2ss %xmm0,%xmm0" +#define u64f32 "cvtsi2ssq %rax,%xmm0" +#define f32i8 "cvttss2sil %xmm0,%eax\n\tmovsbl\t%al,%eax" +#define f32u8 "cvttss2sil %xmm0,%eax\n\tmovzbl\t%al,%eax" +#define f32i16 "cvttss2sil %xmm0,%eax\n\tmovswl\t%ax,%eax" +#define f32u16 "cvttss2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax" +#define f64i8 "cvttsd2sil %xmm0,%eax\n\tmovsbl\t%al,%eax" +#define f64u8 "cvttsd2sil %xmm0,%eax\n\tmovzbl\t%al,%eax" +#define f64i16 "cvttsd2sil %xmm0,%eax\n\tmovswl\t%ax,%eax" +#define f64u16 "cvttsd2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax" +#define f64f80 REDZONE("movsd\t%xmm0,(%rsp)\n\tfldl\t(%rsp)") +#define f80i8 FIST("ps\t(%rsp)\n\tmovsbl\t(%rsp),%eax") +#define f80u8 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax") +#define f80i16 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax") +#define f80u16 FIST("pl\t(%rsp)\n\tmovswl\t(%rsp),%eax") +#define f80i32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax") +#define f80u32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax") +#define f80i64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax") +#define f80u64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax") +#define f80f32 REDZONE("fstps\t(%rsp)\n\tmovss\t(%rsp),%xmm0") +#define f80f64 REDZONE("fstpl\t(%rsp)\n\tmovsd\t(%rsp),%xmm0") +#define i32f80 PUSHPOPRAX("fildl\t(%rsp)") +#define u32f32 "mov\t%eax,%eax\n\tcvtsi2ssq %rax,%xmm0" +#define u32f64 "mov\t%eax,%eax\n\tcvtsi2sdq %rax,%xmm0" +#define u32f80 "mov\t%eax,%eax\n\tpush %rax\n\tfildll\t(%rsp)\n\tpop\t%rax" +#define i64f80 PUSHPOPRAX("fildll\t(%rsp)") +#define f32f80 REDZONE("movss\t%xmm0,(%rsp)\n\tflds\t(%rsp)") +#define i8i128 "movsbq\t%al,%rax\n\tcqto" +#define i16i128 "movswq\t%ax,%rax\n\tcqto" +#define i32i128 "cltq\n\tcqto" +#define i64i128 "cqto" +#define u8i128 "movzbq\t%al,%rax\n\txor\t%edx,%edx" +#define u16i128 "movzwq\t%ax,%rax\n\txor\t%edx,%edx" +#define u32i128 "cltq\n\txor\t%edx,%edx" +#define u64i128 "xor\t%edx,%edx" +#define i128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattisf" +#define i128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattidf" +#define i128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattixf" +#define u128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntisf" +#define u128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntidf" +#define u128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntixf" +#define f32i128 "call\t__fixsfti" +#define f64i128 "call\t__fixdfti" +#define f80i128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixxfti") +#define f32u128 "call\t__fixunssfti" +#define f64u128 "call\t__fixunsdfti" +#define f80u128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixunsxfti") + +enum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64, F80, I128, U128 }; +static const char *const cast_table[13][13] = /* clang-format off */ { + // i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 f80 i128 u128 + {NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i8 + {i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i16 + {i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i32 + {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i64f32, i64f64, i64f80, i64i128, i64i128}, // i64 + {i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u8 + {i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u16 + {i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64, u32f32, u32f64, u32f80, u32i128, i32i128}, // u32 + {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u64f32, u64f64, u64f80, u64i128, u64i128}, // u64 + {f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL, f32f64, f32f80, f32i128, f32u128}, // f32 + {f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL, f64f80, f64i128, f64u128}, // f64 + {f80i8, f80i16, f80i32, f80i64, f80u8, f80u16, f80u32, f80u64, f80f32, f80f64, NULL, f80i128, f80u128}, // f80 + {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i128f32, i128f64, i128f80, NULL, NULL }, // i128 + {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u128f32, u128f64, u128f80, NULL, NULL }, // u128 +} /* clang-format on */; + +static int getTypeId(Type *ty) { + switch (ty->kind) { + case TY_CHAR: + return ty->is_unsigned ? U8 : I8; + case TY_SHORT: + return ty->is_unsigned ? U16 : I16; + case TY_INT: + return ty->is_unsigned ? U32 : I32; + case TY_LONG: + return ty->is_unsigned ? U64 : I64; + case TY_INT128: + return ty->is_unsigned ? U128 : I128; + case TY_FLOAT: + return F32; + case TY_DOUBLE: + return F64; + case TY_LDOUBLE: + return F80; + } + return U64; +} + +void gen_cast(Type *from, Type *to) { + bool skew; + if (to->kind == TY_VOID) return; + if (to->kind == TY_BOOL) { + cmp_zero(from); + println("\tsetne\t%%al"); + println("\tmovzbl\t%%al,%%eax"); + return; + } + int t1 = getTypeId(from); + int t2 = getTypeId(to); + if (cast_table[t1][t2]) { + if ((skew = (depth & 1) && strstr(cast_table[t1][t2], "call"))) { + println("\tsub\t$8,%%rsp"); + depth++; + } + println("\t%s", cast_table[t1][t2]); + if (skew) { + println("\tadd\t$8,%%rsp"); + depth--; + } + } +} diff --git a/third_party/chibicc/chibicc.c b/third_party/chibicc/chibicc.c index 8a8e2bc2..f8da0a66 100644 --- a/third_party/chibicc/chibicc.c +++ b/third_party/chibicc/chibicc.c @@ -1,20 +1,30 @@ #include "third_party/chibicc/chibicc.h" +asm(".ident\t\"\\n\\n\ +chibicc (MIT/ISC License)\\n\ +Copyright 2019 Rui Ueyama\\n\ +Copyright 2020 Justine Alexandra Roberts Tunney\""); +asm(".include \"libc/disclaimer.inc\""); + typedef enum { FILE_NONE, FILE_C, FILE_ASM, + FILE_ASM_CPP, FILE_OBJ, FILE_AR, FILE_DSO, } FileType; -StringArray include_paths; bool opt_fcommon = true; bool opt_fpic; +bool opt_verbose; +bool opt_mpopcnt; +bool opt_pg; +bool opt_mfentry; +bool opt_mnop_mcount; +bool opt_mrecord_mcount; -static FileType opt_x; -static StringArray opt_include; static bool opt_E; static bool opt_M; static bool opt_MD; @@ -25,19 +35,20 @@ static bool opt_c; static bool opt_cc1; static bool opt_hash_hash_hash; static bool opt_static; -static bool opt_shared; static char *opt_MF; static char *opt_MT; static char *opt_o; +static FileType opt_x; +static StringArray opt_include; +StringArray include_paths; static StringArray ld_extra_args; +static StringArray as_extra_args; static StringArray std_include_paths; char *base_file; static char *output_file; - static StringArray input_paths; - static char **tmpfiles; static void usage(int status) { @@ -46,48 +57,49 @@ static void usage(int status) { } static bool take_arg(char *arg) { - char *x[] = { - "-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker", - }; - - for (int i = 0; i < sizeof(x) / sizeof(*x); i++) - if (!strcmp(arg, x[i])) return true; + char *x[] = {"-o", "-I", "-idirafter", "-include", + "-x", "-MF", "-MT", "-Xlinker"}; + for (int i = 0; i < sizeof(x) / sizeof(*x); i++) { + if (!strcmp(arg, x[i])) { + return true; + } + } return false; } static void add_default_include_paths(char *argv0) { // We expect that chibicc-specific include files are installed // to ./include relative to argv[0]. - char *buf = calloc(1, strlen(argv0) + 10); - sprintf(buf, "%s/include", dirname(strdup(argv0))); - strarray_push(&include_paths, buf); - + /* char *buf = calloc(1, strlen(argv0) + 10); */ + /* sprintf(buf, "%s/include", dirname(strdup(argv0))); */ + /* strarray_push(&include_paths, buf); */ // Add standard include paths. - strarray_push(&include_paths, "."); - + /* strarray_push(&include_paths, "."); */ // Keep a copy of the standard include paths for -MMD option. - for (int i = 0; i < include_paths.len; i++) + for (int i = 0; i < include_paths.len; i++) { strarray_push(&std_include_paths, include_paths.data[i]); + } } static void define(char *str) { char *eq = strchr(str, '='); - if (eq) + if (eq) { define_macro(strndup(str, eq - str), eq + 1); - else + } else { define_macro(str, "1"); + } } static FileType parse_opt_x(char *s) { if (!strcmp(s, "c")) return FILE_C; if (!strcmp(s, "assembler")) return FILE_ASM; + if (!strcmp(s, "assembler-with-cpp")) return FILE_ASM_CPP; if (!strcmp(s, "none")) return FILE_NONE; error(": unknown argument for -x: %s", s); } static char *quote_makefile(char *s) { char *buf = calloc(1, strlen(s) * 2 + 1); - for (int i = 0, j = 0; s[i]; i++) { switch (s[i]) { case '$': @@ -112,255 +124,254 @@ static char *quote_makefile(char *s) { return buf; } +static void PrintMemoryUsage(void) { + struct mallinfo mi; + mi = mallinfo(); + fprintf(stderr, "allocated %,ld bytes of memory\n", mi.arena); +} + static void parse_args(int argc, char **argv) { // Make sure that all command line options that take an argument // have an argument. for (int i = 1; i < argc; i++) if (take_arg(argv[i])) if (!argv[++i]) usage(1); - StringArray idirafter = {}; - for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-###")) { opt_hash_hash_hash = true; continue; } - if (!strcmp(argv[i], "-cc1")) { opt_cc1 = true; continue; } - if (!strcmp(argv[i], "--help")) usage(0); - + if (!strcmp(argv[i], "-v")) { + opt_verbose = true; + atexit(PrintMemoryUsage); + continue; + } if (!strcmp(argv[i], "-o")) { opt_o = argv[++i]; continue; } - if (!strncmp(argv[i], "-o", 2)) { opt_o = argv[i] + 2; continue; } - if (!strcmp(argv[i], "-S")) { opt_S = true; continue; } - if (!strcmp(argv[i], "-fcommon")) { opt_fcommon = true; continue; } - if (!strcmp(argv[i], "-fno-common")) { opt_fcommon = false; continue; } - if (!strcmp(argv[i], "-c")) { opt_c = true; continue; } - if (!strcmp(argv[i], "-E")) { opt_E = true; continue; } - if (!strncmp(argv[i], "-I", 2)) { strarray_push(&include_paths, argv[i] + 2); continue; } - if (!strcmp(argv[i], "-D")) { define(argv[++i]); continue; } - if (!strncmp(argv[i], "-D", 2)) { define(argv[i] + 2); continue; } - if (!strcmp(argv[i], "-U")) { undef_macro(argv[++i]); continue; } - if (!strncmp(argv[i], "-U", 2)) { undef_macro(argv[i] + 2); continue; } - if (!strcmp(argv[i], "-include")) { strarray_push(&opt_include, argv[++i]); continue; } - if (!strcmp(argv[i], "-x")) { opt_x = parse_opt_x(argv[++i]); continue; } - if (!strncmp(argv[i], "-x", 2)) { opt_x = parse_opt_x(argv[i] + 2); continue; } - if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) { strarray_push(&input_paths, argv[i]); continue; } - + if (!strcmp(argv[i], "-Xassembler")) { + strarray_push(&as_extra_args, argv[++i]); + continue; + } if (!strcmp(argv[i], "-Xlinker")) { strarray_push(&ld_extra_args, argv[++i]); continue; } - if (!strcmp(argv[i], "-s")) { strarray_push(&ld_extra_args, "-s"); continue; } - if (!strcmp(argv[i], "-M")) { opt_M = true; continue; } - if (!strcmp(argv[i], "-MF")) { opt_MF = argv[++i]; continue; } - if (!strcmp(argv[i], "-MP")) { opt_MP = true; continue; } - if (!strcmp(argv[i], "-MT")) { if (opt_MT == NULL) opt_MT = argv[++i]; else - opt_MT = format("%s %s", opt_MT, argv[++i]); + opt_MT = xasprintf("%s %s", opt_MT, argv[++i]); continue; } - if (!strcmp(argv[i], "-MD")) { opt_MD = true; continue; } - if (!strcmp(argv[i], "-MQ")) { if (opt_MT == NULL) opt_MT = quote_makefile(argv[++i]); else - opt_MT = format("%s %s", opt_MT, quote_makefile(argv[++i])); + opt_MT = xasprintf("%s %s", opt_MT, quote_makefile(argv[++i])); continue; } - if (!strcmp(argv[i], "-MMD")) { opt_MD = opt_MMD = true; continue; } - - if (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) { + if (!strcmp(argv[i], "-fpie") || !strcmp(argv[i], "-fpic") || + !strcmp(argv[i], "-fPIC")) { opt_fpic = true; continue; } - + if (!strcmp(argv[i], "-pg")) { + opt_pg = true; + continue; + } + if (!strcmp(argv[i], "-mfentry")) { + opt_mfentry = true; + continue; + } + if (!strcmp(argv[i], "-mrecord-mcount")) { + opt_mrecord_mcount = true; + continue; + } + if (!strcmp(argv[i], "-mnop-mcount")) { + opt_mnop_mcount = true; + continue; + } + if (!strcmp(argv[i], "-mpopcnt")) { + opt_mpopcnt = true; + continue; + } if (!strcmp(argv[i], "-cc1-input")) { base_file = argv[++i]; continue; } - if (!strcmp(argv[i], "-cc1-output")) { output_file = argv[++i]; continue; } - if (!strcmp(argv[i], "-idirafter")) { strarray_push(&idirafter, argv[i++]); continue; } - if (!strcmp(argv[i], "-static")) { opt_static = true; strarray_push(&ld_extra_args, "-static"); continue; } - if (!strcmp(argv[i], "-shared")) { - opt_shared = true; - strarray_push(&ld_extra_args, "-shared"); - continue; + fprintf(stderr, "error: -shared not supported\n"); + exit(1); } - if (!strcmp(argv[i], "-L")) { strarray_push(&ld_extra_args, "-L"); strarray_push(&ld_extra_args, argv[++i]); continue; } - if (!strncmp(argv[i], "-L", 2)) { strarray_push(&ld_extra_args, "-L"); strarray_push(&ld_extra_args, argv[i] + 2); continue; } - +#if 0 if (!strcmp(argv[i], "-hashmap-test")) { hashmap_test(); exit(0); } - +#endif // These options are ignored for now. - if (!strncmp(argv[i], "-O", 2) || !strncmp(argv[i], "-W", 2) || - !strncmp(argv[i], "-g", 2) || !strncmp(argv[i], "-std=", 5) || - !strcmp(argv[i], "-ffreestanding") || + if (startswith(argv[i], "-O") || startswith(argv[i], "-W") || + startswith(argv[i], "-g") || startswith(argv[i], "-std=") || + startswith(argv[i], "-fno-") || startswith(argv[i], "-mno-") || + startswith(argv[i], "-fsanitize") || + startswith(argv[i], "-fdebug-prefix-map") || + !strcmp(argv[i], "-fwrapv") || !strcmp(argv[i], "-nostdlib") || + !strcmp(argv[i], "-nostdinc") || !strcmp(argv[i], "-ffreestanding") || + !strcmp(argv[i], "-fstrict-aliasing") || + !strcmp(argv[i], "-fstrict-overflow") || + !strcmp(argv[i], "-frecord-gcc-switches") || + !strcmp(argv[i], "-fsignaling-nans") || + !strcmp(argv[i], "-frounding-math") || + !strcmp(argv[i], "-fcx-limited-range") || + !strcmp(argv[i], "-fmodulo-sched") || + !strcmp(argv[i], "-fmerge-constants") || + !strcmp(argv[i], "-fmerge-all-constants") || !strcmp(argv[i], "-fno-builtin") || !strcmp(argv[i], "-fno-omit-frame-pointer") || !strcmp(argv[i], "-fno-stack-protector") || !strcmp(argv[i], "-fno-strict-aliasing") || !strcmp(argv[i], "-m64") || - !strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w")) + !strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w")) { continue; - + } if (argv[i][0] == '-' && argv[i][1] != '\0') error("unknown argument: %s", argv[i]); - strarray_push(&input_paths, argv[i]); } - for (int i = 0; i < idirafter.len; i++) strarray_push(&include_paths, idirafter.data[i]); - if (input_paths.len == 0) error("no input files"); - // -E implies that the input is the C macro language. if (opt_E) opt_x = FILE_C; } static FILE *open_file(char *path) { if (!path || strcmp(path, "-") == 0) return stdout; - FILE *out = fopen(path, "w"); if (!out) error("cannot open output file: %s: %s", path, strerror(errno)); return out; } -static bool ends_with(char *p, char *q) { - int len1 = strlen(p); - int len2 = strlen(q); - return (len1 >= len2) && !strcmp(p + len1 - len2, q); -} - // Replace file extension static char *replace_extn(char *tmpl, char *extn) { char *filename = basename(strdup(tmpl)); int len1 = strlen(filename); int len2 = strlen(extn); char *buf = calloc(1, len1 + len2 + 2); - char *dot = strrchr(filename, '.'); if (dot) *dot = '\0'; sprintf(buf, "%s%s", filename, extn); @@ -368,25 +379,23 @@ static char *replace_extn(char *tmpl, char *extn) { } static void cleanup(void) { - if (tmpfiles) - for (int i = 0; tmpfiles[i]; i++) unlink(tmpfiles[i]); + if (tmpfiles) { + for (int i = 0; tmpfiles[i]; i++) { + unlink(tmpfiles[i]); + } + } } static char *create_tmpfile(void) { - char tmpl[] = "/tmp/chibicc-XXXXXX"; - char *path = calloc(1, sizeof(tmpl)); - memcpy(path, tmpl, sizeof(tmpl)); - + char *path = xstrcat(kTmpPath, "chibicc-XXXXXX"); int fd = mkstemp(path); if (fd == -1) error("mkstemp failed: %s", strerror(errno)); close(fd); - static int len = 2; tmpfiles = realloc(tmpfiles, sizeof(char *) * len); tmpfiles[len - 2] = path; tmpfiles[len - 1] = NULL; len++; - return path; } @@ -397,43 +406,41 @@ static void run_subprocess(char **argv) { for (int i = 1; argv[i]; i++) fprintf(stderr, " %s", argv[i]); fprintf(stderr, "\n"); } - if (fork() == 0) { // Child process. Run a new command. execvp(argv[0], argv); fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno)); _exit(1); } - // Wait for the child process to finish. int status; - while (wait(&status) > 0) - ; - if (status != 0) exit(1); + for (;;) { + if (wait(&status) <= 0) { + break; + } + } + if (status != 0) { + exit(1); + } } static void run_cc1(int argc, char **argv, char *input, char *output) { char **args = calloc(argc + 10, sizeof(char *)); memcpy(args, argv, argc * sizeof(char *)); args[argc++] = "-cc1"; - if (input) { args[argc++] = "-cc1-input"; args[argc++] = input; } - if (output) { args[argc++] = "-cc1-output"; args[argc++] = output; } - run_subprocess(args); } -// Print tokens to stdout. Used for -E. static void print_tokens(Token *tok) { FILE *out = open_file(opt_o ? opt_o : "-"); - int line = 1; for (; tok->kind != TK_EOF; tok = tok->next) { if (line > 1 && tok->at_bol) fprintf(out, "\n"); @@ -458,30 +465,26 @@ static bool in_std_include_path(char *path) { // used to automate file dependency management. static void print_dependencies(void) { char *path; - if (opt_MF) + if (opt_MF) { path = opt_MF; - else if (opt_MD) + } else if (opt_MD) { path = replace_extn(opt_o ? opt_o : base_file, ".d"); - else if (opt_o) + } else if (opt_o) { path = opt_o; - else + } else { path = "-"; - + } FILE *out = open_file(path); if (opt_MT) fprintf(out, "%s:", opt_MT); else fprintf(out, "%s:", quote_makefile(replace_extn(base_file, ".o"))); - File **files = get_input_files(); - for (int i = 0; files[i]; i++) { if (opt_MMD && in_std_include_path(files[i]->name)) continue; fprintf(out, " \\\n %s", files[i]->name); } - fprintf(out, "\n\n"); - if (opt_MP) { for (int i = 1; files[i]; i++) { if (opt_MMD && in_std_include_path(files[i]->name)) continue; @@ -498,51 +501,52 @@ static Token *must_tokenize_file(char *path) { static Token *append_tokens(Token *tok1, Token *tok2) { if (!tok1 || tok1->kind == TK_EOF) return tok2; - Token *t = tok1; while (t->next->kind != TK_EOF) t = t->next; t->next = tok2; return tok1; } +static FileType get_file_type(char *filename) { + if (opt_x != FILE_NONE) return opt_x; + if (endswith(filename, ".a")) return FILE_AR; + if (endswith(filename, ".o")) return FILE_OBJ; + if (endswith(filename, ".c")) return FILE_C; + if (endswith(filename, ".s")) return FILE_ASM; + if (endswith(filename, ".S")) return FILE_ASM_CPP; + error(": unknown file extension: %s", filename); +} + static void cc1(void) { Token *tok = NULL; - // Process -include option for (int i = 0; i < opt_include.len; i++) { char *incl = opt_include.data[i]; - char *path; - if (file_exists(incl)) { + if (fileexists(incl)) { path = incl; } else { path = search_include_paths(incl); if (!path) error("-include: %s: %s", incl, strerror(errno)); } - Token *tok2 = must_tokenize_file(path); tok = append_tokens(tok, tok2); } - // Tokenize and parse. Token *tok2 = must_tokenize_file(base_file); tok = append_tokens(tok, tok2); tok = preprocess(tok); - // If -M or -MD are given, print file dependencies. if (opt_M || opt_MD) { print_dependencies(); if (opt_M) return; } - // If -E is given, print out preprocessed C code as a result. - if (opt_E) { + if (opt_E || get_file_type(base_file) == FILE_ASM_CPP) { print_tokens(tok); return; } - Obj *prog = parse(tok); - // Traverse the AST to emit assembly. FILE *out = open_file(output_file); codegen(prog, out); @@ -550,108 +554,72 @@ static void cc1(void) { } static void assemble(char *input, char *output) { - char *cmd[] = {"as", "-W", "-I.", "-c", input, "-o", output, NULL}; - run_subprocess(cmd); + char *as = getenv("AS"); + if (!as || !*as) as = "as"; + StringArray arr = {}; + strarray_push(&arr, as); + strarray_push(&arr, "-W"); + strarray_push(&arr, "-I."); + strarray_push(&arr, "-c"); + for (int i = 0; i < as_extra_args.len; i++) { + strarray_push(&arr, as_extra_args.data[i]); + } + strarray_push(&arr, input); + strarray_push(&arr, "-o"); + strarray_push(&arr, output); + strarray_push(&arr, NULL); + run_subprocess(arr.data); } static void run_linker(StringArray *inputs, char *output) { + char *ld = getenv("LD"); + if (!ld || !*ld) ld = "ld"; StringArray arr = {}; - - strarray_push(&arr, "ld"); + strarray_push(&arr, ld); strarray_push(&arr, "-o"); strarray_push(&arr, output); strarray_push(&arr, "-m"); strarray_push(&arr, "elf_x86_64"); - - if (opt_shared) { - strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o"); - strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o"); - } else { - strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crt1.o"); - strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o"); - strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o"); - } - - strarray_push(&arr, "-L/usr/lib/gcc/x86_64-linux-gnu/9"); - strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu"); - strarray_push(&arr, "-L/usr/lib64"); - strarray_push(&arr, "-L/lib/x86_64-linux-gnu"); - strarray_push(&arr, "-L/lib64"); - strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu"); - strarray_push(&arr, "-L/usr/lib"); - strarray_push(&arr, "-L/lib"); - - if (!opt_static) { - strarray_push(&arr, "-dynamic-linker"); - strarray_push(&arr, "/lib64/ld-linux-x86-64.so.2"); - } - - for (int i = 0; i < ld_extra_args.len; i++) + strarray_push(&arr, "-z"); + strarray_push(&arr, "max-page-size=0x1000"); + strarray_push(&arr, "-mnostdlib"); + strarray_push(&arr, "--gc-sections"); + strarray_push(&arr, "--build-id=none"); + strarray_push(&arr, "--no-dynamic-linker"); + strarray_push(&arr, "-Ttext-segment=0x400000"); + strarray_push(&arr, "-T"); + strarray_push(&arr, LDS); + strarray_push(&arr, APE); + strarray_push(&arr, CRT); + for (int i = 0; i < ld_extra_args.len; i++) { strarray_push(&arr, ld_extra_args.data[i]); - - for (int i = 0; i < inputs->len; i++) strarray_push(&arr, inputs->data[i]); - - if (opt_static) { - strarray_push(&arr, "--start-group"); - strarray_push(&arr, "-lgcc"); - strarray_push(&arr, "-lgcc_eh"); - strarray_push(&arr, "-lc"); - strarray_push(&arr, "--end-group"); - } else { - strarray_push(&arr, "-lc"); - strarray_push(&arr, "-lgcc"); - strarray_push(&arr, "--as-needed"); - strarray_push(&arr, "-lgcc_s"); - strarray_push(&arr, "--no-as-needed"); } - - if (opt_shared) - strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o"); - else - strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o"); - - strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crtn.o"); + for (int i = 0; i < inputs->len; i++) { + strarray_push(&arr, inputs->data[i]); + } strarray_push(&arr, NULL); - run_subprocess(arr.data); } -static FileType get_file_type(char *filename) { - if (opt_x != FILE_NONE) return opt_x; - - if (ends_with(filename, ".a")) return FILE_AR; - if (ends_with(filename, ".so")) return FILE_DSO; - if (ends_with(filename, ".o")) return FILE_OBJ; - if (ends_with(filename, ".c")) return FILE_C; - if (ends_with(filename, ".s")) return FILE_ASM; - - error(": unknown file extension: %s", filename); -} - int main(int argc, char **argv) { + showcrashreports(); atexit(cleanup); init_macros(); parse_args(argc, argv); - if (opt_cc1) { add_default_include_paths(argv[0]); cc1(); return 0; } - if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E)) error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files"); - StringArray ld_args = {}; - for (int i = 0; i < input_paths.len; i++) { char *input = input_paths.data[i]; - if (!strncmp(input, "-l", 2)) { strarray_push(&ld_args, input); continue; } - if (!strncmp(input, "-Wl,", 4)) { char *s = strdup(input + 4); char *arg = strtok(s, ","); @@ -661,43 +629,38 @@ int main(int argc, char **argv) { } continue; } - char *output; - if (opt_o) + if (opt_o) { output = opt_o; - else if (opt_S) + } else if (opt_S) { output = replace_extn(input, ".s"); - else + } else { output = replace_extn(input, ".o"); - + } FileType type = get_file_type(input); - // Handle .o or .a if (type == FILE_OBJ || type == FILE_AR || type == FILE_DSO) { strarray_push(&ld_args, input); continue; } - // Handle .s if (type == FILE_ASM) { - if (!opt_S) assemble(input, output); + if (!opt_S) { + assemble(input, output); + } continue; } - assert(type == FILE_C); - // Just preprocess if (opt_E || opt_M) { run_cc1(argc, argv, input, NULL); continue; } - // Compile if (opt_S) { run_cc1(argc, argv, input, output); continue; } - // Compile and assemble if (opt_c) { char *tmp = create_tmpfile(); @@ -705,7 +668,6 @@ int main(int argc, char **argv) { assemble(tmp, output); continue; } - // Compile, assemble and link char *tmp1 = create_tmpfile(); char *tmp2 = create_tmpfile(); @@ -714,7 +676,8 @@ int main(int argc, char **argv) { strarray_push(&ld_args, tmp2); continue; } - - if (ld_args.len > 0) run_linker(&ld_args, opt_o ? opt_o : "a.out"); + if (ld_args.len > 0) { + run_linker(&ld_args, opt_o ? opt_o : "a.out"); + } return 0; } diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index 91c059f6..a34bd8c3 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -1,21 +1,21 @@ #ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ #define COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -#define _POSIX_C_SOURCE 200809L - #include "libc/assert.h" #include "libc/bits/popcnt.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" #include "libc/calls/weirdtypes.h" #include "libc/conv/conv.h" +#include "libc/conv/itoa.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" +#include "libc/limits.h" +#include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/mem/mem.h" +#include "libc/nexgen32e/bsf.h" +#include "libc/nexgen32e/bsr.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/stdio/temp.h" @@ -25,30 +25,38 @@ COSMOPOLITAN_C_START_ #include "libc/unicode/unicode.h" #include "libc/x/x.h" #include "third_party/gdtoa/gdtoa.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ #pragma GCC diagnostic ignored "-Wswitch" -#ifndef __GNUC__ -#define __attribute__(x) -#endif - -typedef struct Type Type; -typedef struct Node Node; -typedef struct Member Member; -typedef struct Relocation Relocation; +typedef struct Asm Asm; +typedef struct AsmOperand AsmOperand; +typedef struct File File; +typedef struct FpClassify FpClassify; typedef struct Hideset Hideset; +typedef struct Member Member; +typedef struct Node Node; +typedef struct Obj Obj; +typedef struct Relocation Relocation; +typedef struct Relocation Relocation; +typedef struct StaticAsm StaticAsm; +typedef struct StringArray StringArray; +typedef struct Token Token; +typedef struct TokenStack TokenStack; +typedef struct Type Type; // // strarray.c // -typedef struct { +struct StringArray { char **data; int capacity; int len; -} StringArray; +}; -void strarray_push(StringArray *arr, char *s); +void strarray_push(StringArray *, char *); // // tokenize.c @@ -64,74 +72,144 @@ typedef enum { TK_EOF, // End-of-file markers } TokenKind; -typedef struct { +struct File { char *name; int file_no; char *contents; - // For #line directive char *display_name; int line_delta; -} File; +}; // Token type -typedef struct Token Token; struct Token { TokenKind kind; // Token kind - Token *next; // Next token - int64_t val; // If kind is TK_NUM, its value - long double fval; // If kind is TK_NUM, its value - char *loc; // Token location int len; // Token length - Type *ty; // Used if TK_NUM or TK_STR - char *str; // String literal contents including terminating '\0' - - File *file; // Source location - char *filename; // Filename int line_no; // Line number int line_delta; // Line number bool at_bol; // True if this token is at beginning of line bool has_space; // True if this token follows a space character + Token *next; // Next token + char *loc; // Token location + Type *ty; // Used if TK_NUM or TK_STR + File *file; // Source location + char *filename; // Filename Hideset *hideset; // For macro expansion Token *origin; // If this is expanded from a macro, the original token + union { + int64_t val; // If kind is TK_NUM, its value + long double fval; // If kind is TK_NUM, its value + char *str; // String literal contents including terminating '\0' + }; }; -noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2))); -noreturn void error_at(char *loc, char *fmt, ...) - __attribute__((format(printf, 2, 3))); -noreturn void error_tok(Token *tok, char *fmt, ...) - __attribute__((format(printf, 2, 3))); -void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3))); -bool equal(Token *tok, char *op); -Token *skip(Token *tok, char *op); -bool consume(Token **rest, Token *tok, char *str); -void convert_pp_tokens(Token *tok); -File **get_input_files(void); -File *new_file(char *name, int file_no, char *contents); -Token *tokenize_string_literal(Token *tok, Type *basety); -Token *tokenize(File *file); -Token *tokenize_file(char *filename); +void error(char *, ...) + __attribute__((__noreturn__, __format__(__printf__, 1, 2))); +void error_at(char *, char *, ...) + __attribute__((__noreturn__, __format__(__printf__, 2, 3))); +void error_tok(Token *, char *, ...) + __attribute__((__noreturn__, __format__(__printf__, 2, 3))); +void warn_tok(Token *, char *, ...) + __attribute__((__format__(__printf__, 2, 3))); -#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__) +File **get_input_files(void); +File *new_file(char *, int, char *); +Token *skip(Token *, char *); +Token *tokenize(File *); +Token *tokenize_file(char *); +Token *tokenize_string_literal(Token *, Type *); +bool consume(Token **, Token *, char *, size_t); +bool equal(Token *, char *, size_t); +void convert_pp_tokens(Token *); + +#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__) +#define EQUAL(T, S) equal(T, S, strlen(S)) +#define CONSUME(R, T, S) consume(R, T, S, strlen(S)) // // preprocess.c // -char *format(char *fmt, ...); -char *search_include_paths(char *filename); -bool file_exists(char *path); +char *search_include_paths(char *); void init_macros(void); -void define_macro(char *name, char *buf); -void undef_macro(char *name); -Token *preprocess(Token *tok); +void define_macro(char *, char *); +void undef_macro(char *); +Token *preprocess(Token *); + +// +// asm.c +// + +#define kAsmImm 1 +#define kAsmMem 2 +#define kAsmReg 4 +#define kAsmMmx 8 +#define kAsmXmm 16 +#define kAsmFpu 32 +#define kAsmRaw 64 +#define kAsmFlag 128 + +struct AsmOperand { + uint8_t reg; + uint8_t type; + char flow; + char x87mask; + bool isused; + int regmask; + int predicate; + char *str; + Node *node; + Token *tok; + int64_t val; + char **label; +}; + +struct Asm { + int n; + char *str; + Token *tok; + AsmOperand ops[20]; + bool isgnu; + bool flagclob; + uint8_t x87clob; + uint16_t regclob; + uint16_t xmmclob; +}; + +struct StaticAsm { + StaticAsm *next; + Asm *body; +}; + +extern StaticAsm *staticasms; + +Asm *asm_stmt(Token **, Token *); +void flushln(void); +void gen_addr(Node *); +void gen_asm(Asm *); +void gen_expr(Node *); +void pop(char *); +void popreg(char *); +void print_loc(int64_t, int64_t); +void push(void); +void pushreg(char *); + +// +// fpclassify.c +// + +struct FpClassify { + Node *node; + int args[5]; +}; + +void gen_fpclassify(FpClassify *); // // parse.c // // Variable or function -typedef struct Obj Obj; struct Obj { Obj *next; char *name; // Variable name @@ -139,31 +217,36 @@ struct Obj { Token *tok; // representative token bool is_local; // local or global/function int align; // alignment - // Local variable int offset; - // Global variable or function bool is_function; bool is_definition; bool is_static; - + bool is_weak; + bool is_externally_visible; + char *asmname; + char *section; + char *visibility; // Global variable bool is_tentative; + bool is_string_literal; bool is_tls; char *init_data; Relocation *rel; - // Function bool is_inline; + bool is_aligned; + bool is_noreturn; + bool is_destructor; + bool is_constructor; + int stack_size; Obj *params; Node *body; Obj *locals; Obj *va_area; Obj *alloca_bottom; - int stack_size; - - // Static inline function + // Dead Code Elimination bool is_live; bool is_root; StringArray refs; @@ -172,7 +255,6 @@ struct Obj { // Global variable can be initialized either by a constant expression // or a pointer to another global variable. This struct represents the // latter. -typedef struct Relocation Relocation; struct Relocation { Relocation *next; int offset; @@ -180,127 +262,139 @@ struct Relocation { long addend; }; -// AST node typedef enum { - ND_NULL_EXPR, // Do nothing - ND_ADD, // + - ND_SUB, // - - ND_MUL, // * - ND_DIV, // / - ND_NEG, // unary - - ND_MOD, // % - ND_BITAND, // & - ND_BITOR, // | - ND_BITXOR, // ^ - ND_SHL, // << - ND_SHR, // >> - ND_EQ, // == - ND_NE, // != - ND_LT, // < - ND_LE, // <= - ND_ASSIGN, // = - ND_COND, // ?: - ND_COMMA, // , - ND_MEMBER, // . (struct member access) - ND_ADDR, // unary & - ND_DEREF, // unary * - ND_NOT, // ! - ND_BITNOT, // ~ - ND_LOGAND, // && - ND_LOGOR, // || - ND_RETURN, // "return" - ND_IF, // "if" - ND_FOR, // "for" or "while" - ND_DO, // "do" - ND_SWITCH, // "switch" - ND_CASE, // "case" - ND_BLOCK, // { ... } - ND_GOTO, // "goto" - ND_GOTO_EXPR, // "goto" labels-as-values - ND_LABEL, // Labeled statement - ND_LABEL_VAL, // [GNU] Labels-as-values - ND_FUNCALL, // Function call - ND_EXPR_STMT, // Expression statement - ND_STMT_EXPR, // Statement expression - ND_VAR, // Variable - ND_VLA_PTR, // VLA designator - ND_NUM, // Integer - ND_CAST, // Type cast - ND_MEMZERO, // Zero-clear a stack variable - ND_ASM, // "asm" - ND_CAS, // Atomic compare-and-swap - ND_EXCH, // Atomic exchange + ND_NULL_EXPR, // Do nothing + ND_ADD, // + + ND_SUB, // - + ND_MUL, // * + ND_DIV, // / + ND_NEG, // unary - + ND_MOD, // % + ND_BITAND, // & + ND_BITOR, // | + ND_BITXOR, // ^ + ND_SHL, // << + ND_SHR, // >> + ND_EQ, // == + ND_NE, // != + ND_LT, // < + ND_LE, // <= + ND_ASSIGN, // = + ND_COND, // ?: + ND_COMMA, // , + ND_MEMBER, // . (struct member access) + ND_ADDR, // unary & + ND_DEREF, // unary * + ND_NOT, // ! + ND_BITNOT, // ~ + ND_LOGAND, // && + ND_LOGOR, // || + ND_RETURN, // "return" + ND_IF, // "if" + ND_FOR, // "for" or "while" + ND_DO, // "do" + ND_SWITCH, // "switch" + ND_CASE, // "case" + ND_BLOCK, // { ... } + ND_GOTO, // "goto" + ND_GOTO_EXPR, // "goto" labels-as-values + ND_LABEL, // Labeled statement + ND_LABEL_VAL, // [GNU] Labels-as-values + ND_FUNCALL, // Function call + ND_EXPR_STMT, // Expression statement + ND_STMT_EXPR, // Statement expression + ND_VAR, // Variable + ND_VLA_PTR, // VLA designator + ND_NUM, // Integer + ND_CAST, // Type cast + ND_MEMZERO, // Zero-clear a stack variable + ND_ASM, // "asm" + ND_CAS, // Atomic compare-and-swap + ND_EXCH, // Atomic exchange + ND_FPCLASSIFY, // floating point classify } NodeKind; -// AST node type struct Node { NodeKind kind; // Node kind Node *next; // Next node Type *ty; // Type, e.g. int or pointer to int Token *tok; // Representative token - - Node *lhs; // Left-hand side - Node *rhs; // Right-hand side - + Node *lhs; // Left-hand side + Node *rhs; // Right-hand side // "if" or "for" statement Node *cond; Node *then; Node *els; Node *init; Node *inc; - - // "break" and "continue" labels - char *brk_label; - char *cont_label; - // Block or statement expression Node *body; - - // Struct member access - Member *member; - - // Function call - Type *func_ty; - Node *args; - bool pass_by_stack; - Obj *ret_buffer; - - // Goto or labeled statement, or labels-as-values - char *label; - char *unique_label; - Node *goto_next; - - // Switch - Node *case_next; - Node *default_case; - - // Case - long begin; - long end; - - // "asm" string literal - char *asm_str; - - // Atomic compare-and-swap - Node *cas_addr; - Node *cas_old; - Node *cas_new; - - // Atomic op= operators - Obj *atomic_addr; - Node *atomic_expr; - - // Variable - Obj *var; - - // Numeric literal - int64_t val; - long double fval; + union { + struct { + // Function call + Type *func_ty; + Node *args; + bool pass_by_stack; + Obj *ret_buffer; + }; + struct { + // Switch + Node *case_next; + Node *default_case; + // Goto or labeled statement, or labels-as-values + char *label; + char *unique_label; + Node *goto_next; + // "break" and "continue" labels + char *brk_label; + char *cont_label; + // Case + long begin; + long end; + }; + struct { + // Struct member access + Member *member; + }; + struct { + // Assembly + Asm *azm; + }; + struct { + // Atomic compare-and-swap + Node *cas_addr; + Node *cas_old; + Node *cas_new; + }; + struct { + // Atomic op= operators + Obj *atomic_addr; + Node *atomic_expr; + }; + struct { + // Variable + Obj *var; + }; + struct { + // Numeric literal + int64_t val; + long double fval; + }; + struct { + FpClassify *fpc; + }; + }; }; -Node *new_cast(Node *expr, Type *ty); -int64_t const_expr(Token **rest, Token *tok); -Obj *parse(Token *tok); +Node *expr(Token **, Token *); +Node *new_cast(Node *, Type *); +Node *new_node(NodeKind, Token *); +Obj *parse(Token *); +bool is_const_expr(Node *); +char *ConsumeStringLiteral(Token **, Token *); +int64_t const_expr(Token **, Token *); +int64_t eval(Node *); +int64_t eval2(Node *, char ***); // // type.c @@ -313,6 +407,7 @@ typedef enum { TY_SHORT, TY_INT, TY_LONG, + TY_INT128, TY_FLOAT, TY_DOUBLE, TY_LDOUBLE, @@ -332,7 +427,6 @@ struct Type { bool is_unsigned; // unsigned or signed bool is_atomic; // true if _Atomic Type *origin; // for type compatibility check - // Pointer-to or array-of type. We intentionally use the same member // to represent pointer/array duality in C. // @@ -342,23 +436,20 @@ struct Type { // naturally handled as if it were "pointer to T", as required by // the C spec. Type *base; - // Declaration Token *name; Token *name_pos; - // Array int array_len; - + int vector_size; // Variable-length array Node *vla_len; // # of elements Obj *vla_size; // sizeof() value - // Struct Member *members; bool is_flexible; bool is_packed; - + bool is_aligned; // Function type Type *return_ty; Type *params; @@ -375,59 +466,70 @@ struct Member { int idx; int align; int offset; - // Bitfield bool is_bitfield; int bit_offset; int bit_width; }; -extern Type *ty_void; -extern Type *ty_bool; +extern Type ty_void[1]; +extern Type ty_bool[1]; +extern Type ty_char[1]; +extern Type ty_short[1]; +extern Type ty_int[1]; +extern Type ty_long[1]; +extern Type ty_int128[1]; +extern Type ty_uchar[1]; +extern Type ty_ushort[1]; +extern Type ty_uint[1]; +extern Type ty_ulong[1]; +extern Type ty_uint128[1]; +extern Type ty_float[1]; +extern Type ty_double[1]; +extern Type ty_ldouble[1]; -extern Type *ty_char; -extern Type *ty_short; -extern Type *ty_int; -extern Type *ty_long; - -extern Type *ty_uchar; -extern Type *ty_ushort; -extern Type *ty_uint; -extern Type *ty_ulong; - -extern Type *ty_float; -extern Type *ty_double; -extern Type *ty_ldouble; - -bool is_integer(Type *ty); -bool is_flonum(Type *ty); -bool is_numeric(Type *ty); -bool is_compatible(Type *t1, Type *t2); -Type *copy_type(Type *ty); -Type *pointer_to(Type *base); -Type *func_type(Type *return_ty); -Type *array_of(Type *base, int size); -Type *vla_of(Type *base, Node *expr); +bool is_integer(Type *); +bool is_flonum(Type *); +bool is_numeric(Type *); +bool is_compatible(Type *, Type *); +Type *copy_type(Type *); +Type *pointer_to(Type *); +Type *func_type(Type *); +Type *array_of(Type *, int); +Type *vla_of(Type *, Node *); Type *enum_type(void); Type *struct_type(void); -void add_type(Node *node); +void add_type(Node *); + +// +// cast.c +// + +void gen_cast(Type *, Type *); // // codegen.c // -void codegen(Obj *prog, FILE *out); -int align_to(int n, int align); +extern int depth; +extern FILE *output_stream; + +int align_to(int, int); +int count(void); +void cmp_zero(Type *); +void codegen(Obj *, FILE *); +void gen_stmt(Node *); +void println(char *, ...) __attribute__((__format__(__printf__, 1, 2))); // // unicode.c // -int encode_utf8(char *buf, uint32_t c); -uint32_t decode_utf8(char **new_pos, char *p); -bool is_ident1(uint32_t c); -bool is_ident2(uint32_t c); -int str_width(char *p, int len); +int encode_utf8(char *, uint32_t); +uint32_t decode_utf8(char **, char *); +bool is_ident1(uint32_t); +bool is_ident2(uint32_t); +int str_width(char *, int); // // hashmap.c @@ -445,29 +547,28 @@ typedef struct { int used; } HashMap; -void *hashmap_get(HashMap *map, char *key); -void *hashmap_get2(HashMap *map, char *key, int keylen); -void hashmap_put(HashMap *map, char *key, void *val); -void hashmap_put2(HashMap *map, char *key, int keylen, void *val); -void hashmap_delete(HashMap *map, char *key); -void hashmap_delete2(HashMap *map, char *key, int keylen); +void *hashmap_get(HashMap *, char *); +void *hashmap_get2(HashMap *, char *, int); +void hashmap_put(HashMap *, char *, void *); +void hashmap_put2(HashMap *, char *, int, void *); +void hashmap_delete(HashMap *, char *); +void hashmap_delete2(HashMap *, char *, int); void hashmap_test(void); // -// main.c +// chibicc.c // extern StringArray include_paths; -extern bool opt_fpic; extern bool opt_fcommon; +extern bool opt_fpic; +extern bool opt_verbose; +extern bool opt_mpopcnt; extern char *base_file; - -typedef struct StaticAsm { - struct StaticAsm *next; - Node *body; -} StaticAsm; - -extern struct StaticAsm *staticasms; +extern bool opt_pg; +extern bool opt_mfentry; +extern bool opt_mnop_mcount; +extern bool opt_mrecord_mcount; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index 000f5ccf..cd013f41 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -1,70 +1,109 @@ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ +# +# SYNOPSIS +# +# C Compiler +# +# OVERVIEW +# +# This makefile compiles and runs each test twice. The first with +# GCC-built chibicc, and a second time with chibicc-built chibicc + +CHIBICC = o/$(MODE)/third_party/chibicc/chibicc.com.dbg +CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com.dbg +CHIBICC_FLAGS = \ + -fno-common \ + -include libc/integral/normalize.inc PKGS += THIRD_PARTY_CHIBICC - THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A THIRD_PARTY_CHIBICC = $(THIRD_PARTY_CHIBICC_A_DEPS) $(THIRD_PARTY_CHIBICC_A) THIRD_PARTY_CHIBICC_A = o/$(MODE)/third_party/chibicc/chibicc.a THIRD_PARTY_CHIBICC_A_FILES := $(wildcard third_party/chibicc/*) THIRD_PARTY_CHIBICC_A_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_A_FILES)) -THIRD_PARTY_CHIBICC_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_CHIBICC_A_FILES)) -THIRD_PARTY_CHIBICC_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES)) +THIRD_PARTY_CHIBICC_A_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES)) -THIRD_PARTY_CHIBICC_BINS = \ - o/$(MODE)/third_party/chibicc/chibicc.com +THIRD_PARTY_CHIBICC_BINS = \ + o/$(MODE)/third_party/chibicc/chibicc.com.dbg \ + o/$(MODE)/third_party/chibicc/chibicc.com \ + o/$(MODE)/third_party/chibicc/chibicc2.com.dbg \ + o/$(MODE)/third_party/chibicc/chibicc2.com -THIRD_PARTY_CHIBICC_A_SRCS = \ - $(THIRD_PARTY_CHIBICC_A_SRCS_S) \ - $(THIRD_PARTY_CHIBICC_A_SRCS_C) +THIRD_PARTY_CHIBICC_A_OBJS = \ + $(THIRD_PARTY_CHIBICC_A_SRCS:%=o/$(MODE)/%.zip.o) \ + $(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.o) -THIRD_PARTY_CHIBICC_A_OBJS = \ - $(THIRD_PARTY_CHIBICC_A_SRCS:%=o/$(MODE)/%.zip.o) \ - $(THIRD_PARTY_CHIBICC_A_SRCS_S:%.S=o/$(MODE)/%.o) \ - $(THIRD_PARTY_CHIBICC_A_SRCS_C:%.c=o/$(MODE)/%.o) - -THIRD_PARTY_CHIBICC_A_CHECKS = \ - $(THIRD_PARTY_CHIBICC_A).pkg \ +THIRD_PARTY_CHIBICC_A_CHECKS = \ + $(THIRD_PARTY_CHIBICC_A).pkg \ $(THIRD_PARTY_CHIBICC_A_HDRS:%=o/$(MODE)/%.ok) -THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \ - LIBC_STR \ - LIBC_STUBS \ - LIBC_FMT \ - LIBC_NEXGEN32E \ - LIBC_UNICODE \ - LIBC_STDIO \ - LIBC_MEM \ - LIBC_LOG \ - LIBC_CALLS \ - LIBC_CALLS_HEFTY \ - LIBC_TIME \ - LIBC_X \ - LIBC_CONV \ - LIBC_RUNTIME \ +THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \ + LIBC_BITS \ + LIBC_CALLS \ + LIBC_CALLS_HEFTY \ + LIBC_CONV \ + LIBC_FMT \ + LIBC_LOG \ + LIBC_MEM \ + LIBC_NEXGEN32E \ + LIBC_RUNTIME \ + LIBC_STDIO \ + LIBC_LOG \ + LIBC_STR \ + LIBC_STUBS \ + LIBC_TIME \ + LIBC_UNICODE \ + LIBC_X \ + THIRD_PARTY_DLMALLOC \ THIRD_PARTY_GDTOA -THIRD_PARTY_CHIBICC_A_DEPS := \ +THIRD_PARTY_CHIBICC_A_DEPS := \ $(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x)))) -$(THIRD_PARTY_CHIBICC_A): \ - third_party/chibicc/ \ - $(THIRD_PARTY_CHIBICC_A).pkg \ +$(THIRD_PARTY_CHIBICC_A): \ + third_party/chibicc/ \ + $(THIRD_PARTY_CHIBICC_A).pkg \ $(THIRD_PARTY_CHIBICC_A_OBJS) -$(THIRD_PARTY_CHIBICC_A).pkg: \ - $(THIRD_PARTY_CHIBICC_A_OBJS) \ +$(THIRD_PARTY_CHIBICC_A).pkg: \ + $(THIRD_PARTY_CHIBICC_A_OBJS) \ $(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/third_party/chibicc/%.com.dbg: \ - $(THIRD_PARTY_CHIBICC_A_DEPS) \ - $(THIRD_PARTY_CHIBICC_A) \ - o/$(MODE)/third_party/chibicc/%.o \ - $(THIRD_PARTY_CHIBICC_A).pkg \ - $(CRT) \ +o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \ + $(THIRD_PARTY_CHIBICC_A_DEPS) \ + $(THIRD_PARTY_CHIBICC_A) \ + o/$(MODE)/third_party/chibicc/chibicc.o \ + $(THIRD_PARTY_CHIBICC_A).pkg \ + $(CRT) \ $(APE) @$(APELINK) +o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \ + $(THIRD_PARTY_CHIBICC_A_DEPS) \ + $(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.chibicc.o) \ + $(THIRD_PARTY_CHIBICC_A).pkg \ + $(CRT) \ + $(APE) + @$(APELINK) + +o/$(MODE)/third_party/chibicc/chibicc.o: \ + CPPFLAGS += \ + -DCRT=\"$(CRT)\" \ + -DAPE=\"o/$(MODE)/ape/ape.o\" \ + -DLDS=\"o/$(MODE)/ape/ape.lds\" + +o/$(MODE)/third_party/chibicc/chibicc.chibicc.s: \ + CHIBICC_FLAGS += \ + -DCRT=\"$(CRT)\" \ + -DAPE=\"o/$(MODE)/ape/ape.o\" \ + -DLDS=\"o/$(MODE)/ape/ape.lds\" + +o/$(MODE)/%.chibicc.s: %.c o/$(MODE)/third_party/chibicc/chibicc.com.dbg + @ACTION=CHIBICC TARGET=$@ build/do $(CHIBICC) $(CHIBICC_FLAGS) -S -o $@ $< +o/$(MODE)/%.chibicc2.s: %.c o/$(MODE)/third_party/chibicc/chibicc2.com.dbg + @ACTION=CHIBICC2 TARGET=$@ build/do $(CHIBICC2) $(CHIBICC_FLAGS) -S -o $@ $< + THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x))) THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_CHIBICC_HDRS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_HDRS)) @@ -73,6 +112,8 @@ THIRD_PARTY_CHIBICC_OBJS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_O $(THIRD_PARTY_CHIBICC_OBJS): $(BUILD_FILES) third_party/chibicc/chibicc.mk .PHONY: o/$(MODE)/third_party/chibicc -o/$(MODE)/third_party/chibicc: \ - $(THIRD_PARTY_CHIBICC_BINS) \ - $(THIRD_PARTY_CHIBICC_CHECKS) +o/$(MODE)/third_party/chibicc: \ + o/$(MODE)/third_party/chibicc/test \ + $(THIRD_PARTY_CHIBICC_BINS) \ + $(THIRD_PARTY_CHIBICC_CHECKS) \ + $(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.chibicc.s) diff --git a/third_party/chibicc/codegen.c b/third_party/chibicc/codegen.c index bc9375b7..31667814 100644 --- a/third_party/chibicc/codegen.c +++ b/third_party/chibicc/codegen.c @@ -3,55 +3,213 @@ #define GP_MAX 6 #define FP_MAX 8 -static FILE *output_file; -static int depth; +int depth; static char *argreg8[] = {"%dil", "%sil", "%dl", "%cl", "%r8b", "%r9b"}; static char *argreg16[] = {"%di", "%si", "%dx", "%cx", "%r8w", "%r9w"}; static char *argreg32[] = {"%edi", "%esi", "%edx", "%ecx", "%r8d", "%r9d"}; static char *argreg64[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; static Obj *current_fn; +static char *lastline; -static void gen_expr(Node *node); -static void gen_stmt(Node *node); +FILE *output_stream; -__attribute__((format(printf, 1, 2))) static void println(char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vfprintf(output_file, fmt, ap); - fprintf(output_file, "\n"); +void flushln(void) { + if (!lastline) return; + fputs(lastline, output_stream); + fputc('\n', output_stream); + free(lastline); + lastline = NULL; } -static int count(void) { +static void emitln(char *nextline) { + if (lastline) { + // unsophisticated optimization pass to reduce asm noise a little bit + if ((!strcmp(lastline, "\txor\t%eax,%eax") && + !strcmp(nextline, "\tcltq")) || + (!strcmp(lastline, "\tmov\t$0x1,%eax") && + !strcmp(nextline, "\tcltq")) || + (!strcmp(lastline, "\tmovslq\t(%rax),%rax") && + !strcmp(nextline, "\tcltq"))) { + free(nextline); + } else if (!strcmp(lastline, "\tmov\t(%rax),%rax") && + !strcmp(nextline, "\tpush\t%rax")) { + free(lastline); + free(nextline); + lastline = strdup("\tpush\t(%rax)"); + } else if (!strcmp(lastline, "\tmov\t$0x1,%eax") && + !strcmp(nextline, "\tpush\t%rax")) { + free(lastline); + free(nextline); + lastline = strdup("\tpush\t$1"); + } else if (!strcmp(lastline, "\tpush\t(%rax)") && + !strcmp(nextline, "\tpop\t%rdi")) { + free(lastline); + free(nextline); + lastline = strdup("\tmov\t(%rax),%rdi"); + } else if (!strcmp(lastline, "\tpush\t%rax") && + !strcmp(nextline, "\tpop\t%rdi")) { + free(lastline); + free(nextline); + lastline = strdup("\tmov\t%rax,%rdi"); + } else { + flushln(); + lastline = nextline; + } + } else { + lastline = nextline; + } +} + +void println(char *fmt, ...) { + va_list ap; + char *nextline; + va_start(ap, fmt); + emitln(xvasprintf(fmt, ap)); + va_end(ap); +} + +int count(void) { static int i = 1; return i++; } -static void push(void) { - println(" push %%rax"); +void push(void) { + println("\tpush\t%%rax"); depth++; } -static void pop(char *arg) { - println(" pop %s", arg); +void pop(char *arg) { + println("\tpop\t%s", arg); depth--; } -static void pushf(void) { - println(" sub $8, %%rsp"); - println(" movsd %%xmm0, (%%rsp)"); +void push2(void) { + println("\tpush\t%%rdx"); + println("\tpush\t%%rax"); + depth++; depth++; } -static void popf(int reg) { - println(" movsd (%%rsp), %%xmm%d", reg); - println(" add $8, %%rsp"); +void pop2(char *a, char *b) { + println("\tpop\t%s", a); + println("\tpop\t%s", b); + depth--; depth--; } -// Round up `n` to the nearest multiple of `align`. For instance, -// align_to(5, 8) returns 8 and align_to(11, 8) returns 16. -int align_to(int n, int align) { - return (n + align - 1) / align * align; +void pushreg(char *arg) { + println("\tpush\t%%%s", arg); + depth++; +} + +void popreg(char *arg) { + println("\tpop\t%%%s", arg); + depth--; +} + +static const char *nameof(Obj *obj) { + if (obj->asmname) { + return obj->asmname; + } else { + return obj->name; + } +} + +static void pushf(Type *ty) { + if (ty->vector_size == 16) { + println("\tsub\t$16,%%rsp"); + println("\tmovdqu\t%%xmm0,(%%rsp)"); + depth++; + depth++; + } else { + println("\tpush\t%%rax"); + println("\tmovsd\t%%xmm0,(%%rsp)"); + depth++; + } +} + +static void popf(Type *ty, int reg) { + if (ty->vector_size == 16) { + println("\tmovdqu\t(%%rsp),%%xmm%d", reg); + println("\tadd\t$16,%%rsp"); + depth--; + depth--; + } else { + println("\tmovsd\t(%%rsp),%%xmm%d", reg); + println("\tadd\t$8,%%rsp"); + depth--; + } +} + +static void print_visibility(Obj *obj) { + if (obj->visibility) { + if (!strcmp(obj->visibility, "hidden")) { + println("\t.hidden\t%s", nameof(obj)); + } else if (!strcmp(obj->visibility, "protected")) { + println("\t.protected %s", nameof(obj)); + } else { + println("\t.globl\t%s", nameof(obj)); + } + } else if (obj->is_static) { + println("\t.local\t%s", nameof(obj)); + } else { + println("\t.globl\t%s", nameof(obj)); + } + if (obj->is_weak) { + println("\t.weak\t%s", nameof(obj)); + } +} + +static void print_align(int align) { + if (align > 1) println("\t.align\t%d", align); +} + +void print_loc(int64_t file, int64_t line) { + static int64_t lastfile = -1; + static int64_t lastline = -1; + char *locbuf, *p; + if (file != lastfile || line != lastline) { + locbuf = malloc(2 + 4 + 1 + 20 + 1 + 20 + 1); + p = stpcpy(locbuf, "\t.loc\t"); + p += int64toarray_radix10(file, p); + *p++ = ' '; + int64toarray_radix10(line, p); + emitln(locbuf); + lastfile = file; + lastline = line; + } +} + +static void print_mov_imm(int64_t val, const char *reg64, const char *reg32) { + if (val) { + if (val != -1) { + if (0 < val && val <= INT32_MAX) { + println("\tmov\t$%#lx,%s", val, reg32); + } else if (INT32_MIN <= val && val < 0) { + println("\tmov\t$%#lx,%s", (int64_t)(int32_t)val, reg64); + } else { + println("\tmov\t$%#lx,%s", val, reg64); + } + } else { + println("\tor\t$-1,%s", reg64); + } + } else { + println("\txor\t%s,%s", reg32, reg32); + } +} + +static bool is_quotable_string(const char *s, size_t n) { + size_t i; + if (!n) return false; + if (s[n - 1]) return false; + for (i = 0; i < n - 1; ++i) { + if (s[i] == '"') return false; + if (s[i] == '\\') return false; + if (s[i] < 0x20 || s[i] >= 0x7f) { + return false; + } + } + return true; } static char *reg_dx(int sz) { @@ -84,43 +242,36 @@ static char *reg_ax(int sz) { // Compute the absolute address of a given node. // It's an error if a given node does not reside in memory. -static void gen_addr(Node *node) { +// asm() requires this not clobber flags or regs other than rax +void gen_addr(Node *node) { switch (node->kind) { case ND_VAR: // Variable-length array, which is always local. if (node->var->ty->kind == TY_VLA) { - println(" mov %d(%%rbp), %%rax", node->var->offset); + println("\tmov\t%d(%%rbp),%%rax", node->var->offset); return; } - // Local variable if (node->var->is_local) { - println(" lea %d(%%rbp), %%rax", node->var->offset); + println("\tlea\t%d(%%rbp),%%rax", node->var->offset); return; } - if (opt_fpic) { - // Thread-local variable if (node->var->is_tls) { - println(" data16 lea %s@tlsgd(%%rip), %%rdi", node->var->name); - println(" .value 0x6666"); - println(" rex64"); - println(" call __tls_get_addr@PLT"); + // Dynamic thread-local variable + println("\tmov\t%%fs:0,%%rax"); + println("\tmov\t%s@dtpoff(%%rax),%%rax", nameof(node->var)); return; } - // Function or global variable - println(" mov %s@GOTPCREL(%%rip), %%rax", node->var->name); + println("\tmov\t%s@gotpcrel(%%rip),%%rax", nameof(node->var)); return; } - - // Thread-local variable + // Static thread-local variable if (node->var->is_tls) { - println(" mov %%fs:0, %%rax"); - println(" add $%s@tpoff, %%rax", node->var->name); + println("\tmov\t%%fs:%s@tpoff,%%rax", nameof(node->var)); return; } - // Here, we generate an absolute address of a function or a global // variable. Even though they exist at a certain address at runtime, // their addresses are not known at link-time for the following @@ -143,18 +294,23 @@ static void gen_addr(Node *node) { // addressing, denoted by `(%rip)`. For the latter, we obtain an // address of a stuff that may be in a shared object file from the // Global Offset Table using `@GOTPCREL(%rip)` notation. - // Function if (node->ty->kind == TY_FUNC) { - if (node->var->is_definition) - println(" lea %s(%%rip), %%rax", node->var->name); - else - println(" mov %s@GOTPCREL(%%rip), %%rax", node->var->name); + if (!opt_fpic) { + println("\tmov\t$%s,%%eax", nameof(node->var)); + } else if (node->var->is_definition) { + println("\tlea\t%s(%%rip),%%rax", nameof(node->var)); + } else { + println("\tmov\t%s@gotpcrel(%%rip),%%rax", nameof(node->var)); + } return; } - // Global variable - println(" lea %s(%%rip), %%rax", node->var->name); + if (opt_fpic) { + println("\tlea\t%s(%%rip),%%rax", nameof(node->var)); + } else { + println("\tmov\t$%s,%%eax", nameof(node->var)); + } return; case ND_DEREF: gen_expr(node->lhs); @@ -165,7 +321,9 @@ static void gen_addr(Node *node) { return; case ND_MEMBER: gen_addr(node->lhs); - println(" add $%d, %%rax", node->member->offset); + if (node->member->offset) { + println("\tlea\t%d(%%rax),%%rax", node->member->offset); + } return; case ND_FUNCALL: if (node->ret_buffer) { @@ -174,10 +332,9 @@ static void gen_addr(Node *node) { } break; case ND_VLA_PTR: - println(" lea %d(%%rbp), %%rax", node->var->offset); + println("\tlea\t%d(%%rbp),%%rax", node->var->offset); return; } - error_tok(node->tok, "not an lvalue"); } @@ -197,207 +354,168 @@ static void load(Type *ty) { // the first element of the array in C" occurs. return; case TY_FLOAT: - println(" movss (%%rax), %%xmm0"); - return; + if (ty->vector_size == 16) { + println("\tmovdqu\t(%%rax),%%xmm0"); + } else { + println("\tmovss\t(%%rax),%%xmm0"); + return; + } case TY_DOUBLE: - println(" movsd (%%rax), %%xmm0"); + if (ty->vector_size == 16) { + println("\tmovdqu\t(%%rax),%%xmm0"); + } else { + println("\tmovsd\t(%%rax),%%xmm0"); + } return; case TY_LDOUBLE: - println(" fldt (%%rax)"); + println("\tfldt\t(%%rax)"); return; + case TY_INT128: + println("\tmov\t8(%%rax),%%rdx"); + println("\tmov\t(%%rax),%%rax"); + return; + default: + break; } - char *insn = ty->is_unsigned ? "movz" : "movs"; - // When we load a char or a short value to a register, we always // extend them to the size of int, so we can assume the lower half of // a register always contains a valid value. The upper half of a // register for char, short and int may contain garbage. When we load // a long value to a register, it simply occupies the entire register. - if (ty->size == 1) - println(" %sbl (%%rax), %%eax", insn); - else if (ty->size == 2) - println(" %swl (%%rax), %%eax", insn); - else if (ty->size == 4) - println(" movslq (%%rax), %%rax"); - else - println(" mov (%%rax), %%rax"); + if (ty->size == 1) { + println("\t%sbl\t(%%rax),%%eax", insn); + } else if (ty->size == 2) { + println("\t%swl\t(%%rax),%%eax", insn); + } else if (ty->size == 4) { + println("\tmovslq\t(%%rax),%%rax"); + } else { + println("\tmov\t(%%rax),%%rax"); + } +} + +static void gen_memcpy(size_t size) { + switch (size) { + case 0: + break; + case 1: + println("\tmov\t(%%rax),%%r8b"); + println("\tmov\t%%r8b,(%%rdi)"); + break; + case 2: + println("\tmov\t(%%rax),%%r8w"); + println("\tmov\t%%r8w,(%%rdi)"); + break; + case 3: + println("\tmov\t(%%rax),%%r8w"); + println("\tmov\t%%r8w,(%%rdi)"); + println("\tmov\t2(%%rax),%%r8b"); + println("\tmov\t%%r8b,2(%%rdi)"); + break; + case 4: + println("\tmov\t(%%rax),%%r8d"); + println("\tmov\t%%r8d,(%%rdi)"); + break; + case 5 ... 7: + println("\tmov\t(%%rax),%%r8d"); + println("\tmov\t%d(%%rax),%%r9d", size - 4); + println("\tmov\t%%r8d,(%%rdi)"); + println("\tmov\t%%r9d,%d(%%rdi)", size - 4); + break; + case 8: + println("\tmov\t(%%rax),%%r8"); + println("\tmov\t%%r8,(%%rdi)"); + break; + case 9 ... 15: + println("\tmov\t(%%rax),%%r8"); + println("\tmov\t%d(%%rax),%%r9", size - 8); + println("\tmov\t%%r8,(%%rdi)"); + println("\tmov\t%%r9,%d(%%rdi)", size - 8); + break; + case 16: + println("\tmovdqu\t(%%rax),%%xmm2"); + println("\tmovdqu\t%%xmm2,(%%rdi)"); + break; + case 17 ... 32: + println("\tmovdqu\t(%%rax),%%xmm2"); + println("\tmovdqu\t%d(%%rax),%%xmm3", size - 16); + println("\tmovdqu\t%%xmm2,(%%rdi)"); + println("\tmovdqu\t%%xmm3,%d(%%rdi)", size - 16); + break; + default: + println("\tmov\t%%rax,%%rsi"); + print_mov_imm(size, "%rcx", "%ecx"); + println("\trep movsb"); + break; + } } // Store %rax to an address that the stack top is pointing to. static void store(Type *ty) { pop("%rdi"); - switch (ty->kind) { case TY_STRUCT: case TY_UNION: - for (int i = 0; i < ty->size; i++) { - println(" mov %d(%%rax), %%r8b", i); - println(" mov %%r8b, %d(%%rdi)", i); + gen_memcpy(ty->size); + return; + case TY_FLOAT: + if (ty->vector_size == 16) { + println("\tmovdqu\t%%xmm0,(%%rdi)"); + } else { + println("\tmovss\t%%xmm0,(%%rdi)"); } return; - case TY_FLOAT: - println(" movss %%xmm0, (%%rdi)"); - return; case TY_DOUBLE: - println(" movsd %%xmm0, (%%rdi)"); + if (ty->vector_size == 16) { + println("\tmovdqu\t%%xmm0,(%%rdi)"); + } else { + println("\tmovsd\t%%xmm0,(%%rdi)"); + } return; case TY_LDOUBLE: - println(" fstpt (%%rdi)"); + println("\tfstpt\t(%%rdi)"); + return; + case TY_INT128: + println("\tmov\t%%rax,(%%rdi)"); + println("\tmov\t%%rdx,8(%%rdi)"); return; } - - if (ty->size == 1) - println(" mov %%al, (%%rdi)"); - else if (ty->size == 2) - println(" mov %%ax, (%%rdi)"); - else if (ty->size == 4) - println(" mov %%eax, (%%rdi)"); - else - println(" mov %%rax, (%%rdi)"); + if (ty->size == 1) { + println("\tmov\t%%al,(%%rdi)"); + } else if (ty->size == 2) { + println("\tmov\t%%ax,(%%rdi)"); + } else if (ty->size == 4) { + println("\tmov\t%%eax,(%%rdi)"); + } else { + println("\tmov\t%%rax,(%%rdi)"); + } } -static void cmp_zero(Type *ty) { +void cmp_zero(Type *ty) { switch (ty->kind) { case TY_FLOAT: - println(" xorps %%xmm1, %%xmm1"); - println(" ucomiss %%xmm1, %%xmm0"); + println("\txorps\t%%xmm1,%%xmm1"); + println("\tucomiss\t%%xmm1,%%xmm0"); return; case TY_DOUBLE: - println(" xorpd %%xmm1, %%xmm1"); - println(" ucomisd %%xmm1, %%xmm0"); + println("\txorpd\t%%xmm1,%%xmm1"); + println("\tucomisd\t%%xmm1,%%xmm0"); return; case TY_LDOUBLE: - println(" fldz"); - println(" fucomip"); - println(" fstp %%st(0)"); + println("\tfldz"); + println("\tfucomip"); + println("\tfstp\t%%st"); + return; + case TY_INT128: + println("mov\t%%rax,%%r11"); + println("or\t%%edx,%%r11"); return; } - - if (is_integer(ty) && ty->size <= 4) - println(" cmp $0, %%eax"); - else - println(" cmp $0, %%rax"); -} - -enum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64, F80 }; - -static int getTypeId(Type *ty) { - switch (ty->kind) { - case TY_CHAR: - return ty->is_unsigned ? U8 : I8; - case TY_SHORT: - return ty->is_unsigned ? U16 : I16; - case TY_INT: - return ty->is_unsigned ? U32 : I32; - case TY_LONG: - return ty->is_unsigned ? U64 : I64; - case TY_FLOAT: - return F32; - case TY_DOUBLE: - return F64; - case TY_LDOUBLE: - return F80; + if (is_integer(ty) && ty->size <= 4) { + println("\ttest\t%%eax,%%eax"); + } else { + println("\ttest\t%%rax,%%rax"); } - return U64; -} - -// The table for type casts -static char i32i8[] = "movsbl %al, %eax"; -static char i32u8[] = "movzbl %al, %eax"; -static char i32i16[] = "movswl %ax, %eax"; -static char i32u16[] = "movzwl %ax, %eax"; -static char i32f32[] = "cvtsi2ssl %eax, %xmm0"; -static char i32i64[] = "movslq %eax, %rax"; -static char i32f64[] = "cvtsi2sdl %eax, %xmm0"; -static char i32f80[] = "mov %eax, -4(%rsp)\n fildl -4(%rsp)"; - -static char u32f32[] = "mov %eax, %eax\n cvtsi2ssq %rax, %xmm0"; -static char u32i64[] = "mov %eax, %eax"; -static char u32f64[] = "mov %eax, %eax\n cvtsi2sdq %rax, %xmm0"; -static char u32f80[] = - "mov %eax, %eax\n mov %rax, -8(%rsp)\n fildll -8(%rsp)"; - -static char i64f32[] = "cvtsi2ssq %rax, %xmm0"; -static char i64f64[] = "cvtsi2sdq %rax, %xmm0"; -static char i64f80[] = "movq %rax, -8(%rsp)\n fildll -8(%rsp)"; - -static char u64f32[] = "cvtsi2ssq %rax, %xmm0"; -static char u64f64[] = - "test %rax,%rax\n js 1f\n pxor %xmm0,%xmm0\n cvtsi2sd %rax,%xmm0\n jmp " - "2f\n1: mov %rax,%rdi\n and $1,%eax\n pxor %xmm0,%xmm0\n shr %rdi\n " - "or %rax,%rdi\n cvtsi2sd %rdi,%xmm0\n addsd %xmm0,%xmm0\n 2:"; -static char u64f80[] = - "mov %rax, -8(%rsp)\n fildq -8(%rsp)\n test %rax, %rax\n jns 1f;" - "mov $1602224128, %eax\n mov %eax, -4(%rsp)\n fadds -4(%rsp)\n 1:"; - -static char f32i8[] = "cvttss2sil %xmm0, %eax\n movsbl %al, %eax"; -static char f32u8[] = "cvttss2sil %xmm0, %eax\n movzbl %al, %eax"; -static char f32i16[] = "cvttss2sil %xmm0, %eax\n movswl %ax, %eax"; -static char f32u16[] = "cvttss2sil %xmm0, %eax\n movzwl %ax, %eax"; -static char f32i32[] = "cvttss2sil %xmm0, %eax"; -static char f32u32[] = "cvttss2siq %xmm0, %rax"; -static char f32i64[] = "cvttss2siq %xmm0, %rax"; -static char f32u64[] = "cvttss2siq %xmm0, %rax"; -static char f32f64[] = "cvtss2sd %xmm0, %xmm0"; -static char f32f80[] = "movss %xmm0, -4(%rsp)\n flds -4(%rsp)"; - -static char f64i8[] = "cvttsd2sil %xmm0, %eax\n movsbl %al, %eax"; -static char f64u8[] = "cvttsd2sil %xmm0, %eax\n movzbl %al, %eax"; -static char f64i16[] = "cvttsd2sil %xmm0, %eax\n movswl %ax, %eax"; -static char f64u16[] = "cvttsd2sil %xmm0, %eax\n movzwl %ax, %eax"; -static char f64i32[] = "cvttsd2sil %xmm0, %eax"; -static char f64u32[] = "cvttsd2siq %xmm0, %rax"; -static char f64i64[] = "cvttsd2siq %xmm0, %rax"; -static char f64u64[] = "cvttsd2siq %xmm0, %rax"; -static char f64f32[] = "cvtsd2ss %xmm0, %xmm0"; -static char f64f80[] = "movsd %xmm0, -8(%rsp)\n fldl -8(%rsp)"; - -#define FROM_F80_1 \ - "fnstcw -10(%rsp)\n movzwl -10(%rsp), %eax\n or $12, %ah\n " \ - "mov %ax, -12(%rsp)\n fldcw -12(%rsp)\n " - -#define FROM_F80_2 " -24(%rsp)\n fldcw -10(%rsp)\n " - -static char f80i8[] = FROM_F80_1 "fistps" FROM_F80_2 "movsbl -24(%rsp), %eax"; -static char f80u8[] = FROM_F80_1 "fistps" FROM_F80_2 "movzbl -24(%rsp), %eax"; -static char f80i16[] = FROM_F80_1 "fistps" FROM_F80_2 "movzbl -24(%rsp), %eax"; -static char f80u16[] = FROM_F80_1 "fistpl" FROM_F80_2 "movswl -24(%rsp), %eax"; -static char f80i32[] = FROM_F80_1 "fistpl" FROM_F80_2 "mov -24(%rsp), %eax"; -static char f80u32[] = FROM_F80_1 "fistpl" FROM_F80_2 "mov -24(%rsp), %eax"; -static char f80i64[] = FROM_F80_1 "fistpq" FROM_F80_2 "mov -24(%rsp), %rax"; -static char f80u64[] = FROM_F80_1 "fistpq" FROM_F80_2 "mov -24(%rsp), %rax"; -static char f80f32[] = "fstps -8(%rsp)\n movss -8(%rsp), %xmm0"; -static char f80f64[] = "fstpl -8(%rsp)\n movsd -8(%rsp), %xmm0"; - -static const char *const cast_table[11][11] = /* clang-format off */ { - // i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 f80 - {NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80}, // i8 - {i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80}, // i16 - {i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80}, // i32 - {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i64f32, i64f64, i64f80}, // i64 - {i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64, i32f32, i32f64, i32f80}, // u8 - {i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64, i32f32, i32f64, i32f80}, // u16 - {i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64, u32f32, u32f64, u32f80}, // u32 - {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u64f32, u64f64, u64f80}, // u64 - {f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL, f32f64, f32f80}, // f32 - {f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL, f64f80}, // f64 - {f80i8, f80i16, f80i32, f80i64, f80u8, f80u16, f80u32, f80u64, f80f32, f80f64, NULL}, // f80 -} /* clang-format on */; - -static void cast(Type *from, Type *to) { - if (to->kind == TY_VOID) return; - - if (to->kind == TY_BOOL) { - cmp_zero(from); - println(" setne %%al"); - println(" movzbl %%al, %%eax"); - return; - } - - int t1 = getTypeId(from); - int t2 = getTypeId(to); - if (cast_table[t1][t2]) println(" %s", cast_table[t1][t2]); } // Structs or unions equal or smaller than 16 bytes are passed @@ -418,14 +536,12 @@ static bool has_flonum(Type *ty, int lo, int hi, int offset) { if (!has_flonum(mem->ty, lo, hi, offset + mem->offset)) return false; return true; } - if (ty->kind == TY_ARRAY) { for (int i = 0; i < ty->array_len; i++) if (!has_flonum(ty->base, lo, hi, offset + ty->base->size * i)) return false; return true; } - return offset < lo || hi <= offset || ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE; } @@ -439,26 +555,23 @@ static bool has_flonum2(Type *ty) { } static void push_struct(Type *ty) { - int sz = align_to(ty->size, 8); - println(" sub $%d, %%rsp", sz); + int sz = ROUNDUP(ty->size, 8); + println("\tsub\t$%d,%%rsp", sz); depth += sz / 8; - for (int i = 0; i < ty->size; i++) { - println(" mov %d(%%rax), %%r10b", i); - println(" mov %%r10b, %d(%%rsp)", i); + println("\tmov\t%d(%%rax),%%r10b", i); + println("\tmov\t%%r10b,%d(%%rsp)", i); } } static void push_args2(Node *args, bool first_pass) { if (!args) return; push_args2(args->next, first_pass); - if ((first_pass && !args->pass_by_stack) || - (!first_pass && args->pass_by_stack)) + (!first_pass && args->pass_by_stack)) { return; - + } gen_expr(args); - switch (args->ty->kind) { case TY_STRUCT: case TY_UNION: @@ -466,13 +579,16 @@ static void push_args2(Node *args, bool first_pass) { break; case TY_FLOAT: case TY_DOUBLE: - pushf(); + pushf(args->ty); break; case TY_LDOUBLE: - println(" sub $16, %%rsp"); - println(" fstpt (%%rsp)"); + println("\tsub\t$16,%%rsp"); + println("\tfstpt\t(%%rsp)"); depth += 2; break; + case TY_INT128: + push2(); + break; default: push(); } @@ -499,31 +615,27 @@ static void push_args2(Node *args, bool first_pass) { // arguments to RAX. static int push_args(Node *node) { int stack = 0, gp = 0, fp = 0; - // If the return type is a large struct/union, the caller passes // a pointer to a buffer as if it were the first argument. if (node->ret_buffer && node->ty->size > 16) gp++; - // Load as many arguments to the registers as possible. for (Node *arg = node->args; arg; arg = arg->next) { Type *ty = arg->ty; - switch (ty->kind) { case TY_STRUCT: case TY_UNION: if (ty->size > 16) { arg->pass_by_stack = true; - stack += align_to(ty->size, 8) / 8; + stack += ROUNDUP(ty->size, 8) / 8; } else { bool fp1 = has_flonum1(ty); bool fp2 = has_flonum2(ty); - if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) { fp = fp + fp1 + fp2; gp = gp + !fp1 + !fp2; } else { arg->pass_by_stack = true; - stack += align_to(ty->size, 8) / 8; + stack += ROUNDUP(ty->size, 8) / 8; } } break; @@ -538,106 +650,115 @@ static int push_args(Node *node) { arg->pass_by_stack = true; stack += 2; break; + case TY_INT128: + gp++; + if (gp++ >= GP_MAX) { + arg->pass_by_stack = true; + stack++; + stack++; + } + break; default: if (gp++ >= GP_MAX) { arg->pass_by_stack = true; stack++; } + break; } } - if ((depth + stack) % 2 == 1) { - println(" sub $8, %%rsp"); + println("\tsub\t$8,%%rsp"); depth++; stack++; } - push_args2(node->args, true); push_args2(node->args, false); - // If the return type is a large struct/union, the caller passes // a pointer to a buffer as if it were the first argument. if (node->ret_buffer && node->ty->size > 16) { - println(" lea %d(%%rbp), %%rax", node->ret_buffer->offset); + println("\tlea\t%d(%%rbp),%%rax", node->ret_buffer->offset); push(); } - return stack; } static void copy_ret_buffer(Obj *var) { + /* todo(jart): wat */ Type *ty = var->ty; int gp = 0, fp = 0; - if (has_flonum1(ty)) { assert(ty->size == 4 || 8 <= ty->size); - if (ty->size == 4) - println(" movss %%xmm0, %d(%%rbp)", var->offset); - else - println(" movsd %%xmm0, %d(%%rbp)", var->offset); + if (ty->size == 4) { + println("\tmovss\t%%xmm0,%d(%%rbp)", var->offset); + } else { + println("\tmovsd\t%%xmm0,%d(%%rbp)", var->offset); + } fp++; } else { for (int i = 0; i < MIN(8, ty->size); i++) { - println(" mov %%al, %d(%%rbp)", var->offset + i); - println(" shr $8, %%rax"); + println("\tmov\t%%al,%d(%%rbp)", var->offset + i); + println("\tshr\t$8,%%rax"); } gp++; } - if (ty->size > 8) { if (has_flonum2(ty)) { assert(ty->size == 12 || ty->size == 16); - if (ty->size == 12) - println(" movss %%xmm%d, %d(%%rbp)", fp, var->offset + 8); - else - println(" movsd %%xmm%d, %d(%%rbp)", fp, var->offset + 8); + if (ty->size == 12) { + println("\tmovss\t%%xmm%d,%d(%%rbp)", fp, var->offset + 8); + } else { + println("\tmovsd\t%%xmm%d,%d(%%rbp)", fp, var->offset + 8); + } } else { char *reg1 = (gp == 0) ? "%al" : "%dl"; char *reg2 = (gp == 0) ? "%rax" : "%rdx"; for (int i = 8; i < MIN(16, ty->size); i++) { - println(" mov %s, %d(%%rbp)", reg1, var->offset + i); - println(" shr $8, %s", reg2); + println("\tmov\t%s,%d(%%rbp)", reg1, var->offset + i); + println("\tshr\t$8,%s", reg2); } } } } static void copy_struct_reg(void) { + /* todo(jart): wat */ Type *ty = current_fn->ty->return_ty; int gp = 0, fp = 0; - - println(" mov %%rax, %%rdi"); - + println("\tmov\t%%rax,%%rdi"); if (has_flonum(ty, 0, 8, 0)) { assert(ty->size == 4 || 8 <= ty->size); - if (ty->size == 4) - println(" movss (%%rdi), %%xmm0"); - else - println(" movsd (%%rdi), %%xmm0"); + if (ty->size == 4) { + println("\tmovss\t(%%rdi),%%xmm0"); + } else if (ty->size == 8) { + println("\tmovsd\t(%%rdi),%%xmm0"); + } else { + println("\tmovdqu\t(%%rdi),%%xmm0"); + } fp++; } else { - println(" mov $0, %%rax"); + println("\txor\t%%eax,%%eax"); for (int i = MIN(8, ty->size) - 1; i >= 0; i--) { - println(" shl $8, %%rax"); - println(" mov %d(%%rdi), %%al", i); + println("\tshl\t$8,%%rax"); + println("\tmov\t%d(%%rdi),%%al", i); } gp++; } - if (ty->size > 8) { if (has_flonum(ty, 8, 16, 0)) { assert(ty->size == 12 || ty->size == 16); - if (ty->size == 4) - println(" movss 8(%%rdi), %%xmm%d", fp); - else - println(" movsd 8(%%rdi), %%xmm%d", fp); + if (ty->size == 4) { + println("\tmovss\t8(%%rdi),%%xmm%d", fp); + } else { + println("\tmovsd\t8(%%rdi),%%xmm%d", fp); + } } else { char *reg1 = (gp == 0) ? "%al" : "%dl"; char *reg2 = (gp == 0) ? "%rax" : "%rdx"; - println(" mov $0, %s", reg2); + char *reg3 = (gp == 0) ? "%eax" : "%edx"; + println("\txor\t%s,%s", reg3, reg3); for (int i = MIN(16, ty->size) - 1; i >= 8; i--) { - println(" shl $8, %s", reg2); - println(" mov %d(%%rdi), %s", i, reg1); + println("\tshl\t$8,%s", reg2); + println("\tmov\t%d(%%rdi),%s", i, reg1); } } } @@ -646,47 +767,241 @@ static void copy_struct_reg(void) { static void copy_struct_mem(void) { Type *ty = current_fn->ty->return_ty; Obj *var = current_fn->params; - - println(" mov %d(%%rbp), %%rdi", var->offset); - + println("\tmov\t%d(%%rbp),%%rdi", var->offset); for (int i = 0; i < ty->size; i++) { - println(" mov %d(%%rax), %%dl", i); - println(" mov %%dl, %d(%%rdi)", i); + println("\tmov\t%d(%%rax),%%dl", i); + println("\tmov\t%%dl,%d(%%rdi)", i); } } static void builtin_alloca(void) { // Align size to 16 bytes. - println(" add $15, %%rdi"); - println(" and $0xfffffff0, %%edi"); - + println("\tadd\t$15,%%rdi"); + println("\tand\t$-16,%%rdi"); // Shift the temporary area by %rdi. - println(" mov %d(%%rbp), %%rcx", current_fn->alloca_bottom->offset); - println(" sub %%rsp, %%rcx"); - println(" mov %%rsp, %%rax"); - println(" sub %%rdi, %%rsp"); - println(" mov %%rsp, %%rdx"); - println("1:"); - println(" cmp $0, %%rcx"); - println(" je 2f"); - println(" mov (%%rax), %%r8b"); - println(" mov %%r8b, (%%rdx)"); - println(" inc %%rdx"); - println(" inc %%rax"); - println(" dec %%rcx"); - println(" jmp 1b"); - println("2:"); - + println("\tmov\t%d(%%rbp),%%rcx", current_fn->alloca_bottom->offset); + println("\ +\tsub\t%%rsp,%%rcx\n\ +\tmov\t%%rsp,%%rax\n\ +\tsub\t%%rdi,%%rsp\n\ +\tmov\t%%rsp,%%rdx\n\ +1:\n\ +\ttest\t%%rcx,%%rcx\n\ +\tje\t2f\n\ +\tmov\t(%%rax),%%r8b\n\ +\tmov\t%%r8b,(%%rdx)\n\ +\tinc\t%%rdx\n\ +\tinc\t%%rax\n\ +\tdec\t%%rcx\n\ +\tjmp\t1b\n\ +2:"); // Move alloca_bottom pointer. - println(" mov %d(%%rbp), %%rax", current_fn->alloca_bottom->offset); - println(" sub %%rdi, %%rax"); - println(" mov %%rax, %d(%%rbp)", current_fn->alloca_bottom->offset); + println("\tmov\t%d(%%rbp),%%rax", current_fn->alloca_bottom->offset); + println("\tsub\t%%rdi,%%rax"); + println("\tmov\t%%rax,%d(%%rbp)", current_fn->alloca_bottom->offset); +} + +static void gen_comis(Node *node, const char *op, int a, int b, + const char *pred) { + if (a != b) { + gen_expr(node->args->next); + pushf(node->args->next->ty); + gen_expr(node->args); + popf(node->args->next->ty, 1); + } else { + gen_expr(node->args); + } + println("\txor\t%%eax,%%eax"); + println("\t%s\t%%xmm%d,%%xmm%d", op, a, b); + println("\tset%s\t%%al", pred); +} + +static bool gen_builtin_funcall(Node *node, const char *name) { + if (!strcmp(name, "trap")) { + println("\tint3"); + return true; + } else if (!strcmp(name, "unreachable")) { + println("\tud2"); + return true; + } else if (!strcmp(name, "ctz")) { + gen_expr(node->args); + println("\tbsf\t%%eax,%%eax"); + return true; + } else if (!strcmp(name, "ctzl") || !strcmp(name, "ctzll")) { + gen_expr(node->args); + println("\tbsf\t%%rax,%%rax"); + return true; + } else if (!strcmp(name, "clz")) { + gen_expr(node->args); + println("\ +\tbsr\t%%eax,%%eax\n\ +\txor\t$31,%%eax"); + return true; + } else if (!strcmp(name, "clzl") || !strcmp(name, "clzll")) { + gen_expr(node->args); + println("\ +\tbsr\t%%rax,%%rax\n\ +\txor\t$63,%%eax"); + return true; + } else if (!strcmp(name, "ffs") || !strcmp(name, "ffsl") || + !strcmp(name, "ffsll")) { + char regprefix; + gen_expr(node->args); + println("\tor\t$-1,%%edi"); + regprefix = endswith(name, "l") ? 'r' : 'e'; + println("\tbsf\t%%%cax,%%%cax", regprefix, regprefix); + println("\tcmovz\t%%edi,%%eax"); + println("\tinc\t%%eax"); + return true; + } else if (!strcmp(name, "bswap16")) { + gen_expr(node->args); + println("\txchg\t%%al,%%ah"); + return true; + } else if (!strcmp(name, "bswap32")) { + gen_expr(node->args); + println("\tbswap\t%%eax"); + return true; + } else if (!strcmp(name, "bswap64")) { + gen_expr(node->args); + println("\tbswap\t%%rax"); + return true; + } else if (!strcmp(name, "popcount")) { + gen_expr(node->args); + if (opt_mpopcnt) { + println("\tpopcnt\t%%eax,%%eax"); + } else { + println("\tmov\t%%rax,%%rdi"); + println("\tcall\t__popcountsi2"); + } + return true; + } else if (!strcmp(name, "popcountl") || !strcmp(name, "popcountll")) { + gen_expr(node->args); + if (opt_mpopcnt) { + println("\tpopcnt\t%%rax,%%rax"); + } else { + println("\tmov\t%%rax,%%rdi"); + println("\tcall\t__popcountdi2"); + } + return true; + } else if (!strcmp(name, "memcpy")) { + if (is_const_expr(node->args->next->next)) { + gen_expr(node->args); + push(); + gen_expr(node->args->next); + println("\tmov\t(%%rsp),%%rdi"); + gen_memcpy(eval(node->args->next->next)); + pop("%rax"); + return true; + } + } else if (!strcmp(name, "isgreater")) { + gen_comis(node, "comisd", 1, 0, "a"); + return true; + } else if (!strcmp(name, "isgreaterequal")) { + gen_comis(node, "comisd", 1, 0, "ae"); + return true; + } else if (!strcmp(name, "isless")) { + gen_comis(node, "comisd", 0, 1, "a"); + return true; + } else if (!strcmp(name, "islessequal")) { + gen_comis(node, "comisd", 0, 1, "ae"); + return true; + } else if (!strcmp(name, "islessgreater")) { + gen_comis(node, "ucomisd", 1, 0, "ne"); + return true; + } else if (!strcmp(name, "isunordered")) { + gen_comis(node, "ucomisd", 1, 0, "p"); + return true; + } else if (!strcmp(name, "isnan")) { + gen_comis(node, "ucomisd", 0, 0, "p"); + return true; + } else if (!strcmp(name, "nanf")) { + println("\ +\tmov\t$0x7fc00000,%%eax\n\ +\tmovd\t%%eax,%%xmm0"); + return true; + } else if (!strcmp(name, "nan")) { + println("\ +\tmov\t$0x7fffffffffffffff,%%rax\n\ +\tmovq\t%%rax,%%xmm0"); + return true; + } else if (!strcmp(name, "nanl")) { + println("\ +\tpush\t$0x7fc00000\n\ +\tflds\t(%%rsp)\n\ +\tpop\t%%rax"); + return true; + } else if (!strcmp(name, "inff")) { + println("\ +\tmov\t$0x7f800000,%%eax\n\ +\tmovd\t%%eax,%%xmm0"); + return true; + } else if (!strcmp(name, "inf")) { + println("\ +\tmov\t$0x7ff0000000000000,%%rax\n\ +\tmovq\t%%rax,%%xmm0"); + return true; + } else if (!strcmp(name, "infl")) { + println("\ +\tpush\t$0x7f800000\n\ +\tflds\t(%%rsp)\n\ +\tpop\t%%rax"); + return true; + } else if (!strcmp(name, "isinf")) { + gen_expr(node->args); + println("\ +\tmov\t$0x7fffffffffffffff,%%rax\n\ +\tmovq\t%%rax,%%xmm1\n\ +\tandps\t%%xmm1,%%xmm0\n\ +\tmov\t$0x7fefffffffffffff,%%rax\n\ +\tmovq\t%%rax,%%xmm1\n\ +\txor\t%%eax,%%eax\n\ +\tcomisd\t%%xmm1,%%xmm0\n\ +\tseta\t%%al"); + return true; + } else if (!strcmp(name, "isfinite")) { + gen_expr(node->args); + println("\ +\tmov\t$0x7fffffffffffffff,%%rax\n\ +\tmovq\t%%rax,%%xmm1\n\ +\tandps\t%%xmm1,%%xmm0\n\ +\tmov\t$0x7fefffffffffffff,%%rax\n\ +\tmovq\t%%rax,%%xmm1\n\ +\txor\t%%eax,%%eax\n\ +\tcomisd\t%%xmm0,%%xmm1\n\ +\tsetnb\t%%al"); + return true; + } else if (!strcmp(name, "signbitf")) { + gen_expr(node->args); + println("\ +\tmovd\t%%xmm0,%%eax\n\ +\tand\t$0x80000000,%%eax"); + return true; + } else if (!strcmp(name, "signbit")) { + gen_expr(node->args); + println("\ +\tmovmskpd\t%%xmm0,%%eax\n\ +\tand\t$1,%%eax"); + return true; + } else if (!strcmp(name, "signbitl")) { + gen_expr(node->args); + println("\ +\tfxam\n\ +\tfnstsw\t%%ax\n\ +\tfstp\t%%st\n\ +\tand\t$0x200,%%eax"); + return true; +#if 0 + } else { + error_tok(node->lhs->var->tok, "invalid expression"); +#endif + } + return false; } // Generate code for a given node. -static void gen_expr(Node *node) { - println(" .loc %d %d", node->tok->file->file_no, node->tok->line_no); - +void gen_expr(Node *node) { + char fbuf[32]; + print_loc(node->tok->file->file_no, node->tok->line_no); switch (node->kind) { case ND_NULL_EXPR: return; @@ -697,8 +1012,9 @@ static void gen_expr(Node *node) { float f32; uint32_t u32; } u = {node->fval}; - println(" mov $%u, %%eax # float %Lf", u.u32, node->fval); - println(" movq %%rax, %%xmm0"); + g_ffmt_p(fbuf, &u.f32, 7, sizeof(fbuf), 0); + println("\tmov\t$%#x,%%eax\t# float %s", u.u32, fbuf); + println("\tmovq\t%%rax,%%xmm0"); return; } case TY_DOUBLE: { @@ -706,8 +1022,9 @@ static void gen_expr(Node *node) { double f64; uint64_t u64; } u = {node->fval}; - println(" mov $%lu, %%rax # double %Lf", u.u64, node->fval); - println(" movq %%rax, %%xmm0"); + g_dfmt_p(fbuf, &u.f64, 16, sizeof(fbuf), 0); + println("\tmov\t$%#lx,%%rax\t# double %s", u.u64, fbuf); + println("\tmovq\t%%rax,%%xmm0"); return; } case TY_LDOUBLE: { @@ -717,40 +1034,57 @@ static void gen_expr(Node *node) { } u; memset(&u, 0, sizeof(u)); u.f80 = node->fval; - println(" mov $%lu, %%rax # long double %Lf", u.u64[0], node->fval); - println(" mov %%rax, -16(%%rsp)"); - println(" mov $%lu, %%rax", u.u64[1]); - println(" mov %%rax, -8(%%rsp)"); - println(" fldt -16(%%rsp)"); + g_xfmt_p(fbuf, &u.f80, 19, sizeof(fbuf), 0); + println("\tmov\t$%lu,%%rax\t# long double %s", u.u64[0], fbuf); + println("\tmov\t%%rax,-16(%%rsp)"); + println("\tmov\t$%lu,%%rax", u.u64[1]); + println("\tmov\t%%rax,-8(%%rsp)"); + println("\tfldt\t-16(%%rsp)"); return; } + case TY_INT128: + print_mov_imm(node->val, "%rax", "%eax"); + if (node->ty->is_unsigned) { + println("\txor\t%%edx,%%edx"); + } else { + println("\tcqto"); + } + return; + default: + print_mov_imm(node->val, "%rax", "%eax"); + return; } - - println(" mov $%ld, %%rax", node->val); - return; } case ND_NEG: gen_expr(node->lhs); - switch (node->ty->kind) { case TY_FLOAT: - println(" mov $1, %%rax"); - println(" shl $31, %%rax"); - println(" movq %%rax, %%xmm1"); - println(" xorps %%xmm1, %%xmm0"); + println("\tmov\t$0x80000000,%%eax"); + println("\tmovq\t%%rax,%%xmm1"); + if (node->ty->vector_size == 16) { + println("\tpshufd\t$0,%%xmm1"); + } + println("\txorps\t%%xmm1,%%xmm0"); return; case TY_DOUBLE: - println(" mov $1, %%rax"); - println(" shl $63, %%rax"); - println(" movq %%rax, %%xmm1"); - println(" xorpd %%xmm1, %%xmm0"); + println("\tmov\t$1,%%eax"); + println("\tror\t%%rax"); + println("\tmovq\t%%rax,%%xmm1"); + if (node->ty->vector_size == 16) { + println("\tpshufd\t$0b01000100,%%xmm1"); + } + println("\txorpd\t%%xmm1,%%xmm0"); return; case TY_LDOUBLE: - println(" fchs"); + println("\tfchs"); + return; + case TY_INT128: + println("\tneg\t%%rax"); + println("\tadc\t$0,%%rdx"); + println("\tneg\t%%rdx"); return; } - - println(" neg %%rax"); + println("\tneg\t%%rax"); return; case ND_VAR: gen_addr(node); @@ -759,14 +1093,14 @@ static void gen_expr(Node *node) { case ND_MEMBER: { gen_addr(node); load(node->ty); - Member *mem = node->member; if (mem->is_bitfield) { - println(" shl $%d, %%rax", 64 - mem->bit_width - mem->bit_offset); - if (mem->ty->is_unsigned) - println(" shr $%d, %%rax", 64 - mem->bit_width); - else - println(" sar $%d, %%rax", 64 - mem->bit_width); + println("\tshl\t$%d,%%rax", 64 - mem->bit_width - mem->bit_offset); + if (mem->ty->is_unsigned) { + println("\tshr\t$%d,%%rax", 64 - mem->bit_width); + } else { + println("\tsar\t$%d,%%rax", 64 - mem->bit_width); + } } return; } @@ -781,29 +1115,24 @@ static void gen_expr(Node *node) { gen_addr(node->lhs); push(); gen_expr(node->rhs); - if (node->lhs->kind == ND_MEMBER && node->lhs->member->is_bitfield) { - println(" mov %%rax, %%r8"); - // If the lhs is a bitfield, we need to read the current value // from memory and merge it with a new value. + println("\tmov\t%%rax,%%r8"); Member *mem = node->lhs->member; - println(" mov %%rax, %%rdi"); - println(" and $%ld, %%rdi", (1L << mem->bit_width) - 1); - println(" shl $%d, %%rdi", mem->bit_offset); - - println(" mov (%%rsp), %%rax"); + println("\tmov\t%%rax,%%rdi"); + println("\tshl\t$%d,%%rdi", 64 - mem->bit_width); + println("\tshr\t$%d,%%rdi", 64 - mem->bit_width - mem->bit_offset); + println("\tmov\t(%%rsp),%%rax"); load(mem->ty); - - long mask = ((1L << mem->bit_width) - 1) << mem->bit_offset; - println(" mov $%ld, %%r9", ~mask); - println(" and %%r9, %%rax"); - println(" or %%rdi, %%rax"); + unsigned long mask = ((1ul << mem->bit_width) - 1) << mem->bit_offset; + println("\tmov\t$%#lx,%%r9", ~mask); + println("\tand\t%%r9,%%rax"); + println("\tor\t%%rdi,%%rax"); store(node->ty); - println(" mov %%r8, %%rax"); + println("\tmov\t%%r8,%%rax"); return; } - store(node->ty); return; case ND_STMT_EXPR: @@ -815,22 +1144,44 @@ static void gen_expr(Node *node) { return; case ND_CAST: gen_expr(node->lhs); - cast(node->lhs->ty, node->ty); + gen_cast(node->lhs->ty, node->ty); return; case ND_MEMZERO: - // `rep stosb` is equivalent to `memset(%rdi, %al, %rcx)`. - println(" mov $%d, %%rcx", node->var->ty->size); - println(" lea %d(%%rbp), %%rdi", node->var->offset); - println(" mov $0, %%al"); - println(" rep stosb"); + switch (node->var->ty->size) { + case 1: + println("\tmovb\t$0,%d(%%rbp)", node->var->offset); + break; + case 2: + println("\tmovw\t$0,%d(%%rbp)", node->var->offset); + break; + case 4: + println("\tmovl\t$0,%d(%%rbp)", node->var->offset); + break; + case 8: + println("\tmovq\t$0,%d(%%rbp)", node->var->offset); + break; + case 9 ... 16: + println("\txor\t%%eax,%%eax"); + println("\tmov\t%%rax,%d(%%rbp)", node->var->offset); + println("\tmov\t%%rax,%d(%%rbp)", + node->var->offset + 8 - (16 - node->var->ty->size)); + break; + default: + // `rep stosb` is equivalent to `memset(%rdi, %al, %rcx)`. + print_mov_imm(node->var->ty->size, "%rcx", "%ecx"); + println("\tlea\t%d(%%rbp),%%rdi", node->var->offset); + println("\txor\t%%eax,%%eax"); + println("\trep stosb"); + break; + } return; case ND_COND: { int c = count(); gen_expr(node->cond); cmp_zero(node->cond->ty); - println(" je .L.else.%d", c); + println("\tje\t.L.else.%d", c); gen_expr(node->then); - println(" jmp .L.end.%d", c); + println("\tjmp\t.L.end.%d", c); println(".L.else.%d:", c); gen_expr(node->els); println(".L.end.%d:", c); @@ -839,25 +1190,30 @@ static void gen_expr(Node *node) { case ND_NOT: gen_expr(node->lhs); cmp_zero(node->lhs->ty); - println(" sete %%al"); - println(" movzbl %%al, %%rax"); + println("\tsete\t%%al"); + println("\tmovzbl\t%%al,%%rax"); return; case ND_BITNOT: gen_expr(node->lhs); - println(" not %%rax"); + if (node->lhs->ty->kind == TY_INT128) { + println("\tnot\t%%rax"); + println("\tnot\t%%rdx"); + } else { + println("\tnot\t%%rax"); + } return; case ND_LOGAND: { int c = count(); gen_expr(node->lhs); cmp_zero(node->lhs->ty); - println(" je .L.false.%d", c); + println("\tje\t.L.false.%d", c); gen_expr(node->rhs); cmp_zero(node->rhs->ty); - println(" je .L.false.%d", c); - println(" mov $1, %%rax"); - println(" jmp .L.end.%d", c); + println("\tje\t.L.false.%d", c); + println("\tmov\t$1,%%eax"); + println("\tjmp\t.L.end.%d", c); println(".L.false.%d:", c); - println(" mov $0, %%rax"); + println("\txor\t%%eax,%%eax"); println(".L.end.%d:", c); return; } @@ -865,110 +1221,148 @@ static void gen_expr(Node *node) { int c = count(); gen_expr(node->lhs); cmp_zero(node->lhs->ty); - println(" jne .L.true.%d", c); + println("\tjne\t.L.true.%d", c); gen_expr(node->rhs); cmp_zero(node->rhs->ty); - println(" jne .L.true.%d", c); - println(" mov $0, %%rax"); - println(" jmp .L.end.%d", c); + println("\tjne\t.L.true.%d", c); + println("\txor\t%%eax,%%eax"); + println("\tjmp\t.L.end.%d", c); println(".L.true.%d:", c); - println(" mov $1, %%rax"); + println("\tmov\t$1,%%eax"); println(".L.end.%d:", c); return; } case ND_FUNCALL: { - if (node->lhs->kind == ND_VAR && - !strcmp(node->lhs->var->name, "alloca")) { - gen_expr(node->args); - println(" mov %%rax, %%rdi"); - builtin_alloca(); - return; + const char *funcname = NULL; + if (node->lhs->kind == ND_VAR) { + if (!strcmp(nameof(node->lhs->var), "alloca")) { + gen_expr(node->args); + println("\tmov\t%%rax,%%rdi"); + builtin_alloca(); + return; + } else if (startswith(nameof(node->lhs->var), "__builtin_")) { + funcname = nameof(node->lhs->var) + 10; + if (gen_builtin_funcall(node, funcname)) { + return; + } + } } - int stack_args = push_args(node); - gen_expr(node->lhs); - + if (!funcname) { + if (node->lhs->kind == ND_VAR && !node->lhs->var->is_local && + !node->lhs->var->is_tls && node->lhs->ty->kind == TY_FUNC) { + if (!opt_fpic || node->lhs->var->is_definition) { + funcname = nameof(node->lhs->var); + } else { + funcname = xasprintf("%s@gotpcrel(%%rip)", nameof(node->lhs->var)); + } + } else { + gen_expr(node->lhs); + funcname = NULL; + } + } int gp = 0, fp = 0; - // If the return type is a large struct/union, the caller passes // a pointer to a buffer as if it were the first argument. - if (node->ret_buffer && node->ty->size > 16) pop(argreg64[gp++]); - + if (node->ret_buffer && node->ty->size > 16) { + pop(argreg64[gp++]); + } for (Node *arg = node->args; arg; arg = arg->next) { Type *ty = arg->ty; - switch (ty->kind) { case TY_STRUCT: case TY_UNION: if (ty->size > 16) continue; - bool fp1 = has_flonum1(ty); bool fp2 = has_flonum2(ty); - if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) { if (fp1) - popf(fp++); + popf(ty, fp++); else pop(argreg64[gp++]); - if (ty->size > 8) { - if (fp2) - popf(fp++); - else + if (fp2) { + popf(ty, fp++); + } else { pop(argreg64[gp++]); + } } } break; case TY_FLOAT: case TY_DOUBLE: - if (fp < FP_MAX) popf(fp++); + if (fp < FP_MAX) popf(ty, fp++); break; case TY_LDOUBLE: break; + case TY_INT128: + if (gp + 1 < GP_MAX) { + int a = gp++; + int b = gp++; + pop2(argreg64[a], argreg64[b]); + } + break; default: - if (gp < GP_MAX) pop(argreg64[gp++]); + if (gp < GP_MAX) { + pop(argreg64[gp++]); + } + break; } } - - println(" mov %%rax, %%r10"); - println(" mov $%d, %%eax", fp); - println(" call *%%r10"); - println(" add $%d, %%rsp", stack_args * 8); - + if (funcname) { + if (node->lhs->ty->is_variadic) { + print_mov_imm(fp, "%rax", "%eax"); + } + println("\tcall\t%s", funcname); + } else { + if (!node->lhs->ty->is_variadic) { + println("\tcall\t*%%rax"); + } else { + println("\tmov\t%%rax,%%r10"); + print_mov_imm(fp, "%rax", "%eax"); + println("\tcall\t*%%r10"); + } + } + if (stack_args) { + println("\tadd\t$%d,%%rsp", stack_args * 8); + } depth -= stack_args; - // It looks like the most significant 48 or 56 bits in RAX may // contain garbage if a function return type is short or bool/char, // respectively. We clear the upper bits here. switch (node->ty->kind) { case TY_BOOL: - println(" movzbl %%al, %%eax"); + println("\tmovzbl\t%%al,%%eax"); return; case TY_CHAR: - if (node->ty->is_unsigned) - println(" movzbl %%al, %%eax"); - else - println(" movsbl %%al, %%eax"); + if (node->ty->is_unsigned) { + println("\tmovzbl\t%%al,%%eax"); + } else { + println("\tmovsbl\t%%al,%%eax"); + } return; case TY_SHORT: - if (node->ty->is_unsigned) - println(" movzwl %%ax, %%eax"); - else - println(" movswl %%ax, %%eax"); + if (node->ty->is_unsigned) { + println("\tmovzwl\t%%ax,%%eax"); + } else { + println("\tcwtl"); + } return; } - // If the return type is a small struct, a value is returned // using up to two registers. if (node->ret_buffer && node->ty->size <= 16) { copy_ret_buffer(node->ret_buffer); - println(" lea %d(%%rbp), %%rax", node->ret_buffer->offset); + println("\tlea\t%d(%%rbp),%%rax", node->ret_buffer->offset); } - return; } case ND_LABEL_VAL: - println(" lea %s(%%rip), %%rax", node->unique_label); + if (opt_fpic) { + println("\tlea\t%s(%%rip),%%rax", node->unique_label); + } else { + println("\tmov\t$%s,%%eax", node->unique_label); + } return; case ND_CAS: { gen_expr(node->cas_addr); @@ -976,18 +1370,17 @@ static void gen_expr(Node *node) { gen_expr(node->cas_new); push(); gen_expr(node->cas_old); - println(" mov %%rax, %%r8"); + println("\tmov\t%%rax,%%r8"); load(node->cas_old->ty->base); pop("%rdx"); // new pop("%rdi"); // addr - int sz = node->cas_addr->ty->base->size; - println(" lock cmpxchg %s, (%%rdi)", reg_dx(sz)); - println(" sete %%cl"); - println(" je 1f"); - println(" mov %s, (%%r8)", reg_ax(sz)); + println("\tlock cmpxchg %s,(%%rdi)", reg_dx(sz)); + println("\tsete\t%%cl"); + println("\tje\t1f"); + println("\tmov\t%s,(%%r8)", reg_ax(sz)); println("1:"); - println(" movzbl %%cl, %%eax"); + println("\tmovzbl\t%%cl,%%eax"); return; } case ND_EXCH: { @@ -995,111 +1388,120 @@ static void gen_expr(Node *node) { push(); gen_expr(node->rhs); pop("%rdi"); - int sz = node->lhs->ty->base->size; - println(" xchg %s, (%%rdi)", reg_ax(sz)); + println("\txchg\t%s,(%%rdi)", reg_ax(sz)); return; } + case ND_FPCLASSIFY: + gen_fpclassify(node->fpc); + return; } - switch (node->lhs->ty->kind) { case TY_FLOAT: case TY_DOUBLE: { gen_expr(node->rhs); - pushf(); + pushf(node->rhs->ty); gen_expr(node->lhs); - popf(1); - - char *sz = (node->lhs->ty->kind == TY_FLOAT) ? "ss" : "sd"; - + popf(node->rhs->ty, 1); + char sd = node->lhs->ty->kind == TY_FLOAT ? 's' : 'd'; + char ps = node->lhs->ty->vector_size == 16 ? 'p' : 's'; switch (node->kind) { case ND_ADD: - println(" add%s %%xmm1, %%xmm0", sz); + println("\tadd%c%c\t%%xmm1,%%xmm0", ps, sd); return; case ND_SUB: - println(" sub%s %%xmm1, %%xmm0", sz); + println("\tsub%c%c\t%%xmm1,%%xmm0", ps, sd); return; case ND_MUL: - println(" mul%s %%xmm1, %%xmm0", sz); + println("\tmul%c%c\t%%xmm1,%%xmm0", ps, sd); return; case ND_DIV: - println(" div%s %%xmm1, %%xmm0", sz); + println("\tdiv%c%c\t%%xmm1,%%xmm0", ps, sd); return; case ND_EQ: case ND_NE: case ND_LT: case ND_LE: - println(" ucomi%s %%xmm0, %%xmm1", sz); - + println("\tucomis%c\t%%xmm0,%%xmm1", sd); if (node->kind == ND_EQ) { - println(" sete %%al"); - println(" setnp %%dl"); - println(" and %%dl, %%al"); + println("\ +\tsete\t%%al\n\ +\tsetnp\t%%dl\n\ +\tand\t%%dl,%%al"); } else if (node->kind == ND_NE) { - println(" setne %%al"); - println(" setp %%dl"); - println(" or %%dl, %%al"); + println("\ +\tsetne\t%%al\n\ +\tsetp\t%%dl\n\ +\tor\t%%dl,%%al"); } else if (node->kind == ND_LT) { - println(" seta %%al"); + println("\tseta\t%%al"); } else { - println(" setae %%al"); + println("\tsetae\t%%al"); } - - println(" and $1, %%al"); - println(" movzb %%al, %%rax"); + println("\tand\t$1,%%al"); + println("\tmovzbl\t%%al,%%eax"); return; } - error_tok(node->tok, "invalid expression"); } case TY_LDOUBLE: { gen_expr(node->lhs); gen_expr(node->rhs); - switch (node->kind) { case ND_ADD: - println(" faddp"); + println("\tfaddp"); return; case ND_SUB: - println(" fsubrp"); + println("\tfsubrp"); return; case ND_MUL: - println(" fmulp"); + println("\tfmulp"); return; case ND_DIV: - println(" fdivrp"); + println("\tfdivrp"); return; case ND_EQ: case ND_NE: case ND_LT: case ND_LE: - println(" fcomip"); - println(" fstp %%st(0)"); - + println("\tfcomip"); + println("\tfstp\t%%st"); if (node->kind == ND_EQ) - println(" sete %%al"); + println("\tsete\t%%al"); else if (node->kind == ND_NE) - println(" setne %%al"); + println("\tsetne\t%%al"); else if (node->kind == ND_LT) - println(" seta %%al"); + println("\tseta\t%%al"); else - println(" setae %%al"); - - println(" movzb %%al, %%rax"); + println("\tsetae\t%%al"); + println("\tmovzbl\t%%al,%%eax"); return; } - error_tok(node->tok, "invalid expression"); } } - - gen_expr(node->rhs); - push(); - gen_expr(node->lhs); - pop("%rdi"); - + if (node->rhs->ty->kind == TY_INT128) { + gen_expr(node->rhs); + push2(); + gen_expr(node->lhs); + pop2("%rdi", "%rsi"); + } else if (!opt_fpic && is_const_expr(node->rhs)) { + /* shortcut path for immediates */ + char **label = NULL; + uint64_t val = eval2(node->rhs, &label); + gen_expr(node->lhs); + if (label) { + println("\tmov\t$%s%+ld,%%edi", *label, val); + } else { + print_mov_imm(val, "%rdi", "%edi"); + } + } else { + gen_expr(node->rhs); + push(); + gen_expr(node->lhs); + pop("%rdi"); + } char *ax, *di, *dx; - if (node->lhs->ty->kind == TY_LONG || node->lhs->ty->base) { ax = "%rax"; di = "%rdi"; @@ -1109,92 +1511,234 @@ static void gen_expr(Node *node) { di = "%edi"; dx = "%edx"; } - switch (node->kind) { case ND_ADD: - println(" add %s, %s", di, ax); + if (node->lhs->ty->kind == TY_INT128) { + println("\tadd\t%%rdi,%%rax"); + println("\tadc\t%%rsi,%%rdx"); + } else { + println("\tadd\t%s,%s", di, ax); + } return; case ND_SUB: - println(" sub %s, %s", di, ax); + if (node->lhs->ty->kind == TY_INT128) { + println("\tsub\t%%rdi,%%rax"); + println("\tsbb\t%%rsi,%%rdx"); + } else { + println("\tsub\t%s,%s", di, ax); + } return; case ND_MUL: - println(" imul %s, %s", di, ax); + if (node->lhs->ty->kind == TY_INT128) { + println("\ +\timul\t%%rdi,%%rdx\n\ +\timul\t%%rax,%%rsi\n\ +\tadd\t%%rdx,%%rsi\n\ +\tmul\t%%rdi\n\ +\tadd\t%%rsi,%%rdx"); + } else { + println("\timul\t%s,%s", di, ax); + } return; case ND_DIV: case ND_MOD: - if (node->ty->is_unsigned) { - println(" mov $0, %s", dx); - println(" div %s", di); + if (node->lhs->ty->kind == TY_INT128) { + bool skew; + if ((skew = (depth & 1))) { + println("\tsub\t$8,%%rsp"); + depth++; + } + println("\ +\tmov\t%%rsi,%%rcx\n\ +\tmov\t%%rdx,%%rsi\n\ +\tmov\t%%rdi,%%rdx\n\ +\tmov\t%%rax,%%rdi"); + if (node->kind == ND_DIV) { + if (node->ty->is_unsigned) { + println("\tcall\t__udivti3"); + } else { + println("\tcall\t__divti3"); + } + } else { + if (node->ty->is_unsigned) { + println("\tcall\t__umodti3"); + } else { + println("\tcall\t__modti3"); + } + } + if (skew) { + println("\tadd\t$8,%%rsp"); + depth--; + } } else { - if (node->lhs->ty->size == 8) - println(" cqo"); - else - println(" cdq"); - println(" idiv %s", di); + if (node->ty->is_unsigned) { + println("\txor\t%%edx,%%edx"); + println("\tdiv\t%s", di); + } else { + if (node->lhs->ty->size == 8) { + println("\tcqo"); + } else { + println("\tcdq"); + } + println("\tidiv\t%s", di); + } + if (node->kind == ND_MOD) { + println("\tmov\t%%rdx,%%rax"); + } } - - if (node->kind == ND_MOD) println(" mov %%rdx, %%rax"); return; case ND_BITAND: - println(" and %s, %s", di, ax); + if (node->lhs->ty->kind == TY_INT128) { + println("\tand\t%%rdi,%%rax"); + println("\tand\t%%rsi,%%rdx"); + } else { + println("\tand\t%s,%s", di, ax); + } return; case ND_BITOR: - println(" or %s, %s", di, ax); + if (node->lhs->ty->kind == TY_INT128) { + println("\tor\t%%rdi,%%rax"); + println("\tor\t%%rsi,%%rdx"); + } else { + println("\tor\t%s,%s", di, ax); + } return; case ND_BITXOR: - println(" xor %s, %s", di, ax); + if (node->lhs->ty->kind == TY_INT128) { + println("\txor\t%%rdi,%%rax"); + println("\txor\t%%rsi,%%rdx"); + } else { + println("\txor\t%s,%s", di, ax); + } return; case ND_EQ: case ND_NE: case ND_LT: case ND_LE: - println(" cmp %s, %s", di, ax); - - if (node->kind == ND_EQ) { - println(" sete %%al"); - } else if (node->kind == ND_NE) { - println(" setne %%al"); - } else if (node->kind == ND_LT) { - if (node->lhs->ty->is_unsigned) - println(" setb %%al"); - else - println(" setl %%al"); - } else if (node->kind == ND_LE) { - if (node->lhs->ty->is_unsigned) - println(" setbe %%al"); - else - println(" setle %%al"); + if (node->lhs->ty->kind == TY_INT128) { + switch (node->kind) { + case ND_EQ: + println("\ +\txor\t%%rax,%%rdi\n\ +\txor\t%%rdx,%%rsi\n\ +\tor\t%%rsi,%%rdi\n\ +\tsete\t%%al"); + break; + case ND_NE: + println("\ +\txor\t%%rax,%%rdi\n\ +\txor\t%%rdx,%%rsi\n\ +\tor\t%%rsi,%%rdi\n\ +\tsetne\t%%al"); + break; + case ND_LT: + if (node->lhs->ty->is_unsigned) { + println("\ +\tcmp\t%%rdi,%%rax\n\ +\tmov\t%%rdx,%%rax\n\ +\tsbb\t%%rsi,%%rax\n\ +\tsetc\t%%al"); + } else { + println("\ +\tcmp\t%%rdi,%%rax\n\ +\tmov\t%%rdx,%%rax\n\ +\tsbb\t%%rsi,%%rax\n\ +\tsetl\t%%al"); + } + break; + case ND_LE: + if (node->lhs->ty->is_unsigned) { + println("\ +\tcmp\t%%rax,%%rdi\n\ +\tsbb\t%%rdx,%%rsi\n\ +\tsetnc\t%%al"); + } else { + println("\ +\tcmp\t%%rax,%%rdi\n\ +\tsbb\t%%rdx,%%rsi\n\ +\tsetge\t%%al"); + } + break; + } + } else { + println("\tcmp\t%s,%s", di, ax); + if (node->kind == ND_EQ) { + println("\tsete\t%%al"); + } else if (node->kind == ND_NE) { + println("\tsetne\t%%al"); + } else if (node->kind == ND_LT) { + if (node->lhs->ty->is_unsigned) { + println("\tsetb\t%%al"); + } else { + println("\tsetl\t%%al"); + } + } else if (node->kind == ND_LE) { + if (node->lhs->ty->is_unsigned) { + println("\tsetbe\t%%al"); + } else { + println("\tsetle\t%%al"); + } + } } - - println(" movzb %%al, %%rax"); + println("\tmovzbl\t%%al,%%eax"); return; case ND_SHL: - println(" mov %%rdi, %%rcx"); - println(" shl %%cl, %s", ax); + println("\tmov\t%%edi,%%ecx"); + if (node->lhs->ty->kind == TY_INT128) { + println("\ +\tshld\t%%cl,%%rax,%%rdx\n\ +\tshl\t%%cl,%%rax\n\ +\txor\t%%edi,%%edi\n\ +\tand\t$64,%%cl\n\ +\tcmovne\t%%rax,%%rdx\n\ +\tcmovne\t%%rdi,%%rax"); + } else { + println("\tshl\t%%cl,%s", ax); + } return; case ND_SHR: - println(" mov %%rdi, %%rcx"); - if (node->lhs->ty->is_unsigned) - println(" shr %%cl, %s", ax); - else - println(" sar %%cl, %s", ax); + println("\tmov\t%%edi,%%ecx"); + if (node->lhs->ty->is_unsigned) { + if (node->lhs->ty->kind == TY_INT128) { + println("\ +\tshrd\t%%cl,%%rdx,%%rax\n\ +\tshr\t%%cl,%%rdx\n\ +\txor\t%%edi,%%edi\n\ +\tand\t$64,%%cl\n\ +\tcmovne\t%%rdx,%%rax\n\ +\tcmovne\t%%rdi,%%rdx"); + } else { + println("\tshr\t%%cl,%s", ax); + } + } else { + if (node->lhs->ty->kind == TY_INT128) { + println("\ +\tshrd\t%%cl,%%rdx,%%rax\n\ +\tsar\t%%cl,%%rdx\n\ +\tmov\t%%rdx,%%rdi\n\ +\tsar\t$63,%%rdi\n\ +\tand\t$64,%%cl\n\ +\tcmovne\t%%rdx,%%rax\n\ +\tcmovne\t%%rdi,%%rdx"); + } else { + println("\tsar\t%%cl,%s", ax); + } + } return; } - error_tok(node->tok, "invalid expression"); } -static void gen_stmt(Node *node) { - println(" .loc %d %d", node->tok->file->file_no, node->tok->line_no); - +void gen_stmt(Node *node) { + print_loc(node->tok->file->file_no, node->tok->line_no); switch (node->kind) { case ND_IF: { int c = count(); gen_expr(node->cond); cmp_zero(node->cond->ty); - println(" je .L.else.%d", c); + println("\tje\t.L.else.%d", c); gen_stmt(node->then); - println(" jmp .L.end.%d", c); + println("\tjmp\t.L.end.%d", c); println(".L.else.%d:", c); if (node->els) gen_stmt(node->els); println(".L.end.%d:", c); @@ -1207,12 +1751,12 @@ static void gen_stmt(Node *node) { if (node->cond) { gen_expr(node->cond); cmp_zero(node->cond->ty); - println(" je %s", node->brk_label); + println("\tje\t%s", node->brk_label); } gen_stmt(node->then); println("%s:", node->cont_label); if (node->inc) gen_expr(node->inc); - println(" jmp .L.begin.%d", c); + println("\tjmp\t.L.begin.%d", c); println("%s:", node->brk_label); return; } @@ -1223,33 +1767,30 @@ static void gen_stmt(Node *node) { println("%s:", node->cont_label); gen_expr(node->cond); cmp_zero(node->cond->ty); - println(" jne .L.begin.%d", c); + println("\tjne\t.L.begin.%d", c); println("%s:", node->brk_label); return; } - case ND_SWITCH: + case ND_SWITCH: // TODO(jart): 64-bit? gen_expr(node->cond); - for (Node *n = node->case_next; n; n = n->case_next) { char *ax = (node->cond->ty->size == 8) ? "%rax" : "%eax"; char *di = (node->cond->ty->size == 8) ? "%rdi" : "%edi"; - if (n->begin == n->end) { - println(" cmp $%ld, %s", n->begin, ax); - println(" je %s", n->label); + println("\tcmp\t$%ld,%s", n->begin, ax); + println("\tje\t%s", n->label); continue; } - // [GNU] Case ranges - println(" mov %s, %s", ax, di); - println(" sub $%ld, %s", n->begin, di); - println(" cmp $%ld, %s", n->end - n->begin, di); - println(" jbe %s", n->label); + println("\tmov\t%s,%s", ax, di); + println("\tsub\t$%ld,%s", n->begin, di); + println("\tcmp\t$%ld,%s", n->end - n->begin, di); + println("\tjbe\t%s", n->label); } - - if (node->default_case) println(" jmp %s", node->default_case->label); - - println(" jmp %s", node->brk_label); + if (node->default_case) { + println("\tjmp\t%s", node->default_case->label); + } + println("\tjmp\t%s", node->brk_label); gen_stmt(node->then); println("%s:", node->brk_label); return; @@ -1261,11 +1802,11 @@ static void gen_stmt(Node *node) { for (Node *n = node->body; n; n = n->next) gen_stmt(n); return; case ND_GOTO: - println(" jmp %s", node->unique_label); + println("\tjmp\t%s", node->unique_label); return; case ND_GOTO_EXPR: gen_expr(node->lhs); - println(" jmp *%%rax"); + println("\tjmp\t*%%rax"); return; case ND_LABEL: println("%s:", node->unique_label); @@ -1275,28 +1816,26 @@ static void gen_stmt(Node *node) { if (node->lhs) { gen_expr(node->lhs); Type *ty = node->lhs->ty; - switch (ty->kind) { case TY_STRUCT: case TY_UNION: - if (ty->size <= 16) + if (ty->size <= 16) { copy_struct_reg(); - else + } else { copy_struct_mem(); + } break; } } - - println(" jmp .L.return.%s", current_fn->name); + println("\tjmp\t.L.return.%s", nameof(current_fn)); return; case ND_EXPR_STMT: gen_expr(node->lhs); return; case ND_ASM: - println(" %s", node->asm_str); + gen_asm(node->azm); return; } - error_tok(node->tok, "invalid statement"); } @@ -1304,19 +1843,15 @@ static void gen_stmt(Node *node) { static void assign_lvar_offsets(Obj *prog) { for (Obj *fn = prog; fn; fn = fn->next) { if (!fn->is_function) continue; - // If a function has many parameters, some parameters are // inevitably passed by stack rather than by register. // The first passed-by-stack parameter resides at RBP+16. int top = 16; int bottom = 0; - int gp = 0, fp = 0; - // Assign offsets to pass-by-stack parameters. for (Obj *var = fn->params; var; var = var->next) { Type *ty = var->ty; - switch (ty->kind) { case TY_STRUCT: case TY_UNION: @@ -1336,19 +1871,19 @@ static void assign_lvar_offsets(Obj *prog) { break; case TY_LDOUBLE: break; + case TY_INT128: + gp++; + if (gp++ < GP_MAX) continue; default: if (gp++ < GP_MAX) continue; } - - top = align_to(top, 8); + top = ROUNDUP(top, 8); var->offset = top; top += var->ty->size; } - // Assign offsets to pass-by-register parameters and local variables. for (Obj *var = fn->locals; var; var = var->next) { if (var->offset) continue; - // AMD64 System V ABI has a special alignment rule for an array of // length at least 16 bytes. We need to align such array to at least // 16-byte boundaries. See p.14 of @@ -1356,80 +1891,77 @@ static void assign_lvar_offsets(Obj *prog) { int align = (var->ty->kind == TY_ARRAY && var->ty->size >= 16) ? MAX(16, var->align) : var->align; - bottom += var->ty->size; - bottom = align_to(bottom, align); + bottom = ROUNDUP(bottom, align); var->offset = -bottom; } - - fn->stack_size = align_to(bottom, 16); + fn->stack_size = ROUNDUP(bottom, 16); } } static void emit_data(Obj *prog) { for (Obj *var = prog; var; var = var->next) { if (var->is_function || !var->is_definition) continue; - - if (var->is_static) - println(" .local %s", var->name); - else - println(" .globl %s", var->name); - + flushln(); + fputc('\n', output_stream); + print_visibility(var); int align = (var->ty->kind == TY_ARRAY && var->ty->size >= 16) ? MAX(16, var->align) : var->align; - - // Common symbol if (opt_fcommon && var->is_tentative && !var->is_tls) { - println(" .comm %s, %d, %d", var->name, var->ty->size, align); - continue; - } - - // .data or .tdata - if (var->init_data) { - if (var->is_tls) - println(" .section .tdata,\"awT\",@progbits"); - else - println(" .data"); - - println(" .type %s, @object", var->name); - println(" .size %s, %d", var->name, var->ty->size); - println(" .align %d", align); - println("%s:", var->name); - - Relocation *rel = var->rel; - int pos = 0; - while (pos < var->ty->size) { - if (rel && rel->offset == pos) { - println(" .quad %s%+ld", *rel->label, rel->addend); - rel = rel->next; - pos += 8; - } else { - println(" .byte %d", var->init_data[pos++]); - } + println("\t.comm\t%s,%d,%d", nameof(var), var->ty->size, align); + } else { + if (var->section) { + println("\t.section %s", var->section); + } else if (var->is_tls) { + println("\t.section .t%s,\"awT\",@%s", + var->init_data ? "progbits" : "nobits", + var->init_data ? "data" : "bss"); +#if 0 /* TODO: unflag if assigned to array */ + } else if (align <= 1 && var->is_string_literal) { + println("\t.section .rodata.str1.1,\"aSM\",@progbits,1"); +#endif + } else { + println("\t.%s", var->init_data ? "data" : "bss"); + } + print_align(align); + println("\t.type\t%s,@object", nameof(var)); + println("\t.size\t%s,%d", nameof(var), var->ty->size); + println("%s:", nameof(var)); + if (var->init_data) { + int pos = 0; + Relocation *rel = var->rel; + if (!rel && is_quotable_string(var->init_data, var->ty->size)) { + println("\t.asciz\t\"%s\"", var->init_data); + } else { + while (pos < var->ty->size) { + if (rel && rel->offset == pos) { + assert(pos + 8 <= var->ty->size); + println("\t.quad\t%s%+ld", *rel->label, rel->addend); + rel = rel->next; + pos += 8; + } else { + println("\t.byte\t%d", var->init_data[pos++]); + } + } + } + } else { + println("\t.zero\t%d", var->ty->size); } - continue; } - - // .bss or .tbss - if (var->is_tls) - println(" .section .tbss,\"awT\",@nobits"); - else - println(" .bss"); - - println(" .align %d", align); - println("%s:", var->name); - println(" .zero %d", var->ty->size); } } static void store_fp(int r, int offset, int sz) { switch (sz) { case 4: - println(" movss %%xmm%d, %d(%%rbp)", r, offset); + println("\tmovss\t%%xmm%d,%d(%%rbp)", r, offset); return; case 8: - println(" movsd %%xmm%d, %d(%%rbp)", r, offset); + println("\tmovsd\t%%xmm%d,%d(%%rbp)", r, offset); + return; + case 16: + println("\tmovaps\t%%xmm%d,%d(%%rbp)", r, offset); return; } UNREACHABLE(); @@ -1438,21 +1970,21 @@ static void store_fp(int r, int offset, int sz) { static void store_gp(int r, int offset, int sz) { switch (sz) { case 1: - println(" mov %s, %d(%%rbp)", argreg8[r], offset); + println("\tmov\t%s,%d(%%rbp)", argreg8[r], offset); return; case 2: - println(" mov %s, %d(%%rbp)", argreg16[r], offset); + println("\tmov\t%s,%d(%%rbp)", argreg16[r], offset); return; case 4: - println(" mov %s, %d(%%rbp)", argreg32[r], offset); + println("\tmov\t%s,%d(%%rbp)", argreg32[r], offset); return; case 8: - println(" mov %s, %d(%%rbp)", argreg64[r], offset); + println("\tmov\t%s,%d(%%rbp)", argreg64[r], offset); return; default: for (int i = 0; i < sz; i++) { - println(" mov %s, %d(%%rbp)", argreg8[r], offset + i); - println(" shr $8, %s", argreg64[r]); + println("\tmov\t%s,%d(%%rbp)", argreg8[r], offset + i); + println("\tshr\t$8,%s", argreg64[r]); } return; } @@ -1461,130 +1993,148 @@ static void store_gp(int r, int offset, int sz) { static void emit_text(Obj *prog) { for (Obj *fn = prog; fn; fn = fn->next) { if (!fn->is_function || !fn->is_definition) continue; - // No code is emitted for "static inline" functions // if no one is referencing them. if (!fn->is_live) continue; - - if (fn->is_static) - println(" .local %s", fn->name); - else - println(" .globl %s", fn->name); - - println(" .text"); - println(" .type %s, @function", fn->name); - println("%s:", fn->name); + flushln(); + fputc('\n', output_stream); + if (fn->section) { + println("\t.section %s", fn->section); + } else { + println("\t.text"); + } + print_visibility(fn); + print_align(fn->align); + println("\t.type\t%s,@function", nameof(fn)); + println("%s:", nameof(fn)); current_fn = fn; - // Prologue - println(" push %%rbp"); - println(" mov %%rsp, %%rbp"); - println(" sub $%d, %%rsp", fn->stack_size); - println(" mov %%rsp, %d(%%rbp)", fn->alloca_bottom->offset); - + println("\tpush\t%%rbp"); + println("\tmov\t%%rsp,%%rbp"); + if (opt_mnop_mcount) { + println("\tnopw\t0(%%rax,%%rax,1)"); + } else if (opt_mrecord_mcount) { + println("\tcall\tmcount@gotpcrel(%%rip)"); + } else if (opt_mfentry) { + println("\tcall\t__fentry__@gotpcrel(%%rip)"); + } + println("\tsub\t$%d,%%rsp", fn->stack_size); + println("\tmov\t%%rsp,%d(%%rbp)", fn->alloca_bottom->offset); // Save arg registers if function is variadic if (fn->va_area) { int gp = 0, fp = 0; for (Obj *var = fn->params; var; var = var->next) { - if (is_flonum(var->ty)) + if (is_flonum(var->ty)) { fp++; - else + } else { gp++; + } } - int off = fn->va_area->offset; - // va_elem - println(" movl $%d, %d(%%rbp)", gp * 8, off); // gp_offset - println(" movl $%d, %d(%%rbp)", fp * 8 + 48, off + 4); // fp_offset - println(" movq %%rbp, %d(%%rbp)", off + 8); // overflow_arg_area - println(" addq $16, %d(%%rbp)", off + 8); - println(" movq %%rbp, %d(%%rbp)", off + 16); // reg_save_area - println(" addq $%d, %d(%%rbp)", off + 24, off + 16); - + println("\tmovl\t$%d,%d(%%rbp)", gp * 8, off); // gp_offset + println("\tmovl\t$%d,%d(%%rbp)", fp * 8 + 48, off + 4); // fp_offset + println("\tmov\t%%rbp,%d(%%rbp)", off + 8); // overflow_arg_area + println("\taddq\t$16,%d(%%rbp)", off + 8); + println("\tmov\t%%rbp,%d(%%rbp)", off + 16); // reg_save_area + println("\taddq\t$%d,%d(%%rbp)", off + 24, off + 16); // __reg_save_area__ - println(" movq %%rdi, %d(%%rbp)", off + 24); - println(" movq %%rsi, %d(%%rbp)", off + 32); - println(" movq %%rdx, %d(%%rbp)", off + 40); - println(" movq %%rcx, %d(%%rbp)", off + 48); - println(" movq %%r8, %d(%%rbp)", off + 56); - println(" movq %%r9, %d(%%rbp)", off + 64); - println(" movsd %%xmm0, %d(%%rbp)", off + 72); - println(" movsd %%xmm1, %d(%%rbp)", off + 80); - println(" movsd %%xmm2, %d(%%rbp)", off + 88); - println(" movsd %%xmm3, %d(%%rbp)", off + 96); - println(" movsd %%xmm4, %d(%%rbp)", off + 104); - println(" movsd %%xmm5, %d(%%rbp)", off + 112); - println(" movsd %%xmm6, %d(%%rbp)", off + 120); - println(" movsd %%xmm7, %d(%%rbp)", off + 128); + println("\tmov\t%%rdi,%d(%%rbp)", off + 24); + println("\tmov\t%%rsi,%d(%%rbp)", off + 32); + println("\tmov\t%%rdx,%d(%%rbp)", off + 40); + println("\tmov\t%%rcx,%d(%%rbp)", off + 48); + println("\tmov\t%%r8,%d(%%rbp)", off + 56); + println("\tmov\t%%r9,%d(%%rbp)", off + 64); + println("\tmovsd\t%%xmm0,%d(%%rbp)", off + 72); + println("\tmovsd\t%%xmm1,%d(%%rbp)", off + 80); + println("\tmovsd\t%%xmm2,%d(%%rbp)", off + 88); + println("\tmovsd\t%%xmm3,%d(%%rbp)", off + 96); + println("\tmovsd\t%%xmm4,%d(%%rbp)", off + 104); + println("\tmovsd\t%%xmm5,%d(%%rbp)", off + 112); + println("\tmovsd\t%%xmm6,%d(%%rbp)", off + 120); + println("\tmovsd\t%%xmm7,%d(%%rbp)", off + 128); } - // Save passed-by-register arguments to the stack int gp = 0, fp = 0; for (Obj *var = fn->params; var; var = var->next) { if (var->offset > 0) continue; - Type *ty = var->ty; - switch (ty->kind) { case TY_STRUCT: case TY_UNION: assert(ty->size <= 16); - if (has_flonum(ty, 0, 8, 0)) + if (has_flonum(ty, 0, 8, 0)) { store_fp(fp++, var->offset, MIN(8, ty->size)); - else + } else { store_gp(gp++, var->offset, MIN(8, ty->size)); - + } if (ty->size > 8) { - if (has_flonum(ty, 8, 16, 0)) + if (has_flonum(ty, 8, 16, 0)) { store_fp(fp++, var->offset + 8, ty->size - 8); - else + } else { store_gp(gp++, var->offset + 8, ty->size - 8); + } } break; case TY_FLOAT: case TY_DOUBLE: store_fp(fp++, var->offset, ty->size); break; + case TY_INT128: + store_gp(gp++, var->offset + 0, 8); + store_gp(gp++, var->offset + 8, 8); + break; default: store_gp(gp++, var->offset, ty->size); } } - // Emit code gen_stmt(fn->body); - assert(depth == 0); - + assert(!depth); // The C spec defines a special rule for the main function. // Reaching the end of the main function is equivalent to // returning 0, even though the behavior is undefined for the // other functions. See C11 5.1.2.2.3. - if (strcmp(fn->name, "main") == 0) println(" mov $0, %%rax"); - + if (strcmp(nameof(fn), "main") == 0) { + println("\txor\t%%eax,%%eax"); + } // Epilogue - println(".L.return.%s:", fn->name); - println(" mov %%rbp, %%rsp"); - println(" pop %%rbp"); - println(" ret"); + println(".L.return.%s:", nameof(fn)); + if (fn->is_noreturn) { + println("\tud2"); + } else { + println("\tleave"); + println("\tret"); + } + println("\t.size\t%s,.-%s", nameof(fn), nameof(fn)); + if (fn->is_constructor) { + println("\t.section .ctors,\"aw\",@progbits"); + println("\t.align\t8"); + println("\t.quad\t%s", nameof(fn)); + } + if (fn->is_destructor) { + println("\t.section .dtors,\"aw\",@progbits"); + println("\t.align\t8"); + println("\t.quad\t%s", nameof(fn)); + } } } static void emit_staticasms(StaticAsm *a) { if (!a) return; emit_staticasms(a->next); - println(" .loc %d %d", a->body->tok->file->file_no, a->body->tok->line_no); - println(" %s", a->body->asm_str); + gen_asm(a->body); } void codegen(Obj *prog, FILE *out) { - output_file = out; - + output_stream = out; File **files = get_input_files(); - for (int i = 0; files[i]; i++) - println(" .file %d \"%s\"", files[i]->file_no, files[i]->name); - + for (int i = 0; files[i]; i++) { + println("\t.file\t%d %`'s", files[i]->file_no, files[i]->name); + } assign_lvar_offsets(prog); emit_staticasms(staticasms); emit_data(prog); emit_text(prog); + flushln(); } diff --git a/third_party/chibicc/fpclassify.c b/third_party/chibicc/fpclassify.c new file mode 100644 index 00000000..6f013925 --- /dev/null +++ b/third_party/chibicc/fpclassify.c @@ -0,0 +1,145 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or 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. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/chibicc/chibicc.h" + +/** + * @fileoverview __builtin_fpclassify() implementation + */ + +#define FPCLASSIFY_FLOAT \ + "\tmovaps\t%%xmm0,%%xmm1\n\ +\tmov\t$0x7fffffff,%%eax\n\ +\tmovd\t%%eax,%%xmm2\n\ +\tandps\t%%xmm2,%%xmm1\n\ +\tmov\t$%d,%%eax\n\ +\tucomiss\t%%xmm1,%%xmm1\n\ +\tjp\t9f\n\ +\tmov\t$0x7f7fffff,%%edi\n\ +\tmovd\t%%edi,%%xmm2\n\ +\tucomiss\t%%xmm2,%%xmm1\n\ +\tja\t2f\n\ +\tmov\t$0x00800000,%%edi\n\ +\tmovd\t%%edi,%%xmm2\n\ +\tucomiss\t%%xmm2,%%xmm1\n\ +\tjnb\t3f\n\ +\txorps\t%%xmm1,%%xmm1\n\ +\tucomiss\t%%xmm1,%%xmm0\n\ +\tjp\t1f\n\ +\tmovl\t$%d,%%eax\n\ +\tje\t9f\n\ +1:\tmovl\t$%d,%%eax\n\ +\tjmp\t9f\n\ +2:\tmovl\t$%d,%%eax\n\ +\tjmp\t9f\n\ +3:\tmovl\t$%d,%%eax\n\ +9:" + +#define FPCLASSIFY_DOUBLE \ + "\tmovapd\t%%xmm0,%%xmm1\n\ +\tmov\t$0x7fffffffffffffff,%%rax\n\ +\tmovq\t%%rax,%%xmm2\n\ +\tandps\t%%xmm2,%%xmm1\n\ +\tmov\t$%d,%%eax\n\ +\tucomisd\t%%xmm1,%%xmm1\n\ +\tjp\t9f\n\ +\tmov\t$0x7fefffffffffffff,%%rdi\n\ +\tmovq\t%%rdi,%%xmm2\n\ +\tucomisd\t%%xmm2,%%xmm1\n\ +\tja\t2f\n\ +\tmov\t$0x0010000000000000,%%rdi\n\ +\tmovq\t%%rdi,%%xmm2\n\ +\tucomisd\t%%xmm2,%%xmm1\n\ +\tjnb\t3f\n\ +\txorps\t%%xmm1,%%xmm1\n\ +\tucomisd\t%%xmm1,%%xmm0\n\ +\tjp\t1f\n\ +\tmovl\t$%d,%%eax\n\ +\tje\t9f\n\ +1:\tmovl\t$%d,%%eax\n\ +\tjmp\t9f\n\ +2:\tmovl\t$%d,%%eax\n\ +\tjmp\t9f\n\ +3:\tmovl\t$%d,%%eax\n\ +9:" + +#define FPCLASSIFY_LDOUBLE \ + "\tmov\t$%d,%%eax\n\ +\tfld\t%%st\n\ +\tfabs\n\ +\tfucomi\t%%st,%%st\n\ +\tjp\t6f\n\ +\tpush\t$0x7ffe\n\ +\tpush\t$-1\n\ +\tfldt\t(%%rsp)\n\ +\tadd\t$16,%%rsp\n\ +\tfxch\n\ +\tmov\t$%d,%%eax\n\ +\tfucomi\n\ +\tfstp\t%%st(1)\n\ +\tja\t7f\n\ +\tmov\t$1,%%edi\n\ +\tpush\t%%rdi\n\ +\tror\t%%rdi\n\ +\tpush\t%%rdi\n\ +\tfldt\t(%%rsp)\n\ +\tadd\t$16,%%rsp\n\ +\tfxch\n\ +\tmov\t$%d,%%eax\n\ +\tfucomip\n\ +\tfstp\t%%st\n\ +\tjnb\t8f\n\ +\tfldz\n\ +\tfxch\n\ +\tfucomip\n\ +\tfstp\t%%st\n\ +\tjp\t5f\n\ +\tmov\t$%d,%%eax\n\ +\tje\t9f\n\ +5:\tmov\t$%d,%%eax\n\ +\tjmp\t9f\n\ +6:\tfstp\t%%st\n\ +\tfstp\t%%st\n\ +\tjmp\t9f\n\ +7:\tfstp\t%%st\n\ +\tfstp\t%%st\n\ +\tjmp\t9f\n\ +8:\tfstp\t%%st\n\ +9:" + +void gen_fpclassify(FpClassify *fpc) { + int fpnan = fpc->args[0]; + int fpinf = fpc->args[1]; + int fpnorm = fpc->args[2]; + int fpsubnorm = fpc->args[3]; + int fpzero = fpc->args[4]; + gen_expr(fpc->node); + switch (fpc->node->ty->kind) { + case TY_FLOAT: + println(FPCLASSIFY_FLOAT, fpnan, fpzero, fpsubnorm, fpinf, fpnorm); + break; + case TY_DOUBLE: + println(FPCLASSIFY_DOUBLE, fpnan, fpzero, fpsubnorm, fpinf, fpnorm); + break; + case TY_LDOUBLE: + println(FPCLASSIFY_LDOUBLE, fpnan, fpinf, fpnorm, fpzero, fpsubnorm); + break; + default: + UNREACHABLE(); + } +} diff --git a/third_party/chibicc/hashmap.c b/third_party/chibicc/hashmap.c index 5d05af9c..a4ddad97 100644 --- a/third_party/chibicc/hashmap.c +++ b/third_party/chibicc/hashmap.c @@ -20,7 +20,7 @@ static void rehash(HashMap *map) { int nkeys = 0; for (int i = 0; i < map->capacity; i++) if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) nkeys++; - int cap = map->capacity; + size_t cap = map->capacity; while ((nkeys * 100) / cap >= 50) cap = cap * 2; // Create a new hashmap and copy all key-values. HashMap map2 = {}; @@ -44,7 +44,7 @@ static HashEntry *get_entry(HashMap *map, char *key, int keylen) { if (!map->buckets) return NULL; uint64_t hash = fnv_hash(key, keylen); for (int i = 0; i < map->capacity; i++) { - HashEntry *ent = &map->buckets[(hash + i) % map->capacity]; + HashEntry *ent = &map->buckets[(hash + i) & (map->capacity - 1)]; if (match(ent, key, keylen)) return ent; if (ent->key == NULL) return NULL; } @@ -58,7 +58,7 @@ static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) { if ((map->used * 100) / map->capacity >= 70) rehash(map); uint64_t hash = fnv_hash(key, keylen); for (int i = 0; i < map->capacity; i++) { - HashEntry *ent = &map->buckets[(hash + i) % map->capacity]; + HashEntry *ent = &map->buckets[(hash + i) & (map->capacity - 1)]; if (match(ent, key, keylen)) return ent; if (ent->key == TOMBSTONE) { ent->key = key; @@ -102,29 +102,31 @@ void hashmap_delete2(HashMap *map, char *key, int keylen) { if (ent) ent->key = TOMBSTONE; } +#if 0 void hashmap_test(void) { HashMap *map = calloc(1, sizeof(HashMap)); for (int i = 0; i < 5000; i++) - hashmap_put(map, format("key %d", i), (void *)(size_t)i); - for (int i = 1000; i < 2000; i++) hashmap_delete(map, format("key %d", i)); + hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i); + for (int i = 1000; i < 2000; i++) hashmap_delete(map, xasprintf("key %d", i)); for (int i = 1500; i < 1600; i++) - hashmap_put(map, format("key %d", i), (void *)(size_t)i); + hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i); for (int i = 6000; i < 7000; i++) - hashmap_put(map, format("key %d", i), (void *)(size_t)i); + hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i); for (int i = 0; i < 1000; i++) - assert((size_t)hashmap_get(map, format("key %d", i)) == i); + assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i); for (int i = 1000; i < 1500; i++) assert(hashmap_get(map, "no such key") == NULL); for (int i = 1500; i < 1600; i++) - assert((size_t)hashmap_get(map, format("key %d", i)) == i); + assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i); for (int i = 1600; i < 2000; i++) assert(hashmap_get(map, "no such key") == NULL); for (int i = 2000; i < 5000; i++) - assert((size_t)hashmap_get(map, format("key %d", i)) == i); + assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i); for (int i = 5000; i < 6000; i++) assert(hashmap_get(map, "no such key") == NULL); for (int i = 6000; i < 7000; i++) - hashmap_put(map, format("key %d", i), (void *)(size_t)i); + hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i); assert(hashmap_get(map, "no such key") == NULL); printf("OK\n"); } +#endif diff --git a/third_party/chibicc/parse.c b/third_party/chibicc/parse.c index 6d394908..8c912efb 100644 --- a/third_party/chibicc/parse.c +++ b/third_party/chibicc/parse.c @@ -18,12 +18,15 @@ #include "third_party/chibicc/chibicc.h" +typedef struct InitDesg InitDesg; +typedef struct Initializer Initializer; +typedef struct Scope Scope; + // Scope for local variables, global variables, typedefs // or enum constants typedef struct { char *name; int depth; - Obj *var; Type *type_def; Type *enum_ty; @@ -37,10 +40,8 @@ typedef struct { Type *ty; } TagScope; -typedef struct Scope Scope; struct Scope { Scope *next; - // C has two block scopes; one is for variables/typedefs and // the other is for struct/union/enum tags. HashMap vars; @@ -53,35 +54,39 @@ typedef struct { bool is_static; bool is_extern; bool is_inline; + bool is_const; bool is_tls; + bool is_weak; + bool is_aligned; + bool is_noreturn; + bool is_destructor; + bool is_constructor; + bool is_externally_visible; int align; + char *section; + char *visibility; } VarAttr; // This struct represents a variable initializer. Since initializers // can be nested (e.g. `int x[2][2] = {{1, 2}, {3, 4}}`), this struct // is a tree data structure. -typedef struct Initializer Initializer; struct Initializer { Initializer *next; Type *ty; Token *tok; bool is_flexible; - // If it's not an aggregate type and has an initializer, // `expr` has an initialization expression. Node *expr; - // If it's an initializer for an aggregate type (e.g. array or struct), // `children` has initializers for its children. Initializer **children; - // Only one member can be initialized for a union. // `mem` is used to clarify which member is initialized. Member *mem; }; // For local variable initializer. -typedef struct InitDesg InitDesg; struct InitDesg { InitDesg *next; int idx; @@ -119,64 +124,50 @@ static Node *current_switch; static Obj *builtin_alloca; -struct StaticAsm *staticasms; - -static bool is_typename(Token *tok); -static Type *typespec(Token **rest, Token *tok, VarAttr *attr); -static Type *typename(Token **rest, Token *tok); -static Type *enum_specifier(Token **rest, Token *tok); -static Type *typeof_specifier(Token **rest, Token *tok); -static Type *type_suffix(Token **rest, Token *tok, Type *ty); -static Type *declarator(Token **rest, Token *tok, Type *ty); -static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr); -static void array_initializer2(Token **rest, Token *tok, Initializer *init, - int i); -static void struct_initializer2(Token **rest, Token *tok, Initializer *init, - Member *mem); -static void initializer2(Token **rest, Token *tok, Initializer *init); -static Initializer *initializer(Token **rest, Token *tok, Type *ty, - Type **new_ty); -static Node *lvar_initializer(Token **rest, Token *tok, Obj *var); -static void gvar_initializer(Token **rest, Token *tok, Obj *var); -static Node *compound_stmt(Token **rest, Token *tok); -static Node *stmt(Token **rest, Token *tok); -static Node *expr_stmt(Token **rest, Token *tok); -static Node *expr(Token **rest, Token *tok); -static int64_t eval(Node *node); -static int64_t eval2(Node *node, char ***label); -static int64_t eval_rval(Node *node, char ***label); -static bool is_const_expr(Node *node); -static Node *assign(Token **rest, Token *tok); -static Node *logor(Token **rest, Token *tok); -static double eval_double(Node *node); -static Node *conditional(Token **rest, Token *tok); -static Node *logand(Token **rest, Token *tok); -static Node * bitor (Token * *rest, Token *tok); -static Node *bitxor(Token **rest, Token *tok); -static Node *bitand(Token **rest, Token *tok); -static Node *equality(Token **rest, Token *tok); -static Node *relational(Token **rest, Token *tok); -static Node *shift(Token **rest, Token *tok); -static Node *add(Token **rest, Token *tok); -static Node *new_add(Node *lhs, Node *rhs, Token *tok); -static Node *new_sub(Node *lhs, Node *rhs, Token *tok); -static Node *mul(Token **rest, Token *tok); -static Node *cast(Token **rest, Token *tok); -static Member *get_struct_member(Type *ty, Token *tok); -static Type *struct_decl(Token **rest, Token *tok); -static Type *union_decl(Token **rest, Token *tok); -static Node *postfix(Token **rest, Token *tok); -static Node *funcall(Token **rest, Token *tok, Node *node); -static Node *unary(Token **rest, Token *tok); -static Node *primary(Token **rest, Token *tok); -static Token *parse_typedef(Token *tok, Type *basety); -static bool is_function(Token *tok); -static Token *function(Token *tok, Type *basety, VarAttr *attr); -static Token *global_variable(Token *tok, Type *basety, VarAttr *attr); - -static int align_down(int n, int align) { - return align_to(n - align + 1, align); -} +static Initializer *initializer(Token **, Token *, Type *, Type **); +static Member *get_struct_member(Type *, Token *); +static Node * bitor (Token **, Token *); +static Node *add(Token **, Token *); +static Node *assign(Token **, Token *); +static Node *bitand(Token **, Token *); +static Node *bitxor(Token **, Token *); +static Node *cast(Token **, Token *); +static Node *compound_stmt(Token **, Token *); +static Node *conditional(Token **, Token *); +static Node *declaration(Token **, Token *, Type *, VarAttr *); +static Node *equality(Token **, Token *); +static Node *expr_stmt(Token **, Token *); +static Node *funcall(Token **, Token *, Node *); +static Node *logand(Token **, Token *); +static Node *logor(Token **, Token *); +static Node *lvar_initializer(Token **, Token *, Obj *); +static Node *mul(Token **, Token *); +static Node *new_add(Node *, Node *, Token *); +static Node *new_sub(Node *, Node *, Token *); +static Node *postfix(Token **, Token *); +static Node *primary(Token **, Token *); +static Node *relational(Token **, Token *); +static Node *shift(Token **, Token *); +static Node *stmt(Token **, Token *); +static Node *unary(Token **, Token *); +static Token *function(Token *, Type *, VarAttr *); +static Token *global_variable(Token *, Type *, VarAttr *); +static Token *parse_typedef(Token *, Type *); +static Type *declarator(Token **, Token *, Type *); +static Type *enum_specifier(Token **, Token *); +static Type *struct_decl(Token **, Token *); +static Type *type_suffix(Token **, Token *, Type *); +static Type *typename(Token **, Token *); +static Type *typeof_specifier(Token **, Token *); +static Type *union_decl(Token **, Token *); +static bool is_function(Token *); +static bool is_typename(Token *); +static double eval_double(Node *); +static int64_t eval_rval(Node *, char ***); +static void array_initializer2(Token **, Token *, Initializer *, int); +static void gvar_initializer(Token **, Token *, Obj *); +static void initializer2(Token **, Token *, Initializer *); +static void struct_initializer2(Token **, Token *, Initializer *, Member *); static void enter_scope(void) { Scope *sc = calloc(1, sizeof(Scope)); @@ -207,7 +198,7 @@ static TagScope *find_tag(Token *tok) { return NULL; } -static Node *new_node(NodeKind kind, Token *tok) { +Node *new_node(NodeKind kind, Token *tok) { Node *node = calloc(1, sizeof(Node)); node->kind = kind; node->tok = tok; @@ -261,7 +252,6 @@ static Node *new_vla_ptr(Obj *var, Token *tok) { Node *new_cast(Node *expr, Type *ty) { add_type(expr); - Node *node = calloc(1, sizeof(Node)); node->kind = ND_CAST; node->tok = expr->tok; @@ -281,26 +271,21 @@ static VarScope *push_scope(char *name) { static Initializer *new_initializer(Type *ty, bool is_flexible) { Initializer *init = calloc(1, sizeof(Initializer)); init->ty = ty; - if (ty->kind == TY_ARRAY) { if (is_flexible && ty->size < 0) { init->is_flexible = true; return init; } - init->children = calloc(ty->array_len, sizeof(Initializer *)); for (int i = 0; i < ty->array_len; i++) init->children[i] = new_initializer(ty->base, false); return init; } - if (ty->kind == TY_STRUCT || ty->kind == TY_UNION) { // Count the number of struct members. int len = 0; for (Member *mem = ty->members; mem; mem = mem->next) len++; - init->children = calloc(len, sizeof(Initializer *)); - for (Member *mem = ty->members; mem; mem = mem->next) { if (is_flexible && ty->is_flexible && !mem->next) { Initializer *child = calloc(1, sizeof(Initializer)); @@ -313,7 +298,6 @@ static Initializer *new_initializer(Type *ty, bool is_flexible) { } return init; } - return init; } @@ -357,6 +341,7 @@ static Obj *new_anon_gvar(Type *ty) { static Obj *new_string_literal(char *p, Type *ty) { Obj *var = new_anon_gvar(ty); var->init_data = p; + var->is_string_literal = true; return var; } @@ -381,6 +366,238 @@ static void push_tag_scope(Token *tok, Type *ty) { hashmap_put2(&scope->tags, tok->loc, tok->len, sc); } +// Consumes token if equal to STR or __STR__. +static bool consume_attribute(Token **rest, Token *tok, char *name) { + size_t n = strlen(name); + if ((n == tok->len && !memcmp(tok->loc, name, n)) || + (2 + n + 2 == tok->len && tok->loc[0] == '_' && tok->loc[1] == '_' && + tok->loc[tok->len - 2] == '_' && tok->loc[tok->len - 1] == '_' && + !memcmp(tok->loc + 2, name, n))) { + *rest = tok->next; + return true; + } + *rest = tok; + return false; +} + +static Token *attribute_list(Token *tok, void *arg, + Token *(*f)(Token *, void *)) { + while (CONSUME(&tok, tok, "__attribute__")) { + tok = skip(tok, "("); + tok = skip(tok, "("); + bool first = true; + while (!CONSUME(&tok, tok, ")")) { + if (!first) tok = skip(tok, ","); + first = false; + tok = f(tok, arg); + } + tok = skip(tok, ")"); + } + return tok; +} + +static Token *type_attributes(Token *tok, void *arg) { + Type *ty = arg; + if (consume_attribute(&tok, tok, "packed")) { + ty->is_packed = true; + return tok; + } + if (consume_attribute(&tok, tok, "aligned")) { + ty->is_aligned = true; + if (CONSUME(&tok, tok, "(")) { + Token *altok = tok; + ty->align = const_expr(&tok, tok); + if (popcnt(ty->align) != 1) error_tok(altok, "must be two power"); + tok = skip(tok, ")"); + } else { + ty->align = 16; /* biggest alignment */ + } + return tok; + } + if (consume_attribute(&tok, tok, "vector_size")) { + tok = skip(tok, "("); + int vs = const_expr(&tok, tok); + if (vs != 16) { + error_tok(tok, "only vector_size 16 supported"); + } + if (vs != ty->vector_size) { + ty->size = vs; + ty->vector_size = vs; + if (!ty->is_aligned) ty->align = vs; + /* ty->base = ty; */ + /* ty->array_len = vs / ty->size; */ + } + return skip(tok, ")"); + } + if (consume_attribute(&tok, tok, "warn_if_not_aligned")) { + tok = skip(tok, "("); + const_expr(&tok, tok); + return skip(tok, ")"); + } + if (consume_attribute(&tok, tok, "deprecated") || + consume_attribute(&tok, tok, "may_alias") || + consume_attribute(&tok, tok, "unused")) { + return tok; + } + if (consume_attribute(&tok, tok, "alloc_size") || + consume_attribute(&tok, tok, "alloc_align")) { + if (CONSUME(&tok, tok, "(")) { + const_expr(&tok, tok); + tok = skip(tok, ")"); + } + return tok; + } + error_tok(tok, "unknown type attribute"); +} + +static Token *thing_attributes(Token *tok, void *arg) { + VarAttr *attr = arg; + if (consume_attribute(&tok, tok, "weak")) { + attr->is_weak = true; + return tok; + } + if (consume_attribute(&tok, tok, "hot")) { + attr->section = ".text.likely"; + return tok; + } + if (consume_attribute(&tok, tok, "cold")) { + attr->section = ".text.unlikely"; + return tok; + } + if (consume_attribute(&tok, tok, "section")) { + tok = skip(tok, "("); + attr->section = ConsumeStringLiteral(&tok, tok); + return skip(tok, ")"); + } + if (consume_attribute(&tok, tok, "noreturn")) { + attr->is_noreturn = true; + return tok; + } + if (consume_attribute(&tok, tok, "always_inline")) { + attr->is_inline = true; + return tok; + } + if (consume_attribute(&tok, tok, "visibility")) { + tok = skip(tok, "("); + attr->visibility = ConsumeStringLiteral(&tok, tok); + return skip(tok, ")"); + } + if (consume_attribute(&tok, tok, "externally_visible")) { + attr->is_externally_visible = true; + return tok; + } + if (consume_attribute(&tok, tok, "constructor")) { + attr->is_constructor = true; + if (CONSUME(&tok, tok, "(")) { + const_expr(&tok, tok); + tok = skip(tok, ")"); + } + return tok; + } + if (consume_attribute(&tok, tok, "destructor")) { + attr->is_destructor = true; + if (CONSUME(&tok, tok, "(")) { + const_expr(&tok, tok); + tok = skip(tok, ")"); + } + return tok; + } + if (consume_attribute(&tok, tok, "aligned")) { + attr->is_aligned = true; + if (CONSUME(&tok, tok, "(")) { + Token *altok = tok; + attr->align = const_expr(&tok, tok); + if (popcnt(attr->align) != 1) error_tok(altok, "must be two power"); + tok = skip(tok, ")"); + } else { + attr->align = 16; /* biggest alignment */ + } + return tok; + } + if (consume_attribute(&tok, tok, "warn_if_not_aligned")) { + tok = skip(tok, "("); + const_expr(&tok, tok); + return skip(tok, ")"); + } + if (consume_attribute(&tok, tok, "error") || + consume_attribute(&tok, tok, "warning")) { + tok = skip(tok, "("); + ConsumeStringLiteral(&tok, tok); + return skip(tok, ")"); + } + if (consume_attribute(&tok, tok, "noinline") || + consume_attribute(&tok, tok, "const") || + consume_attribute(&tok, tok, "pure") || + consume_attribute(&tok, tok, "noclone") || + consume_attribute(&tok, tok, "may_alias") || + consume_attribute(&tok, tok, "warn_unused_result") || + consume_attribute(&tok, tok, "flatten") || + consume_attribute(&tok, tok, "leaf") || + consume_attribute(&tok, tok, "nothrow") || + consume_attribute(&tok, tok, "optnone") || + consume_attribute(&tok, tok, "returns_twice") || + consume_attribute(&tok, tok, "nodebug") || + consume_attribute(&tok, tok, "artificial") || + consume_attribute(&tok, tok, "returns_nonnull") || + consume_attribute(&tok, tok, "malloc") || + consume_attribute(&tok, tok, "deprecated") || + consume_attribute(&tok, tok, "gnu_inline") || + consume_attribute(&tok, tok, "used") || + consume_attribute(&tok, tok, "unused") || + consume_attribute(&tok, tok, "no_icf") || + consume_attribute(&tok, tok, "noipa") || + consume_attribute(&tok, tok, "noplt") || + consume_attribute(&tok, tok, "stack_protect") || + consume_attribute(&tok, tok, "no_sanitize_address") || + consume_attribute(&tok, tok, "no_sanitize_thread") || + consume_attribute(&tok, tok, "no_split_stack") || + consume_attribute(&tok, tok, "no_stack_limit") || + consume_attribute(&tok, tok, "no_sanitize_undefined") || + consume_attribute(&tok, tok, "no_instrument_function") || + consume_attribute(&tok, tok, "no_profile_instrument_function")) { + return tok; + } + if (consume_attribute(&tok, tok, "sentinel") || + consume_attribute(&tok, tok, "nonnull") || + consume_attribute(&tok, tok, "warning") || + consume_attribute(&tok, tok, "optimize") || + consume_attribute(&tok, tok, "target") || + consume_attribute(&tok, tok, "assume_aligned") || + consume_attribute(&tok, tok, "visibility") || + consume_attribute(&tok, tok, "alloc_size") || + consume_attribute(&tok, tok, "alloc_align")) { + if (CONSUME(&tok, tok, "(")) { + for (;;) { + const_expr(&tok, tok); + if (CONSUME(&tok, tok, ")")) break; + tok = skip(tok, ","); + } + } + return tok; + } + if (consume_attribute(&tok, tok, "format")) { + tok = skip(tok, "("); + consume_attribute(&tok, tok, "printf"); + consume_attribute(&tok, tok, "scanf"); + consume_attribute(&tok, tok, "strftime"); + consume_attribute(&tok, tok, "strfmon"); + consume_attribute(&tok, tok, "gnu_printf"); + consume_attribute(&tok, tok, "gnu_scanf"); + consume_attribute(&tok, tok, "gnu_strftime"); + tok = skip(tok, ","); + const_expr(&tok, tok); + tok = skip(tok, ","); + const_expr(&tok, tok); + return skip(tok, ")"); + } + if (consume_attribute(&tok, tok, "format_arg")) { + tok = skip(tok, "("); + const_expr(&tok, tok); + return skip(tok, ")"); + } + error_tok(tok, "unknown function attribute"); +} + // typespec = typename typename* // typename = "void" | "_Bool" | "char" | "short" | "int" | "long" // | struct-decl | union-decl | typedef-name @@ -413,149 +630,155 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { OTHER = 1 << 16, SIGNED = 1 << 17, UNSIGNED = 1 << 18, + INT128 = 1 << 19, }; - - Type *ty = ty_int; + Type *ty = copy_type(ty_int); int counter = 0; bool is_atomic = false; - while (is_typename(tok)) { // Handle storage class specifiers. - if (equal(tok, "typedef") || equal(tok, "static") || equal(tok, "extern") || - equal(tok, "inline") || equal(tok, "_Thread_local") || - equal(tok, "__thread")) { + if (EQUAL(tok, "typedef") || EQUAL(tok, "static") || EQUAL(tok, "extern") || + EQUAL(tok, "inline") || EQUAL(tok, "__inline") || + EQUAL(tok, "_Thread_local") || EQUAL(tok, "__thread")) { if (!attr) error_tok(tok, "storage class specifier is not allowed in this context"); - - if (equal(tok, "typedef")) + if (EQUAL(tok, "typedef")) { attr->is_typedef = true; - else if (equal(tok, "static")) + } else if (EQUAL(tok, "static")) { attr->is_static = true; - else if (equal(tok, "extern")) + } else if (EQUAL(tok, "extern")) { attr->is_extern = true; - else if (equal(tok, "inline")) + } else if (EQUAL(tok, "inline")) { attr->is_inline = true; - else + } else { attr->is_tls = true; - + } if (attr->is_typedef && attr->is_static + attr->is_extern + attr->is_inline + attr->is_tls > - 1) + 1) { error_tok(tok, "typedef may not be used together with static," " extern, inline, __thread or _Thread_local"); + } tok = tok->next; - continue; + goto Continue; + } + if (CONSUME(&tok, tok, "_Noreturn")) { + if (attr) attr->is_noreturn = true; + goto Continue; + } + if (CONSUME(&tok, tok, "const")) { + if (attr) attr->is_const = true; + goto Continue; } - // These keywords are recognized but ignored. - if (consume(&tok, tok, "const") || consume(&tok, tok, "volatile") || - consume(&tok, tok, "auto") || consume(&tok, tok, "register") || - consume(&tok, tok, "restrict") || consume(&tok, tok, "__restrict") || - consume(&tok, tok, "__restrict__") || consume(&tok, tok, "_Noreturn")) - continue; - - if (equal(tok, "_Atomic")) { + if (CONSUME(&tok, tok, "volatile") || CONSUME(&tok, tok, "auto") || + CONSUME(&tok, tok, "register") || CONSUME(&tok, tok, "restrict") || + CONSUME(&tok, tok, "__restrict") || + CONSUME(&tok, tok, "__restrict__")) { + goto Continue; + } + if (EQUAL(tok, "_Atomic")) { tok = tok->next; - if (equal(tok, "(")) { + if (EQUAL(tok, "(")) { ty = typename(&tok, tok->next); tok = skip(tok, ")"); } is_atomic = true; - continue; + goto Continue; } - - if (equal(tok, "_Alignas")) { + if (EQUAL(tok, "_Alignas")) { if (!attr) error_tok(tok, "_Alignas is not allowed in this context"); tok = skip(tok->next, "("); - - if (is_typename(tok)) + if (is_typename(tok)) { attr->align = typename(&tok, tok)->align; - else + } else { + Token *altok = tok; attr->align = const_expr(&tok, tok); + if (popcnt(ty->align) != 1) { + error_tok(altok, "_Alignas needs two power"); + } + } tok = skip(tok, ")"); - continue; + goto Continue; } - // Handle user-defined types. Type *ty2 = find_typedef(tok); - if (equal(tok, "struct") || equal(tok, "union") || equal(tok, "enum") || - equal(tok, "typeof") || ty2) { + if (EQUAL(tok, "struct") || EQUAL(tok, "union") || EQUAL(tok, "enum") || + EQUAL(tok, "typeof") || ty2) { if (counter) break; - - if (equal(tok, "struct")) { + if (EQUAL(tok, "struct")) { ty = struct_decl(&tok, tok->next); - } else if (equal(tok, "union")) { + } else if (EQUAL(tok, "union")) { ty = union_decl(&tok, tok->next); - } else if (equal(tok, "enum")) { + } else if (EQUAL(tok, "enum")) { ty = enum_specifier(&tok, tok->next); - } else if (equal(tok, "typeof")) { + } else if (EQUAL(tok, "typeof")) { ty = typeof_specifier(&tok, tok->next); } else { ty = ty2; tok = tok->next; } - counter += OTHER; - continue; + goto Continue; } - // Handle built-in types. - if (equal(tok, "void")) + if (EQUAL(tok, "void")) counter += VOID; - else if (equal(tok, "_Bool")) + else if (EQUAL(tok, "_Bool")) counter += BOOL; - else if (equal(tok, "char")) + else if (EQUAL(tok, "char")) counter += CHAR; - else if (equal(tok, "short")) + else if (EQUAL(tok, "short")) counter += SHORT; - else if (equal(tok, "int")) + else if (EQUAL(tok, "int")) counter += INT; - else if (equal(tok, "long")) + else if (EQUAL(tok, "long")) counter += LONG; - else if (equal(tok, "float")) + else if (EQUAL(tok, "__int128")) + counter += INT128; + else if (EQUAL(tok, "float")) counter += FLOAT; - else if (equal(tok, "double")) + else if (EQUAL(tok, "double")) counter += DOUBLE; - else if (equal(tok, "signed")) + else if (EQUAL(tok, "signed")) counter |= SIGNED; - else if (equal(tok, "unsigned")) + else if (EQUAL(tok, "unsigned")) counter |= UNSIGNED; else UNREACHABLE(); - switch (counter) { case VOID: - ty = ty_void; + ty = copy_type(ty_void); break; case BOOL: - ty = ty_bool; + ty = copy_type(ty_bool); break; case CHAR: case SIGNED + CHAR: - ty = ty_char; + ty = copy_type(ty_char); break; case UNSIGNED + CHAR: - ty = ty_uchar; + ty = copy_type(ty_uchar); break; case SHORT: case SHORT + INT: case SIGNED + SHORT: case SIGNED + SHORT + INT: - ty = ty_short; + ty = copy_type(ty_short); break; case UNSIGNED + SHORT: case UNSIGNED + SHORT + INT: - ty = ty_ushort; + ty = copy_type(ty_ushort); break; case INT: case SIGNED: case SIGNED + INT: - ty = ty_int; + ty = copy_type(ty_int); break; case UNSIGNED: case UNSIGNED + INT: - ty = ty_uint; + ty = copy_type(ty_uint); break; case LONG: case LONG + INT: @@ -565,35 +788,45 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { case SIGNED + LONG + INT: case SIGNED + LONG + LONG: case SIGNED + LONG + LONG + INT: - ty = ty_long; + ty = copy_type(ty_long); break; case UNSIGNED + LONG: case UNSIGNED + LONG + INT: case UNSIGNED + LONG + LONG: case UNSIGNED + LONG + LONG + INT: - ty = ty_ulong; + ty = copy_type(ty_ulong); + break; + case INT128: + case SIGNED + INT128: + ty = copy_type(ty_int128); + break; + case UNSIGNED + INT128: + ty = copy_type(ty_uint128); break; case FLOAT: - ty = ty_float; + ty = copy_type(ty_float); break; case DOUBLE: - ty = ty_double; + ty = copy_type(ty_double); break; case LONG + DOUBLE: - ty = ty_ldouble; + ty = copy_type(ty_ldouble); break; default: error_tok(tok, "invalid type"); } - tok = tok->next; + Continue: + if (attr && attr->is_typedef) { + tok = attribute_list(tok, ty, type_attributes); + } else if (attr) { + tok = attribute_list(tok, attr, thing_attributes); + } } - if (is_atomic) { ty = copy_type(ty); ty->is_atomic = true; } - *rest = tok; return ty; } @@ -601,30 +834,24 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { // func-params = ("void" | param ("," param)* ("," "...")?)? ")" // param = typespec declarator static Type *func_params(Token **rest, Token *tok, Type *ty) { - if (equal(tok, "void") && equal(tok->next, ")")) { + if (EQUAL(tok, "void") && EQUAL(tok->next, ")")) { *rest = tok->next->next; return func_type(ty); } - Type head = {}; Type *cur = &head; bool is_variadic = false; - - while (!equal(tok, ")")) { + while (!EQUAL(tok, ")")) { if (cur != &head) tok = skip(tok, ","); - - if (equal(tok, "...")) { + if (EQUAL(tok, "...")) { is_variadic = true; tok = tok->next; skip(tok, ")"); break; } - Type *ty2 = typespec(&tok, tok, NULL); ty2 = declarator(&tok, tok, ty2); - Token *name = ty2->name; - if (ty2->kind == TY_ARRAY) { // "array of T" is converted to "pointer to T" only in the parameter // context. For example, *argv[] is converted to **argv by this. @@ -636,12 +863,9 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) { ty2 = pointer_to(ty2); ty2->name = name; } - cur = cur->next = copy_type(ty2); } - if (cur == &head) is_variadic = true; - ty = func_type(ty); ty->params = head.next; ty->is_variadic = is_variadic; @@ -651,17 +875,14 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) { // array-dimensions = ("static" | "restrict")* const-expr? "]" type-suffix static Type *array_dimensions(Token **rest, Token *tok, Type *ty) { - while (equal(tok, "static") || equal(tok, "restrict")) tok = tok->next; - - if (equal(tok, "]")) { + while (EQUAL(tok, "static") || EQUAL(tok, "restrict")) tok = tok->next; + if (EQUAL(tok, "]")) { ty = type_suffix(rest, tok->next, ty); return array_of(ty, -1); } - Node *expr = conditional(&tok, tok); tok = skip(tok, "]"); ty = type_suffix(rest, tok, ty); - if (ty->kind == TY_VLA || !is_const_expr(expr)) return vla_of(ty, expr); return array_of(ty, eval(expr)); } @@ -670,21 +891,24 @@ static Type *array_dimensions(Token **rest, Token *tok, Type *ty) { // | "[" array-dimensions // | ε static Type *type_suffix(Token **rest, Token *tok, Type *ty) { - if (equal(tok, "(")) return func_params(rest, tok->next, ty); - - if (equal(tok, "[")) return array_dimensions(rest, tok->next, ty); - - *rest = tok; + if (EQUAL(tok, "(")) { + ty = func_params(rest, tok->next, ty); + } else if (EQUAL(tok, "[")) { + ty = array_dimensions(rest, tok->next, ty); + *rest = attribute_list(*rest, ty, type_attributes); + } else { + *rest = tok; + } return ty; } // pointers = ("*" ("const" | "volatile" | "restrict")*)* static Type *pointers(Token **rest, Token *tok, Type *ty) { - while (consume(&tok, tok, "*")) { + while (CONSUME(&tok, tok, "*")) { ty = pointer_to(ty); - while (equal(tok, "const") || equal(tok, "volatile") || - equal(tok, "restrict") || equal(tok, "__restrict") || - equal(tok, "__restrict__")) + while (EQUAL(tok, "const") || EQUAL(tok, "volatile") || + EQUAL(tok, "restrict") || EQUAL(tok, "__restrict") || + EQUAL(tok, "__restrict__")) tok = tok->next; } *rest = tok; @@ -695,35 +919,33 @@ static Type *pointers(Token **rest, Token *tok, Type *ty) { // type-suffix static Type *declarator(Token **rest, Token *tok, Type *ty) { ty = pointers(&tok, tok, ty); - - if (equal(tok, "(")) { + if (EQUAL(tok, "(")) { Token *start = tok; Type ignore = {}; declarator(&tok, tok->next, &ignore); tok = skip(tok, ")"); ty = type_suffix(rest, tok, ty); - return declarator(&tok, start->next, ty); + ty = declarator(&tok, start->next, ty); + /* *rest = attribute_list(tok, ty, type_attributes); */ + return ty; } - Token *name = NULL; Token *name_pos = tok; - if (tok->kind == TK_IDENT) { name = tok; tok = tok->next; } - ty = type_suffix(rest, tok, ty); ty->name = name; ty->name_pos = name_pos; + /* *rest = attribute_list(tok, ty, type_attributes); */ return ty; } // abstract-declarator = pointers ("(" abstract-declarator ")")? type-suffix static Type *abstract_declarator(Token **rest, Token *tok, Type *ty) { ty = pointers(&tok, tok, ty); - - if (equal(tok, "(")) { + if (EQUAL(tok, "(")) { Token *start = tok; Type ignore = {}; abstract_declarator(&tok, tok->next, &ignore); @@ -731,7 +953,6 @@ static Type *abstract_declarator(Token **rest, Token *tok, Type *ty) { ty = type_suffix(rest, tok, ty); return abstract_declarator(&tok, start->next, ty); } - return type_suffix(rest, tok, ty); } @@ -742,20 +963,18 @@ static Type *typename(Token **rest, Token *tok) { } static bool is_end(Token *tok) { - return equal(tok, "}") || (equal(tok, ",") && equal(tok->next, "}")); + return EQUAL(tok, "}") || (EQUAL(tok, ",") && EQUAL(tok->next, "}")); } static bool consume_end(Token **rest, Token *tok) { - if (equal(tok, "}")) { + if (EQUAL(tok, "}")) { *rest = tok->next; return true; } - - if (equal(tok, ",") && equal(tok->next, "}")) { + if (EQUAL(tok, ",") && EQUAL(tok->next, "}")) { *rest = tok->next->next; return true; } - return false; } @@ -765,40 +984,32 @@ static bool consume_end(Token **rest, Token *tok) { // enum-list = ident ("=" num)? ("," ident ("=" num)?)* ","? static Type *enum_specifier(Token **rest, Token *tok) { Type *ty = enum_type(); - // Read a struct tag. Token *tag = NULL; if (tok->kind == TK_IDENT) { tag = tok; tok = tok->next; } - - if (tag && !equal(tok, "{")) { + if (tag && !EQUAL(tok, "{")) { TagScope *sc = find_tag(tag); if (!sc) error_tok(tag, "unknown enum type"); if (sc->ty->kind != TY_ENUM) error_tok(tag, "not an enum tag"); *rest = tok; return sc->ty; } - tok = skip(tok, "{"); - // Read an enum-list. int i = 0; int val = 0; while (!consume_end(rest, tok)) { if (i++ > 0) tok = skip(tok, ","); - char *name = get_ident(tok); tok = tok->next; - - if (equal(tok, "=")) val = const_expr(&tok, tok->next); - + if (EQUAL(tok, "=")) val = const_expr(&tok, tok->next); VarScope *sc = push_scope(name); sc->enum_ty = ty; sc->enum_val = val++; } - if (tag) push_tag_scope(tag, ty); return ty; } @@ -806,7 +1017,6 @@ static Type *enum_specifier(Token **rest, Token *tok) { // typeof-specifier = "(" (expr | typename) ")" static Type *typeof_specifier(Token **rest, Token *tok) { tok = skip(tok, "("); - Type *ty; if (is_typename(tok)) { ty = typename(&tok, tok); @@ -824,15 +1034,13 @@ static Node *compute_vla_size(Type *ty, Token *tok) { Node *node = new_node(ND_NULL_EXPR, tok); if (ty->base) node = new_binary(ND_COMMA, node, compute_vla_size(ty->base, tok), tok); - if (ty->kind != TY_VLA) return node; - Node *base_sz; - if (ty->base->kind == TY_VLA) + if (ty->base->kind == TY_VLA) { base_sz = new_var_node(ty->base->vla_size, tok); - else + } else { base_sz = new_num(ty->base->size, tok); - + } ty->vla_size = new_lvar("", ty_ulong); Node *expr = new_binary(ND_ASSIGN, new_var_node(ty->vla_size, tok), new_binary(ND_MUL, ty->vla_len, base_sz, tok), tok); @@ -856,31 +1064,25 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, Node head = {}; Node *cur = &head; int i = 0; - - while (!equal(tok, ";")) { + while (!EQUAL(tok, ";")) { if (i++ > 0) tok = skip(tok, ","); - Type *ty = declarator(&tok, tok, basety); if (ty->kind == TY_VOID) error_tok(tok, "variable declared void"); if (!ty->name) error_tok(ty->name_pos, "variable name omitted"); - if (attr && attr->is_static) { // static local variable Obj *var = new_anon_gvar(ty); push_scope(get_ident(ty->name))->var = var; - if (equal(tok, "=")) gvar_initializer(&tok, tok->next, var); + if (EQUAL(tok, "=")) gvar_initializer(&tok, tok->next, var); continue; } - // Generate code for computing a VLA size. We need to do this // even if ty is not VLA because ty may be a pointer to VLA // (e.g. int (*foo)[n][m] where n and m are variables.) cur = cur->next = new_unary(ND_EXPR_STMT, compute_vla_size(ty, tok), tok); - if (ty->kind == TY_VLA) { - if (equal(tok, "=")) + if (EQUAL(tok, "=")) error_tok(tok, "variable-sized object may not be initialized"); - // Variable length arrays (VLAs) are translated to alloca() calls. // For example, `int x[n+2]` is translated to `tmp = n + 2, // x = alloca(tmp)`. @@ -888,23 +1090,18 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, Token *tok = ty->name; Node *expr = new_binary(ND_ASSIGN, new_vla_ptr(var, tok), new_alloca(new_var_node(ty->vla_size, tok)), tok); - cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok); continue; } - Obj *var = new_lvar(get_ident(ty->name), ty); if (attr && attr->align) var->align = attr->align; - - if (equal(tok, "=")) { + if (EQUAL(tok, "=")) { Node *expr = lvar_initializer(&tok, tok->next, var); cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok); } - if (var->ty->size < 0) error_tok(ty->name, "variable has incomplete type"); if (var->ty->kind == TY_VOID) error_tok(ty->name, "variable declared void"); } - Node *node = new_node(ND_BLOCK, tok); node->body = head.next; *rest = tok->next; @@ -912,23 +1109,21 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, } static Token *skip_excess_element(Token *tok) { - if (equal(tok, "{")) { + if (EQUAL(tok, "{")) { tok = skip_excess_element(tok->next); return skip(tok, "}"); } - assign(&tok, tok); return tok; } // string-initializer = string-literal static void string_initializer(Token **rest, Token *tok, Initializer *init) { - if (init->is_flexible) + if (init->is_flexible) { *init = *new_initializer(array_of(init->ty->base, tok->ty->array_len), false); - + } int len = MIN(init->ty->array_len, tok->ty->array_len); - switch (init->ty->base->size) { case 1: { char *str = tok->str; @@ -951,7 +1146,6 @@ static void string_initializer(Token **rest, Token *tok, Initializer *init) { default: UNREACHABLE(); } - *rest = tok->next; } @@ -985,8 +1179,7 @@ static void array_designator(Token **rest, Token *tok, Type *ty, int *begin, *begin = const_expr(&tok, tok->next); if (*begin >= ty->array_len) error_tok(tok, "array designator index exceeds array bounds"); - - if (equal(tok, "...")) { + if (EQUAL(tok, "...")) { *end = const_expr(&tok, tok->next); if (*end >= ty->array_len) error_tok(tok, "array designator index exceeds array bounds"); @@ -995,7 +1188,6 @@ static void array_designator(Token **rest, Token *tok, Type *ty, int *begin, } else { *end = *begin; } - *rest = skip(tok, "]"); } @@ -1004,7 +1196,6 @@ static Member *struct_designator(Token **rest, Token *tok, Type *ty) { Token *start = tok; tok = skip(tok, "."); if (tok->kind != TK_IDENT) error_tok(tok, "expected a field designator"); - for (Member *mem = ty->members; mem; mem = mem->next) { // Anonymous struct member if (mem->ty->kind == TY_STRUCT && !mem->name) { @@ -1014,7 +1205,6 @@ static Member *struct_designator(Token **rest, Token *tok, Type *ty) { } continue; } - // Regular struct member if (mem->name->len == tok->len && !strncmp(mem->name->loc, tok->loc, tok->len)) { @@ -1022,45 +1212,39 @@ static Member *struct_designator(Token **rest, Token *tok, Type *ty) { return mem; } } - error_tok(tok, "struct has no such member"); } // designation = ("[" const-expr "]" | "." ident)* "="? initializer static void designation(Token **rest, Token *tok, Initializer *init) { - if (equal(tok, "[")) { + if (EQUAL(tok, "[")) { if (init->ty->kind != TY_ARRAY) error_tok(tok, "array index in non-array initializer"); - int begin, end; array_designator(&tok, tok, init->ty, &begin, &end); - Token *tok2; for (int i = begin; i <= end; i++) designation(&tok2, tok, init->children[i]); array_initializer2(rest, tok2, init, begin + 1); return; } - - if (equal(tok, ".") && init->ty->kind == TY_STRUCT) { + if (EQUAL(tok, ".") && init->ty->kind == TY_STRUCT) { Member *mem = struct_designator(&tok, tok, init->ty); designation(&tok, tok, init->children[mem->idx]); init->expr = NULL; struct_initializer2(rest, tok, init, mem->next); return; } - - if (equal(tok, ".") && init->ty->kind == TY_UNION) { + if (EQUAL(tok, ".") && init->ty->kind == TY_UNION) { Member *mem = struct_designator(&tok, tok, init->ty); init->mem = mem; designation(rest, tok, init->children[mem->idx]); return; } - - if (equal(tok, ".")) + if (EQUAL(tok, ".")) { error_tok(tok, "field name not in struct or union initializer"); - - if (equal(tok, "=")) tok = tok->next; + } + if (EQUAL(tok, "=")) tok = tok->next; initializer2(rest, tok, init); } @@ -1070,22 +1254,18 @@ static void designation(Token **rest, Token *tok, Initializer *init) { static int count_array_init_elements(Token *tok, Type *ty) { bool first = true; Initializer *dummy = new_initializer(ty->base, true); - int i = 0, max = 0; - while (!consume_end(&tok, tok)) { if (!first) tok = skip(tok, ","); first = false; - - if (equal(tok, "[")) { + if (EQUAL(tok, "[")) { i = const_expr(&tok, tok->next); - if (equal(tok, "...")) i = const_expr(&tok, tok->next); + if (EQUAL(tok, "...")) i = const_expr(&tok, tok->next); tok = skip(tok, "]"); designation(&tok, tok, dummy); } else { initializer2(&tok, tok, dummy); } - i++; max = MAX(max, i); } @@ -1095,27 +1275,21 @@ static int count_array_init_elements(Token *tok, Type *ty) { // array-initializer1 = "{" initializer ("," initializer)* ","? "}" static void array_initializer1(Token **rest, Token *tok, Initializer *init) { tok = skip(tok, "{"); - if (init->is_flexible) { int len = count_array_init_elements(tok, init->ty); *init = *new_initializer(array_of(init->ty->base, len), false); } - bool first = true; - if (init->is_flexible) { int len = count_array_init_elements(tok, init->ty); *init = *new_initializer(array_of(init->ty->base, len), false); } - for (int i = 0; !consume_end(rest, tok); i++) { if (!first) tok = skip(tok, ","); first = false; - - if (equal(tok, "[")) { + if (EQUAL(tok, "[")) { int begin, end; array_designator(&tok, tok, init->ty, &begin, &end); - Token *tok2; for (int j = begin; j <= end; j++) designation(&tok2, tok, init->children[j]); @@ -1123,11 +1297,11 @@ static void array_initializer1(Token **rest, Token *tok, Initializer *init) { i = end; continue; } - - if (i < init->ty->array_len) + if (i < init->ty->array_len) { initializer2(&tok, tok, init->children[i]); - else + } else { tok = skip_excess_element(tok); + } } } @@ -1138,16 +1312,13 @@ static void array_initializer2(Token **rest, Token *tok, Initializer *init, int len = count_array_init_elements(tok, init->ty); *init = *new_initializer(array_of(init->ty->base, len), false); } - for (; i < init->ty->array_len && !is_end(tok); i++) { Token *start = tok; if (i > 0) tok = skip(tok, ","); - - if (equal(tok, "[") || equal(tok, ".")) { + if (EQUAL(tok, "[") || EQUAL(tok, ".")) { *rest = start; return; } - initializer2(&tok, tok, init->children[i]); } *rest = tok; @@ -1156,21 +1327,17 @@ static void array_initializer2(Token **rest, Token *tok, Initializer *init, // struct-initializer1 = "{" initializer ("," initializer)* ","? "}" static void struct_initializer1(Token **rest, Token *tok, Initializer *init) { tok = skip(tok, "{"); - Member *mem = init->ty->members; bool first = true; - while (!consume_end(rest, tok)) { if (!first) tok = skip(tok, ","); first = false; - - if (equal(tok, ".")) { + if (EQUAL(tok, ".")) { mem = struct_designator(&tok, tok, init->ty); designation(&tok, tok, init->children[mem->idx]); mem = mem->next; continue; } - if (mem) { initializer2(&tok, tok, init->children[mem->idx]); mem = mem->next; @@ -1186,12 +1353,10 @@ static void struct_initializer2(Token **rest, Token *tok, Initializer *init, for (; mem && !is_end(tok); mem = mem->next) { Token *start = tok; if (mem != init->ty->members) tok = skip(tok, ","); - - if (equal(tok, "[") || equal(tok, ".")) { + if (EQUAL(tok, "[") || EQUAL(tok, ".")) { *rest = start; return; } - initializer2(&tok, tok, init->children[mem->idx]); } *rest = tok; @@ -1201,17 +1366,15 @@ static void union_initializer(Token **rest, Token *tok, Initializer *init) { // Unlike structs, union initializers take only one initializer, // and that initializes the first union member by default. // You can initialize other member using a designated initializer. - if (equal(tok, "{") && equal(tok->next, ".")) { + if (EQUAL(tok, "{") && EQUAL(tok->next, ".")) { Member *mem = struct_designator(&tok, tok->next, init->ty); init->mem = mem; designation(&tok, tok, init->children[mem->idx]); *rest = skip(tok, "}"); return; } - init->mem = init->ty->members; - - if (equal(tok, "{")) { + if (EQUAL(tok, "{")) { initializer2(&tok, tok->next, init->children[0]); *rest = skip(tok, "}"); } else { @@ -1227,21 +1390,18 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) { string_initializer(rest, tok, init); return; } - if (init->ty->kind == TY_ARRAY) { - if (equal(tok, "{")) + if (EQUAL(tok, "{")) array_initializer1(rest, tok, init); else array_initializer2(rest, tok, init, 0); return; } - if (init->ty->kind == TY_STRUCT) { - if (equal(tok, "{")) { + if (EQUAL(tok, "{")) { struct_initializer1(rest, tok, init); return; } - // A struct can be initialized with another struct. E.g. // `struct T x = y;` where y is a variable of type `struct T`. // Handle that case first. @@ -1251,30 +1411,25 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) { init->expr = expr; return; } - struct_initializer2(rest, tok, init, init->ty->members); return; } - if (init->ty->kind == TY_UNION) { union_initializer(rest, tok, init); return; } - - if (equal(tok, "{")) { + if (EQUAL(tok, "{")) { // An initializer for a scalar variable can be surrounded by // braces. E.g. `int x = {3};`. Handle that case. initializer2(&tok, tok->next, init); *rest = skip(tok, "}"); return; } - init->expr = assign(rest, tok); } static Type *copy_struct_type(Type *ty) { ty = copy_type(ty); - Member head = {}; Member *cur = &head; for (Member *mem = ty->members; mem; mem = mem->next) { @@ -1282,7 +1437,6 @@ static Type *copy_struct_type(Type *ty) { *m = *mem; cur = cur->next = m; } - ty->members = head.next; return ty; } @@ -1291,32 +1445,26 @@ static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty) { Initializer *init = new_initializer(ty, true); initializer2(rest, tok, init); - if ((ty->kind == TY_STRUCT || ty->kind == TY_UNION) && ty->is_flexible) { ty = copy_struct_type(ty); - Member *mem = ty->members; while (mem->next) mem = mem->next; mem->ty = init->children[mem->idx]->ty; ty->size += mem->ty->size; - *new_ty = ty; return init; } - *new_ty = init->ty; return init; } static Node *init_desg_expr(InitDesg *desg, Token *tok) { if (desg->var) return new_var_node(desg->var, tok); - if (desg->member) { Node *node = new_unary(ND_MEMBER, init_desg_expr(desg->next, tok), tok); node->member = desg->member; return node; } - Node *lhs = init_desg_expr(desg->next, tok); Node *rhs = new_num(desg->idx, tok); return new_unary(ND_DEREF, new_add(lhs, rhs, tok), tok); @@ -1333,10 +1481,8 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, } return node; } - if (ty->kind == TY_STRUCT && !init->expr) { Node *node = new_node(ND_NULL_EXPR, tok); - for (Member *mem = ty->members; mem; mem = mem->next) { InitDesg desg2 = {desg, 0, mem}; Node *rhs = @@ -1345,15 +1491,12 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, } return node; } - if (ty->kind == TY_UNION) { Member *mem = init->mem ? init->mem : ty->members; InitDesg desg2 = {desg, 0, mem}; return create_lvar_init(init->children[mem->idx], mem->ty, &desg2, tok); } - if (!init->expr) return new_node(ND_NULL_EXPR, tok); - Node *lhs = init_desg_expr(desg, tok); return new_binary(ND_ASSIGN, lhs, init->expr, tok); } @@ -1371,14 +1514,12 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, static Node *lvar_initializer(Token **rest, Token *tok, Obj *var) { Initializer *init = initializer(rest, tok, var->ty, &var->ty); InitDesg desg = {NULL, 0, NULL, var}; - // If a partial initializer list is given, the standard requires // that unspecified elements are set to 0. Here, we simply // zero-initialize the entire memory region of a variable before // initializing it with user-supplied values. Node *lhs = new_node(ND_MEMZERO, tok); lhs->var = var; - Node *rhs = create_lvar_init(init, var->ty, &desg, tok); return new_binary(ND_COMMA, lhs, rhs, tok); } @@ -1392,16 +1533,17 @@ static uint64_t read_buf(char *buf, int sz) { } static void write_buf(char *buf, uint64_t val, int sz) { - if (sz == 1) + if (sz == 1) { *buf = val; - else if (sz == 2) + } else if (sz == 2) { *(uint16_t *)buf = val; - else if (sz == 4) + } else if (sz == 4) { *(uint32_t *)buf = val; - else if (sz == 8) + } else if (sz == 8) { *(uint64_t *)buf = val; - else + } else { UNREACHABLE(); + } } static Relocation *write_gvar_data(Relocation *cur, Initializer *init, Type *ty, @@ -1413,13 +1555,11 @@ static Relocation *write_gvar_data(Relocation *cur, Initializer *init, Type *ty, offset + sz * i); return cur; } - if (ty->kind == TY_STRUCT) { for (Member *mem = ty->members; mem; mem = mem->next) { if (mem->is_bitfield) { Node *expr = init->children[mem->idx]->expr; if (!expr) break; - char *loc = buf + offset + mem->offset; uint64_t oldval = read_buf(loc, mem->ty->size); uint64_t newval = eval(expr); @@ -1433,33 +1573,26 @@ static Relocation *write_gvar_data(Relocation *cur, Initializer *init, Type *ty, } return cur; } - if (ty->kind == TY_UNION) { if (!init->mem) return cur; return write_gvar_data(cur, init->children[init->mem->idx], init->mem->ty, buf, offset); } - if (!init->expr) return cur; - if (ty->kind == TY_FLOAT) { *(float *)(buf + offset) = eval_double(init->expr); return cur; } - if (ty->kind == TY_DOUBLE) { *(double *)(buf + offset) = eval_double(init->expr); return cur; } - char **label = NULL; uint64_t val = eval2(init->expr, &label); - if (!label) { write_buf(buf + offset, val, ty->size); return cur; } - Relocation *rel = calloc(1, sizeof(Relocation)); rel->offset = offset; rel->label = label; @@ -1474,7 +1607,6 @@ static Relocation *write_gvar_data(Relocation *cur, Initializer *init, Type *ty, // initializer list contains a non-constant expression. static void gvar_initializer(Token **rest, Token *tok, Obj *var) { Initializer *init = initializer(rest, tok, var->ty, &var->ty); - Relocation head = {}; char *buf = calloc(1, var->ty->size); write_gvar_data(&head, init, var->ty, buf, 0); @@ -1485,39 +1617,23 @@ static void gvar_initializer(Token **rest, Token *tok, Obj *var) { // Returns true if a given token represents a type. static bool is_typename(Token *tok) { static HashMap map; - if (map.capacity == 0) { static char *kw[] = { - "void", "_Bool", "char", "short", "int", - "long", "struct", "union", "typedef", "enum", - "static", "extern", "_Alignas", "signed", "unsigned", - "const", "volatile", "auto", "register", "restrict", - "__restrict", "__restrict__", "_Noreturn", "float", "double", - "typeof", "inline", "_Thread_local", "__thread", "_Atomic", + "void", "_Bool", "char", "short", "int", + "long", "struct", "union", "typedef", "enum", + "static", "extern", "_Alignas", "signed", "unsigned", + "const", "volatile", "auto", "register", "restrict", + "__restrict", "__restrict__", "_Noreturn", "float", "double", + "typeof", "inline", "__inline", "_Thread_local", "__thread", + "_Atomic", "__int128", }; - - for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) + for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { hashmap_put(&map, kw[i], (void *)1); + } } - return hashmap_get2(&map, tok->loc, tok->len) || find_typedef(tok); } -// asm-stmt = "asm" ("volatile" | "inline")* "(" string-literal ")" -static Node *asm_stmt(Token **rest, Token *tok) { - Node *node = new_node(ND_ASM, tok); - tok = tok->next; - - while (equal(tok, "volatile") || equal(tok, "inline")) tok = tok->next; - - tok = skip(tok, "("); - if (tok->kind != TK_STR || tok->ty->base->kind != TY_CHAR) - error_tok(tok, "expected string literal"); - node->asm_str = tok->str; - *rest = skip(tok->next, ")"); - return node; -} - // stmt = "return" expr? ";" // | "if" "(" expr ")" stmt ("else" stmt)? // | "switch" "(" expr ")" stmt @@ -1534,67 +1650,54 @@ static Node *asm_stmt(Token **rest, Token *tok) { // | "{" compound-stmt // | expr-stmt static Node *stmt(Token **rest, Token *tok) { - if (equal(tok, "return")) { + if (EQUAL(tok, "return")) { Node *node = new_node(ND_RETURN, tok); - if (consume(rest, tok->next, ";")) return node; - + if (CONSUME(rest, tok->next, ";")) return node; Node *exp = expr(&tok, tok->next); *rest = skip(tok, ";"); - add_type(exp); Type *ty = current_fn->ty->return_ty; if (ty->kind != TY_STRUCT && ty->kind != TY_UNION) exp = new_cast(exp, current_fn->ty->return_ty); - node->lhs = exp; return node; } - - if (equal(tok, "if")) { + if (EQUAL(tok, "if")) { Node *node = new_node(ND_IF, tok); tok = skip(tok->next, "("); node->cond = expr(&tok, tok); tok = skip(tok, ")"); node->then = stmt(&tok, tok); - if (equal(tok, "else")) node->els = stmt(&tok, tok->next); + if (EQUAL(tok, "else")) node->els = stmt(&tok, tok->next); *rest = tok; return node; } - - if (equal(tok, "switch")) { + if (EQUAL(tok, "switch")) { Node *node = new_node(ND_SWITCH, tok); tok = skip(tok->next, "("); node->cond = expr(&tok, tok); tok = skip(tok, ")"); - Node *sw = current_switch; current_switch = node; - char *brk = brk_label; brk_label = node->brk_label = new_unique_name(); - node->then = stmt(rest, tok); - current_switch = sw; brk_label = brk; return node; } - - if (equal(tok, "case")) { + if (EQUAL(tok, "case")) { if (!current_switch) error_tok(tok, "stray case"); - Node *node = new_node(ND_CASE, tok); int begin = const_expr(&tok, tok->next); int end; - - if (equal(tok, "...")) { + if (EQUAL(tok, "...")) { // [GNU] Case ranges, e.g. "case 1 ... 5:" end = const_expr(&tok, tok->next); if (end < begin) error_tok(tok, "empty case range specified"); } else { end = begin; } - tok = skip(tok, ":"); node->label = new_unique_name(); node->lhs = stmt(rest, tok); @@ -1604,10 +1707,8 @@ static Node *stmt(Token **rest, Token *tok) { current_switch->case_next = node; return node; } - - if (equal(tok, "default")) { + if (EQUAL(tok, "default")) { if (!current_switch) error_tok(tok, "stray default"); - Node *node = new_node(ND_CASE, tok); tok = skip(tok->next, ":"); node->label = new_unique_name(); @@ -1615,70 +1716,53 @@ static Node *stmt(Token **rest, Token *tok) { current_switch->default_case = node; return node; } - - if (equal(tok, "for")) { + if (EQUAL(tok, "for")) { Node *node = new_node(ND_FOR, tok); tok = skip(tok->next, "("); - enter_scope(); - char *brk = brk_label; char *cont = cont_label; brk_label = node->brk_label = new_unique_name(); cont_label = node->cont_label = new_unique_name(); - if (is_typename(tok)) { Type *basety = typespec(&tok, tok, NULL); node->init = declaration(&tok, tok, basety, NULL); } else { node->init = expr_stmt(&tok, tok); } - - if (!equal(tok, ";")) node->cond = expr(&tok, tok); + if (!EQUAL(tok, ";")) node->cond = expr(&tok, tok); tok = skip(tok, ";"); - - if (!equal(tok, ")")) node->inc = expr(&tok, tok); + if (!EQUAL(tok, ")")) node->inc = expr(&tok, tok); tok = skip(tok, ")"); - node->then = stmt(rest, tok); - leave_scope(); brk_label = brk; cont_label = cont; return node; } - - if (equal(tok, "while")) { + if (EQUAL(tok, "while")) { Node *node = new_node(ND_FOR, tok); tok = skip(tok->next, "("); node->cond = expr(&tok, tok); tok = skip(tok, ")"); - char *brk = brk_label; char *cont = cont_label; brk_label = node->brk_label = new_unique_name(); cont_label = node->cont_label = new_unique_name(); - node->then = stmt(rest, tok); - brk_label = brk; cont_label = cont; return node; } - - if (equal(tok, "do")) { + if (EQUAL(tok, "do")) { Node *node = new_node(ND_DO, tok); - char *brk = brk_label; char *cont = cont_label; brk_label = node->brk_label = new_unique_name(); cont_label = node->cont_label = new_unique_name(); - node->then = stmt(&tok, tok->next); - brk_label = brk; cont_label = cont; - tok = skip(tok, "while"); tok = skip(tok, "("); node->cond = expr(&tok, tok); @@ -1686,20 +1770,19 @@ static Node *stmt(Token **rest, Token *tok) { *rest = skip(tok, ";"); return node; } - - if (equal(tok, "asm") || equal(tok, "__asm__")) { - return asm_stmt(rest, tok); + if (EQUAL(tok, "asm") || EQUAL(tok, "__asm__")) { + Node *node = new_node(ND_ASM, tok); + node->azm = asm_stmt(rest, tok); + return node; } - - if (equal(tok, "goto")) { - if (equal(tok->next, "*")) { + if (EQUAL(tok, "goto")) { + if (EQUAL(tok->next, "*")) { // [GNU] `goto *ptr` jumps to the address specified by `ptr`. Node *node = new_node(ND_GOTO_EXPR, tok); node->lhs = expr(&tok, tok->next->next); *rest = skip(tok, ";"); return node; } - Node *node = new_node(ND_GOTO, tok); node->label = get_ident(tok->next); node->goto_next = gotos; @@ -1707,24 +1790,21 @@ static Node *stmt(Token **rest, Token *tok) { *rest = skip(tok->next->next, ";"); return node; } - - if (equal(tok, "break")) { + if (EQUAL(tok, "break")) { if (!brk_label) error_tok(tok, "stray break"); Node *node = new_node(ND_GOTO, tok); node->unique_label = brk_label; *rest = skip(tok->next, ";"); return node; } - - if (equal(tok, "continue")) { + if (EQUAL(tok, "continue")) { if (!cont_label) error_tok(tok, "stray continue"); Node *node = new_node(ND_GOTO, tok); node->unique_label = cont_label; *rest = skip(tok->next, ";"); return node; } - - if (tok->kind == TK_IDENT && equal(tok->next, ":")) { + if (tok->kind == TK_IDENT && EQUAL(tok->next, ":")) { Node *node = new_node(ND_LABEL, tok); node->label = strndup(tok->loc, tok->len); node->unique_label = new_unique_name(); @@ -1733,9 +1813,7 @@ static Node *stmt(Token **rest, Token *tok) { labels = node; return node; } - - if (equal(tok, "{")) return compound_stmt(rest, tok->next); - + if (EQUAL(tok, "{")) return compound_stmt(rest, tok->next); return expr_stmt(rest, tok); } @@ -1744,38 +1822,30 @@ static Node *compound_stmt(Token **rest, Token *tok) { Node *node = new_node(ND_BLOCK, tok); Node head = {}; Node *cur = &head; - enter_scope(); - - while (!equal(tok, "}")) { - if (is_typename(tok) && !equal(tok->next, ":")) { + while (!EQUAL(tok, "}")) { + if (is_typename(tok) && !EQUAL(tok->next, ":")) { VarAttr attr = {}; Type *basety = typespec(&tok, tok, &attr); - if (attr.is_typedef) { tok = parse_typedef(tok, basety); continue; } - if (is_function(tok)) { tok = function(tok, basety, &attr); continue; } - if (attr.is_extern) { tok = global_variable(tok, basety, &attr); continue; } - cur = cur->next = declaration(&tok, tok, basety, &attr); } else { cur = cur->next = stmt(&tok, tok); } add_type(cur); } - leave_scope(); - node->body = head.next; *rest = tok->next; return node; @@ -1783,11 +1853,10 @@ static Node *compound_stmt(Token **rest, Token *tok) { // expr-stmt = expr? ";" static Node *expr_stmt(Token **rest, Token *tok) { - if (equal(tok, ";")) { + if (EQUAL(tok, ";")) { *rest = tok->next; return new_node(ND_BLOCK, tok); } - Node *node = new_node(ND_EXPR_STMT, tok); node->lhs = expr(&tok, tok); *rest = skip(tok, ";"); @@ -1795,17 +1864,16 @@ static Node *expr_stmt(Token **rest, Token *tok) { } // expr = assign ("," expr)? -static Node *expr(Token **rest, Token *tok) { +Node *expr(Token **rest, Token *tok) { Node *node = assign(&tok, tok); - - if (equal(tok, ",")) + if (EQUAL(tok, ",")) { return new_binary(ND_COMMA, node, expr(rest, tok->next), tok); - + } *rest = tok; return node; } -static int64_t eval(Node *node) { +int64_t eval(Node *node) { return eval2(node, NULL); } @@ -1815,11 +1883,9 @@ static int64_t eval(Node *node) { // is a pointer to a global variable and n is a postiive/negative // number. The latter form is accepted only as an initialization // expression for a global variable. -static int64_t eval2(Node *node, char ***label) { +int64_t eval2(Node *node, char ***label) { add_type(node); - if (is_flonum(node->ty)) return eval_double(node); - switch (node->kind) { case ND_ADD: return eval2(node->lhs, label) + eval(node->rhs); @@ -1907,7 +1973,6 @@ static int64_t eval2(Node *node, char ***label) { case ND_NUM: return node->val; } - error_tok(node->tok, "not a compile-time constant"); } @@ -1923,13 +1988,11 @@ static int64_t eval_rval(Node *node, char ***label) { case ND_MEMBER: return eval_rval(node->lhs, label) + node->member->offset; } - error_tok(node->tok, "invalid initializer"); } -static bool is_const_expr(Node *node) { +bool is_const_expr(Node *node) { add_type(node); - switch (node->kind) { case ND_ADD: case ND_SUB: @@ -1960,7 +2023,6 @@ static bool is_const_expr(Node *node) { case ND_NUM: return true; } - return false; } @@ -1971,12 +2033,12 @@ int64_t const_expr(Token **rest, Token *tok) { static double eval_double(Node *node) { add_type(node); - if (is_integer(node->ty)) { - if (node->ty->is_unsigned) return (unsigned long)eval(node); + if (node->ty->is_unsigned) { + return (unsigned long)eval(node); + } return eval(node); } - switch (node->kind) { case ND_ADD: return eval_double(node->lhs) + eval_double(node->rhs); @@ -1999,7 +2061,6 @@ static double eval_double(Node *node) { case ND_NUM: return node->fval; } - error_tok(node->tok, "not a compile-time constant"); } @@ -2013,29 +2074,22 @@ static Node *to_assign(Node *binary) { add_type(binary->lhs); add_type(binary->rhs); Token *tok = binary->tok; - // Convert `A.x op= C` to `tmp = &A, (*tmp).x = (*tmp).x op C`. if (binary->lhs->kind == ND_MEMBER) { Obj *var = new_lvar("", pointer_to(binary->lhs->lhs->ty)); - Node *expr1 = new_binary(ND_ASSIGN, new_var_node(var, tok), new_unary(ND_ADDR, binary->lhs->lhs, tok), tok); - Node *expr2 = new_unary( ND_MEMBER, new_unary(ND_DEREF, new_var_node(var, tok), tok), tok); expr2->member = binary->lhs->member; - Node *expr3 = new_unary( ND_MEMBER, new_unary(ND_DEREF, new_var_node(var, tok), tok), tok); expr3->member = binary->lhs->member; - Node *expr4 = new_binary(ND_ASSIGN, expr2, new_binary(binary->kind, expr3, binary->rhs, tok), tok); - return new_binary(ND_COMMA, expr1, expr4, tok); } - // If A is an atomic type, Convert `A op= B` to // // ({ @@ -2048,66 +2102,52 @@ static Node *to_assign(Node *binary) { if (binary->lhs->ty->is_atomic) { Node head = {}; Node *cur = &head; - Obj *addr = new_lvar("", pointer_to(binary->lhs->ty)); Obj *val = new_lvar("", binary->rhs->ty); Obj *old = new_lvar("", binary->lhs->ty); Obj *new = new_lvar("", binary->lhs->ty); - cur = cur->next = new_unary(ND_EXPR_STMT, new_binary(ND_ASSIGN, new_var_node(addr, tok), new_unary(ND_ADDR, binary->lhs, tok), tok), tok); - cur = cur->next = new_unary( ND_EXPR_STMT, new_binary(ND_ASSIGN, new_var_node(val, tok), binary->rhs, tok), tok); - cur = cur->next = new_unary( ND_EXPR_STMT, new_binary(ND_ASSIGN, new_var_node(old, tok), new_unary(ND_DEREF, new_var_node(addr, tok), tok), tok), tok); - Node *loop = new_node(ND_DO, tok); loop->brk_label = new_unique_name(); loop->cont_label = new_unique_name(); - Node *body = new_binary(ND_ASSIGN, new_var_node(new, tok), new_binary(binary->kind, new_var_node(old, tok), new_var_node(val, tok), tok), tok); - loop->then = new_node(ND_BLOCK, tok); loop->then->body = new_unary(ND_EXPR_STMT, body, tok); - Node *cas = new_node(ND_CAS, tok); cas->cas_addr = new_var_node(addr, tok); cas->cas_old = new_unary(ND_ADDR, new_var_node(old, tok), tok); cas->cas_new = new_var_node(new, tok); loop->cond = new_unary(ND_NOT, cas, tok); - cur = cur->next = loop; cur = cur->next = new_unary(ND_EXPR_STMT, new_var_node(new, tok), tok); - Node *node = new_node(ND_STMT_EXPR, tok); node->body = head.next; return node; } - // Convert `A op= B` to ``tmp = &A, *tmp = *tmp op B`. Obj *var = new_lvar("", pointer_to(binary->lhs->ty)); - Node *expr1 = new_binary(ND_ASSIGN, new_var_node(var, tok), new_unary(ND_ADDR, binary->lhs, tok), tok); - Node *expr2 = new_binary( ND_ASSIGN, new_unary(ND_DEREF, new_var_node(var, tok), tok), new_binary(binary->kind, new_unary(ND_DEREF, new_var_node(var, tok), tok), binary->rhs, tok), tok); - return new_binary(ND_COMMA, expr1, expr2, tok); } @@ -2116,40 +2156,28 @@ static Node *to_assign(Node *binary) { // | "<<=" | ">>=" static Node *assign(Token **rest, Token *tok) { Node *node = conditional(&tok, tok); - - if (equal(tok, "=")) + if (EQUAL(tok, "=")) return new_binary(ND_ASSIGN, node, assign(rest, tok->next), tok); - - if (equal(tok, "+=")) + if (EQUAL(tok, "+=")) return to_assign(new_add(node, assign(rest, tok->next), tok)); - - if (equal(tok, "-=")) + if (EQUAL(tok, "-=")) return to_assign(new_sub(node, assign(rest, tok->next), tok)); - - if (equal(tok, "*=")) + if (EQUAL(tok, "*=")) return to_assign(new_binary(ND_MUL, node, assign(rest, tok->next), tok)); - - if (equal(tok, "/=")) + if (EQUAL(tok, "/=")) return to_assign(new_binary(ND_DIV, node, assign(rest, tok->next), tok)); - - if (equal(tok, "%=")) + if (EQUAL(tok, "%=")) return to_assign(new_binary(ND_MOD, node, assign(rest, tok->next), tok)); - - if (equal(tok, "&=")) + if (EQUAL(tok, "&=")) return to_assign(new_binary(ND_BITAND, node, assign(rest, tok->next), tok)); - - if (equal(tok, "|=")) + if (EQUAL(tok, "|=")) return to_assign(new_binary(ND_BITOR, node, assign(rest, tok->next), tok)); - - if (equal(tok, "^=")) + if (EQUAL(tok, "^=")) return to_assign(new_binary(ND_BITXOR, node, assign(rest, tok->next), tok)); - - if (equal(tok, "<<=")) + if (EQUAL(tok, "<<=")) return to_assign(new_binary(ND_SHL, node, assign(rest, tok->next), tok)); - - if (equal(tok, ">>=")) + if (EQUAL(tok, ">>=")) return to_assign(new_binary(ND_SHR, node, assign(rest, tok->next), tok)); - *rest = tok; return node; } @@ -2157,13 +2185,11 @@ static Node *assign(Token **rest, Token *tok) { // conditional = logor ("?" expr? ":" conditional)? static Node *conditional(Token **rest, Token *tok) { Node *cond = logor(&tok, tok); - - if (!equal(tok, "?")) { + if (!EQUAL(tok, "?")) { *rest = tok; return cond; } - - if (equal(tok->next, ":")) { + if (EQUAL(tok->next, ":")) { // [GNU] Compile `a ?: b` as `tmp = a, tmp ? tmp : b`. add_type(cond); Obj *var = new_lvar("", cond->ty); @@ -2174,7 +2200,6 @@ static Node *conditional(Token **rest, Token *tok) { rhs->els = conditional(rest, tok->next->next); return new_binary(ND_COMMA, lhs, rhs, tok); } - Node *node = new_node(ND_COND, tok); node->cond = cond; node->then = expr(&tok, tok->next); @@ -2186,7 +2211,7 @@ static Node *conditional(Token **rest, Token *tok) { // logor = logand ("||" logand)* static Node *logor(Token **rest, Token *tok) { Node *node = logand(&tok, tok); - while (equal(tok, "||")) { + while (EQUAL(tok, "||")) { Token *start = tok; node = new_binary(ND_LOGOR, node, logand(&tok, tok->next), start); } @@ -2197,7 +2222,7 @@ static Node *logor(Token **rest, Token *tok) { // logand = bitor ("&&" bitor)* static Node *logand(Token **rest, Token *tok) { Node *node = bitor (&tok, tok); - while (equal(tok, "&&")) { + while (EQUAL(tok, "&&")) { Token *start = tok; node = new_binary(ND_LOGAND, node, bitor (&tok, tok->next), start); } @@ -2208,7 +2233,7 @@ static Node *logand(Token **rest, Token *tok) { // bitor = bitxor ("|" bitxor)* static Node * bitor (Token * *rest, Token *tok) { Node *node = bitxor(&tok, tok); - while (equal(tok, "|")) { + while (EQUAL(tok, "|")) { Token *start = tok; node = new_binary(ND_BITOR, node, bitxor(&tok, tok->next), start); } @@ -2219,7 +2244,7 @@ static Node * bitor (Token * *rest, Token *tok) { // bitxor = bitand ("^" bitand)* static Node *bitxor(Token **rest, Token *tok) { Node *node = bitand(&tok, tok); - while (equal(tok, "^")) { + while (EQUAL(tok, "^")) { Token *start = tok; node = new_binary(ND_BITXOR, node, bitand(&tok, tok->next), start); } @@ -2230,7 +2255,7 @@ static Node *bitxor(Token **rest, Token *tok) { // bitand = equality ("&" equality)* static Node *bitand(Token **rest, Token *tok) { Node *node = equality(&tok, tok); - while (equal(tok, "&")) { + while (EQUAL(tok, "&")) { Token *start = tok; node = new_binary(ND_BITAND, node, equality(&tok, tok->next), start); } @@ -2241,20 +2266,16 @@ static Node *bitand(Token **rest, Token *tok) { // equality = relational ("==" relational | "!=" relational)* static Node *equality(Token **rest, Token *tok) { Node *node = relational(&tok, tok); - for (;;) { Token *start = tok; - - if (equal(tok, "==")) { + if (EQUAL(tok, "==")) { node = new_binary(ND_EQ, node, relational(&tok, tok->next), start); continue; } - - if (equal(tok, "!=")) { + if (EQUAL(tok, "!=")) { node = new_binary(ND_NE, node, relational(&tok, tok->next), start); continue; } - *rest = tok; return node; } @@ -2263,30 +2284,24 @@ static Node *equality(Token **rest, Token *tok) { // relational = shift ("<" shift | "<=" shift | ">" shift | ">=" shift)* static Node *relational(Token **rest, Token *tok) { Node *node = shift(&tok, tok); - for (;;) { Token *start = tok; - - if (equal(tok, "<")) { + if (EQUAL(tok, "<")) { node = new_binary(ND_LT, node, shift(&tok, tok->next), start); continue; } - - if (equal(tok, "<=")) { + if (EQUAL(tok, "<=")) { node = new_binary(ND_LE, node, shift(&tok, tok->next), start); continue; } - - if (equal(tok, ">")) { + if (EQUAL(tok, ">")) { node = new_binary(ND_LT, shift(&tok, tok->next), node, start); continue; } - - if (equal(tok, ">=")) { + if (EQUAL(tok, ">=")) { node = new_binary(ND_LE, shift(&tok, tok->next), node, start); continue; } - *rest = tok; return node; } @@ -2295,20 +2310,16 @@ static Node *relational(Token **rest, Token *tok) { // shift = add ("<<" add | ">>" add)* static Node *shift(Token **rest, Token *tok) { Node *node = add(&tok, tok); - for (;;) { Token *start = tok; - - if (equal(tok, "<<")) { + if (EQUAL(tok, "<<")) { node = new_binary(ND_SHL, node, add(&tok, tok->next), start); continue; } - - if (equal(tok, ">>")) { + if (EQUAL(tok, ">>")) { node = new_binary(ND_SHR, node, add(&tok, tok->next), start); continue; } - *rest = tok; return node; } @@ -2322,27 +2333,22 @@ static Node *shift(Token **rest, Token *tok) { static Node *new_add(Node *lhs, Node *rhs, Token *tok) { add_type(lhs); add_type(rhs); - // num + num if (is_numeric(lhs->ty) && is_numeric(rhs->ty)) return new_binary(ND_ADD, lhs, rhs, tok); - if (lhs->ty->base && rhs->ty->base) error_tok(tok, "invalid operands"); - // Canonicalize `num + ptr` to `ptr + num`. if (!lhs->ty->base && rhs->ty->base) { Node *tmp = lhs; lhs = rhs; rhs = tmp; } - // VLA + num if (lhs->ty->base->kind == TY_VLA) { rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), tok); return new_binary(ND_ADD, lhs, rhs, tok); } - // ptr + num rhs = new_binary(ND_MUL, rhs, new_long(lhs->ty->base->size, tok), tok); return new_binary(ND_ADD, lhs, rhs, tok); @@ -2352,11 +2358,9 @@ static Node *new_add(Node *lhs, Node *rhs, Token *tok) { static Node *new_sub(Node *lhs, Node *rhs, Token *tok) { add_type(lhs); add_type(rhs); - // num - num if (is_numeric(lhs->ty) && is_numeric(rhs->ty)) return new_binary(ND_SUB, lhs, rhs, tok); - // VLA + num if (lhs->ty->base->kind == TY_VLA) { rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), @@ -2366,7 +2370,6 @@ static Node *new_sub(Node *lhs, Node *rhs, Token *tok) { node->ty = lhs->ty; return node; } - // ptr - num if (lhs->ty->base && is_integer(rhs->ty)) { rhs = new_binary(ND_MUL, rhs, new_long(lhs->ty->base->size, tok), tok); @@ -2375,34 +2378,28 @@ static Node *new_sub(Node *lhs, Node *rhs, Token *tok) { node->ty = lhs->ty; return node; } - // ptr - ptr, which returns how many elements are between the two. if (lhs->ty->base && rhs->ty->base) { Node *node = new_binary(ND_SUB, lhs, rhs, tok); node->ty = ty_long; return new_binary(ND_DIV, node, new_num(lhs->ty->base->size, tok), tok); } - error_tok(tok, "invalid operands"); } // add = mul ("+" mul | "-" mul)* static Node *add(Token **rest, Token *tok) { Node *node = mul(&tok, tok); - for (;;) { Token *start = tok; - - if (equal(tok, "+")) { + if (EQUAL(tok, "+")) { node = new_add(node, mul(&tok, tok->next), start); continue; } - - if (equal(tok, "-")) { + if (EQUAL(tok, "-")) { node = new_sub(node, mul(&tok, tok->next), start); continue; } - *rest = tok; return node; } @@ -2411,25 +2408,20 @@ static Node *add(Token **rest, Token *tok) { // mul = cast ("*" cast | "/" cast | "%" cast)* static Node *mul(Token **rest, Token *tok) { Node *node = cast(&tok, tok); - for (;;) { Token *start = tok; - - if (equal(tok, "*")) { + if (EQUAL(tok, "*")) { node = new_binary(ND_MUL, node, cast(&tok, tok->next), start); continue; } - - if (equal(tok, "/")) { + if (EQUAL(tok, "/")) { node = new_binary(ND_DIV, node, cast(&tok, tok->next), start); continue; } - - if (equal(tok, "%")) { + if (EQUAL(tok, "%")) { node = new_binary(ND_MOD, node, cast(&tok, tok->next), start); continue; } - *rest = tok; return node; } @@ -2453,20 +2445,17 @@ static Node *compound_literal(Token **rest, Token *tok, Type *ty, // | "(" type-name ")" cast // | unary static Node *cast(Token **rest, Token *tok) { - if (equal(tok, "(") && is_typename(tok->next)) { + if (EQUAL(tok, "(") && is_typename(tok->next)) { Token *start = tok; Type *ty = typename(&tok, tok->next); tok = skip(tok, ")"); - // compound literal - if (equal(tok, "{")) return compound_literal(rest, tok, ty, start); - + if (EQUAL(tok, "{")) return compound_literal(rest, tok, ty, start); // type cast Node *node = new_cast(cast(rest, tok), ty); node->tok = start; return node; } - return unary(rest, tok); } @@ -2475,19 +2464,16 @@ static Node *cast(Token **rest, Token *tok) { // | "&&" ident // | postfix static Node *unary(Token **rest, Token *tok) { - if (equal(tok, "+")) return cast(rest, tok->next); - - if (equal(tok, "-")) return new_unary(ND_NEG, cast(rest, tok->next), tok); - - if (equal(tok, "&")) { + if (EQUAL(tok, "+")) return cast(rest, tok->next); + if (EQUAL(tok, "-")) return new_unary(ND_NEG, cast(rest, tok->next), tok); + if (EQUAL(tok, "&")) { Node *lhs = cast(rest, tok->next); add_type(lhs); if (lhs->kind == ND_MEMBER && lhs->member->is_bitfield) error_tok(tok, "cannot take address of bitfield"); return new_unary(ND_ADDR, lhs, tok); } - - if (equal(tok, "*")) { + if (EQUAL(tok, "*")) { // [C18 6.5.3.2p4] This is an oddity in the C spec, but dereferencing // a function shouldn't do anything. If foo is a function, `*foo`, // `**foo` or `*****foo` are all equivalent to just `foo`. @@ -2496,21 +2482,16 @@ static Node *unary(Token **rest, Token *tok) { if (node->ty->kind == TY_FUNC) return node; return new_unary(ND_DEREF, node, tok); } - - if (equal(tok, "!")) return new_unary(ND_NOT, cast(rest, tok->next), tok); - - if (equal(tok, "~")) return new_unary(ND_BITNOT, cast(rest, tok->next), tok); - + if (EQUAL(tok, "!")) return new_unary(ND_NOT, cast(rest, tok->next), tok); + if (EQUAL(tok, "~")) return new_unary(ND_BITNOT, cast(rest, tok->next), tok); // Read ++i as i+=1 - if (equal(tok, "++")) + if (EQUAL(tok, "++")) return to_assign(new_add(unary(rest, tok->next), new_num(1, tok), tok)); - // Read --i as i-=1 - if (equal(tok, "--")) + if (EQUAL(tok, "--")) return to_assign(new_sub(unary(rest, tok->next), new_num(1, tok), tok)); - // [GNU] labels-as-values - if (equal(tok, "&&")) { + if (EQUAL(tok, "&&")) { Node *node = new_node(ND_LABEL_VAL, tok); node->label = get_ident(tok->next); node->goto_next = gotos; @@ -2518,7 +2499,6 @@ static Node *unary(Token **rest, Token *tok) { *rest = tok->next->next; return node; } - return postfix(rest, tok); } @@ -2527,15 +2507,13 @@ static void struct_members(Token **rest, Token *tok, Type *ty) { Member head = {}; Member *cur = &head; int idx = 0; - - while (!equal(tok, "}")) { + while (!EQUAL(tok, "}")) { VarAttr attr = {}; Type *basety = typespec(&tok, tok, &attr); bool first = true; - // Anonymous struct member if ((basety->kind == TY_STRUCT || basety->kind == TY_UNION) && - consume(&tok, tok, ";")) { + CONSUME(&tok, tok, ";")) { Member *mem = calloc(1, sizeof(Member)); mem->ty = basety; mem->idx = idx++; @@ -2543,27 +2521,22 @@ static void struct_members(Token **rest, Token *tok, Type *ty) { cur = cur->next = mem; continue; } - // Regular struct members - while (!consume(&tok, tok, ";")) { + while (!CONSUME(&tok, tok, ";")) { if (!first) tok = skip(tok, ","); first = false; - Member *mem = calloc(1, sizeof(Member)); mem->ty = declarator(&tok, tok, basety); mem->name = mem->ty->name; mem->idx = idx++; mem->align = attr.align ? attr.align : mem->ty->align; - - if (consume(&tok, tok, ":")) { + if (CONSUME(&tok, tok, ":")) { mem->is_bitfield = true; mem->bit_width = const_expr(&tok, tok); } - cur = cur->next = mem; } } - // If the last element is an array of incomplete type, it's // called a "flexible array member". It should behave as if // if were a zero-sized array. @@ -2571,73 +2544,42 @@ static void struct_members(Token **rest, Token *tok, Type *ty) { cur->ty = array_of(cur->ty->base, 0); ty->is_flexible = true; } - *rest = tok->next; ty->members = head.next; } -// attribute = ("__attribute__" "(" "(" "packed" ")" ")")* -static Token *attribute_list(Token *tok, Type *ty) { - while (consume(&tok, tok, "__attribute__")) { - tok = skip(tok, "("); - tok = skip(tok, "("); - - bool first = true; - - while (!consume(&tok, tok, ")")) { - if (!first) tok = skip(tok, ","); - first = false; - - if (consume(&tok, tok, "packed")) { - ty->is_packed = true; - continue; - } - - if (consume(&tok, tok, "aligned")) { - tok = skip(tok, "("); - ty->align = const_expr(&tok, tok); - tok = skip(tok, ")"); - continue; - } - - error_tok(tok, "unknown attribute"); - } - - tok = skip(tok, ")"); +char *ConsumeStringLiteral(Token **rest, Token *tok) { + char *s; + if (tok->kind != TK_STR || tok->ty->base->kind != TY_CHAR) { + error_tok(tok, "expected string literal"); } - - return tok; + s = tok->str; + *rest = tok->next; + return s; } // struct-union-decl = attribute? ident? ("{" struct-members)? static Type *struct_union_decl(Token **rest, Token *tok) { Type *ty = struct_type(); - tok = attribute_list(tok, ty); - + tok = attribute_list(tok, ty, type_attributes); // Read a tag. Token *tag = NULL; if (tok->kind == TK_IDENT) { tag = tok; tok = tok->next; } - - if (tag && !equal(tok, "{")) { + if (tag && !EQUAL(tok, "{")) { *rest = tok; - TagScope *sc = find_tag(tag); if (sc) return sc->ty; - ty->size = -1; push_tag_scope(tag, ty); return ty; } - tok = skip(tok, "{"); - // Construct a struct object. struct_members(&tok, tok, ty); - *rest = attribute_list(tok, ty); - + *rest = attribute_list(tok, ty, type_attributes); if (tag) { // If this is a redefinition, overwrite a previous type. // Otherwise, register the struct type. @@ -2646,10 +2588,8 @@ static Type *struct_union_decl(Token **rest, Token *tok) { *sc->ty = *ty; return sc->ty; } - push_tag_scope(tag, ty); } - return ty; } @@ -2657,35 +2597,34 @@ static Type *struct_union_decl(Token **rest, Token *tok) { static Type *struct_decl(Token **rest, Token *tok) { Type *ty = struct_union_decl(rest, tok); ty->kind = TY_STRUCT; - if (ty->size < 0) return ty; - // Assign offsets within the struct to members. int bits = 0; - - for (Member *mem = ty->members; mem; mem = mem->next) { - if (mem->is_bitfield && mem->bit_width == 0) { + for (Member *m = ty->members; m; m = m->next) { + if (m->is_bitfield && m->bit_width == 0) { // Zero-width anonymous bitfield has a special meaning. // It affects only alignment. - bits = align_to(bits, mem->ty->size * 8); - } else if (mem->is_bitfield) { - int sz = mem->ty->size; - if (bits / (sz * 8) != (bits + mem->bit_width - 1) / (sz * 8)) - bits = align_to(bits, sz * 8); - - mem->offset = align_down(bits / 8, sz); - mem->bit_offset = bits % (sz * 8); - bits += mem->bit_width; + bits = ROUNDUP(bits, m->ty->size * 8); + } else if (m->is_bitfield) { + int sz = m->ty->size; + if (bits / (sz * 8) != (bits + m->bit_width - 1) / (sz * 8)) { + bits = ROUNDUP(bits, sz * 8); + } + m->offset = ROUNDDOWN(bits / 8, sz); + m->bit_offset = bits % (sz * 8); + bits += m->bit_width; } else { - if (!ty->is_packed) bits = align_to(bits, mem->align * 8); - mem->offset = bits / 8; - bits += mem->ty->size * 8; + if (!ty->is_packed) { + bits = ROUNDUP(bits, m->align * 8); + } + m->offset = bits / 8; + bits += m->ty->size * 8; + } + if (!ty->is_packed && !ty->is_aligned && ty->align < m->align) { + ty->align = m->align; } - - if (!ty->is_packed && ty->align < mem->align) ty->align = mem->align; } - - ty->size = align_to(bits, ty->align * 8) / 8; + ty->size = ROUNDUP(bits, ty->align * 8) / 8; return ty; } @@ -2693,9 +2632,7 @@ static Type *struct_decl(Token **rest, Token *tok) { static Type *union_decl(Token **rest, Token *tok) { Type *ty = struct_union_decl(rest, tok); ty->kind = TY_UNION; - if (ty->size < 0) return ty; - // If union, we don't have to assign offsets because they // are already initialized to zero. We need to compute the // alignment and the size though. @@ -2703,7 +2640,7 @@ static Type *union_decl(Token **rest, Token *tok) { if (ty->align < mem->align) ty->align = mem->align; if (ty->size < mem->ty->size) ty->size = mem->ty->size; } - ty->size = align_to(ty->size, ty->align); + ty->size = ROUNDUP(ty->size, ty->align); return ty; } @@ -2716,11 +2653,11 @@ static Member *get_struct_member(Type *ty, Token *tok) { if (get_struct_member(mem->ty, tok)) return mem; continue; } - // Regular struct member if (mem->name->len == tok->len && - !strncmp(mem->name->loc, tok->loc, tok->len)) + !strncmp(mem->name->loc, tok->loc, tok->len)) { return mem; + } } return NULL; } @@ -2742,9 +2679,7 @@ static Node *struct_ref(Node *node, Token *tok) { add_type(node); if (node->ty->kind != TY_STRUCT && node->ty->kind != TY_UNION) error_tok(node->tok, "not a struct nor a union"); - Type *ty = node->ty; - for (;;) { Member *mem = get_struct_member(ty, tok); if (!mem) error_tok(tok, "no such member"); @@ -2775,14 +2710,12 @@ static Node *new_inc_dec(Node *node, Token *tok, int addend) { // | "--" static Node *postfix(Token **rest, Token *tok) { Node *node = primary(&tok, tok); - for (;;) { - if (equal(tok, "(")) { + if (EQUAL(tok, "(")) { node = funcall(&tok, tok->next, node); continue; } - - if (equal(tok, "[")) { + if (EQUAL(tok, "[")) { // x[y] is short for *(x+y) Token *start = tok; Node *idx = expr(&tok, tok->next); @@ -2790,33 +2723,28 @@ static Node *postfix(Token **rest, Token *tok) { node = new_unary(ND_DEREF, new_add(node, idx, start), start); continue; } - - if (equal(tok, ".")) { + if (EQUAL(tok, ".")) { node = struct_ref(node, tok->next); tok = tok->next->next; continue; } - - if (equal(tok, "->")) { + if (EQUAL(tok, "->")) { // x->y is short for (*x).y node = new_unary(ND_DEREF, node, tok); node = struct_ref(node, tok->next); tok = tok->next->next; continue; } - - if (equal(tok, "++")) { + if (EQUAL(tok, "++")) { node = new_inc_dec(node, tok, 1); tok = tok->next; continue; } - - if (equal(tok, "--")) { + if (EQUAL(tok, "--")) { node = new_inc_dec(node, tok, -1); tok = tok->next; continue; } - *rest = tok; return node; } @@ -2825,25 +2753,18 @@ static Node *postfix(Token **rest, Token *tok) { // funcall = (assign ("," assign)*)? ")" static Node *funcall(Token **rest, Token *tok, Node *fn) { add_type(fn); - if (fn->ty->kind != TY_FUNC && (fn->ty->kind != TY_PTR || fn->ty->base->kind != TY_FUNC)) error_tok(fn->tok, "not a function"); - Type *ty = (fn->ty->kind == TY_FUNC) ? fn->ty : fn->ty->base; Type *param_ty = ty->params; - Node head = {}; Node *cur = &head; - - while (!equal(tok, ")")) { + while (!EQUAL(tok, ")")) { if (cur != &head) tok = skip(tok, ","); - Node *arg = assign(&tok, tok); add_type(arg); - if (!param_ty && !ty->is_variadic) error_tok(tok, "too many arguments"); - if (param_ty) { if (param_ty->kind != TY_STRUCT && param_ty->kind != TY_UNION) arg = new_cast(arg, param_ty); @@ -2853,19 +2774,14 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) { // arguments are promoted to double. arg = new_cast(arg, ty_double); } - cur = cur->next = arg; } - if (param_ty) error_tok(tok, "too few arguments"); - *rest = skip(tok, ")"); - Node *node = new_unary(ND_FUNCALL, fn, tok); node->func_ty = ty; node->ty = ty->return_ty; node->args = head.next; - // If a function returns a struct, it is caller's responsibility // to allocate a space for the return value. if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION) @@ -2880,34 +2796,27 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) { static Node *generic_selection(Token **rest, Token *tok) { Token *start = tok; tok = skip(tok, "("); - Node *ctrl = assign(&tok, tok); add_type(ctrl); - Type *t1 = ctrl->ty; if (t1->kind == TY_FUNC) t1 = pointer_to(t1); else if (t1->kind == TY_ARRAY) t1 = pointer_to(t1->base); - Node *ret = NULL; - - while (!consume(rest, tok, ")")) { + while (!CONSUME(rest, tok, ")")) { tok = skip(tok, ","); - - if (equal(tok, "default")) { + if (EQUAL(tok, "default")) { tok = skip(tok->next, ":"); Node *node = assign(&tok, tok); if (!ret) ret = node; continue; } - Type *t2 = typename(&tok, tok); tok = skip(tok, ":"); Node *node = assign(&tok, tok); if (is_compatible(t1, t2)) ret = node; } - if (!ret) error_tok(start, "controlling expression type not compatible with" " any generic association type"); @@ -2921,67 +2830,67 @@ static Node *generic_selection(Token **rest, Token *tok) { // | "_Alignof" "(" type-name ")" // | "_Alignof" unary // | "_Generic" generic-selection -// | "__builtin_types_compatible_p" "(" type-name, type-name, ")" +// | "__builtin_constant_p" "(" expr ")" // | "__builtin_reg_class" "(" type-name ")" +// | "__builtin_types_compatible_p" "(" type-name, type-name, ")" // | ident // | str // | num static Node *primary(Token **rest, Token *tok) { Token *start = tok; - - if (equal(tok, "(") && equal(tok->next, "{")) { + if (EQUAL(tok, "(") && EQUAL(tok->next, "{")) { // This is a GNU statement expresssion. Node *node = new_node(ND_STMT_EXPR, tok); node->body = compound_stmt(&tok, tok->next->next)->body; *rest = skip(tok, ")"); return node; } - - if (equal(tok, "(")) { + if (EQUAL(tok, "(")) { Node *node = expr(&tok, tok->next); *rest = skip(tok, ")"); return node; } - - if (equal(tok, "sizeof") && equal(tok->next, "(") && + if (EQUAL(tok, "sizeof") && EQUAL(tok->next, "(") && is_typename(tok->next->next)) { Type *ty = typename(&tok, tok->next->next); *rest = skip(tok, ")"); - if (ty->kind == TY_VLA) { - if (ty->vla_size) return new_var_node(ty->vla_size, tok); - + if (ty->vla_size) { + return new_var_node(ty->vla_size, tok); + } Node *lhs = compute_vla_size(ty, tok); Node *rhs = new_var_node(ty->vla_size, tok); return new_binary(ND_COMMA, lhs, rhs, tok); } - return new_ulong(ty->size, start); } - - if (equal(tok, "sizeof")) { + if (EQUAL(tok, "sizeof")) { Node *node = unary(rest, tok->next); add_type(node); if (node->ty->kind == TY_VLA) return new_var_node(node->ty->vla_size, tok); return new_ulong(node->ty->size, tok); } - - if (equal(tok, "_Alignof") && equal(tok->next, "(") && + if (EQUAL(tok, "_Alignof") && EQUAL(tok->next, "(") && is_typename(tok->next->next)) { Type *ty = typename(&tok, tok->next->next); *rest = skip(tok, ")"); return new_ulong(ty->align, tok); } - - if (equal(tok, "_Alignof")) { + if (EQUAL(tok, "_Alignof")) { Node *node = unary(rest, tok->next); add_type(node); return new_ulong(node->ty->align, tok); } - - if (equal(tok, "_Generic")) return generic_selection(rest, tok->next); - - if (equal(tok, "__builtin_types_compatible_p")) { + if (EQUAL(tok, "_Generic")) { + return generic_selection(rest, tok->next); + } + if (EQUAL(tok, "__builtin_constant_p")) { + tok = skip(tok->next, "("); + Node *e = expr(&tok, tok); + *rest = skip(tok, ")"); + return new_num(is_const_expr(e), start); + } + if (EQUAL(tok, "__builtin_types_compatible_p")) { tok = skip(tok->next, "("); Type *t1 = typename(&tok, tok); tok = skip(tok, ","); @@ -2989,18 +2898,34 @@ static Node *primary(Token **rest, Token *tok) { *rest = skip(tok, ")"); return new_num(is_compatible(t1, t2), start); } - - if (equal(tok, "__builtin_reg_class")) { + if (EQUAL(tok, "__builtin_offsetof")) { + tok = skip(tok->next, "("); + Token *stok = tok; + Type *tstruct = typename(&tok, tok); + if (tstruct->kind != TY_STRUCT && tstruct->kind != TY_UNION) { + error_tok(stok, "not a structure or union type"); + } + tok = skip(tok, ","); + Token *member = tok; + tok = tok->next; + *rest = skip(tok, ")"); + for (Member *m = tstruct->members; m; m = m->next) { + if (m->name->len == member->len && + !memcmp(m->name->loc, member->loc, m->name->len)) { + return new_num(m->offset, start); + } + } + error_tok(member, "no such member"); + } + if (EQUAL(tok, "__builtin_reg_class")) { tok = skip(tok->next, "("); Type *ty = typename(&tok, tok); *rest = skip(tok, ")"); - if (is_integer(ty) || ty->kind == TY_PTR) return new_num(0, start); if (is_flonum(ty)) return new_num(1, start); return new_num(2, start); } - - if (equal(tok, "__builtin_compare_and_swap")) { + if (EQUAL(tok, "__builtin_compare_and_swap")) { Node *node = new_node(ND_CAS, tok); tok = skip(tok->next, "("); node->cas_addr = assign(&tok, tok); @@ -3011,8 +2936,7 @@ static Node *primary(Token **rest, Token *tok) { *rest = skip(tok, ")"); return node; } - - if (equal(tok, "__builtin_atomic_exchange")) { + if (EQUAL(tok, "__builtin_atomic_exchange")) { Node *node = new_node(ND_EXCH, tok); tok = skip(tok->next, "("); node->lhs = assign(&tok, tok); @@ -3021,12 +2945,35 @@ static Node *primary(Token **rest, Token *tok) { *rest = skip(tok, ")"); return node; } - + if (EQUAL(tok, "__builtin_fpclassify")) { + Node *node = new_node(ND_FPCLASSIFY, tok); + node->fpc = calloc(1, sizeof(FpClassify)); + node->ty = ty_int; + tok = skip(tok->next, "("); + for (int i = 0; i < 5; ++i) { + node->fpc->args[i] = const_expr(&tok, tok); + tok = skip(tok, ","); + } + node->fpc->node = expr(&tok, tok); + add_type(node->fpc->node); + if (!is_flonum(node->fpc->node->ty)) { + error_tok(node->fpc->node->tok, "need floating point"); + } + *rest = skip(tok, ")"); + return node; + } + if (EQUAL(tok, "__builtin_popcount") || EQUAL(tok, "__builtin_popcountl") || + EQUAL(tok, "__builtin_popcountll")) { + Token *t = skip(tok->next, "("); + if (t->kind == TK_NUM && is_integer(t->ty)) { + *rest = skip(t->next, ")"); + return new_num(popcnt(t->val), t); + } + } if (tok->kind == TK_IDENT) { // Variable or enum constant VarScope *sc = find_var(tok); *rest = tok->next; - // For "static inline" function if (sc && sc->var && sc->var->is_function) { if (current_fn) @@ -3034,23 +2981,19 @@ static Node *primary(Token **rest, Token *tok) { else sc->var->is_root = true; } - if (sc) { if (sc->var) return new_var_node(sc->var, tok); if (sc->enum_ty) return new_num(sc->enum_val, tok); } - - if (equal(tok->next, "(")) + if (EQUAL(tok->next, "(")) error_tok(tok, "implicit declaration of a function"); error_tok(tok, "undefined variable"); } - if (tok->kind == TK_STR) { Obj *var = new_string_literal(tok->str, tok->ty); *rest = tok->next; return new_var_node(var, tok); } - if (tok->kind == TK_NUM) { Node *node; if (is_flonum(tok->ty)) { @@ -3059,24 +3002,21 @@ static Node *primary(Token **rest, Token *tok) { } else { node = new_num(tok->val, tok); } - node->ty = tok->ty; *rest = tok->next; return node; } - error_tok(tok, "expected an expression"); } static Token *parse_typedef(Token *tok, Type *basety) { bool first = true; - - while (!consume(&tok, tok, ";")) { + while (!CONSUME(&tok, tok, ";")) { if (!first) tok = skip(tok, ","); first = false; - Type *ty = declarator(&tok, tok, basety); if (!ty->name) error_tok(ty->name_pos, "typedef name omitted"); + tok = attribute_list(tok, ty, type_attributes); push_scope(get_ident(ty->name))->type_def = ty; } return tok; @@ -3103,18 +3043,15 @@ static void resolve_goto_labels(void) { break; } } - if (x->unique_label == NULL) error_tok(x->tok->next, "use of undeclared label"); } - gotos = labels = NULL; } static Obj *find_func(char *name) { Scope *sc = scope; while (sc->next) sc = sc->next; - VarScope *sc2 = hashmap_get(&sc->vars, name); if (sc2 && sc2->var && sc2->var->is_function) return sc2->var; return NULL; @@ -3123,7 +3060,6 @@ static Obj *find_func(char *name) { static void mark_live(Obj *var) { if (!var->is_function || var->is_live) return; var->is_live = true; - for (int i = 0; i < var->refs.len; i++) { Obj *fn = find_func(var->refs.data[i]); if (fn) mark_live(fn); @@ -3134,57 +3070,63 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) { Type *ty = declarator(&tok, tok, basety); if (!ty->name) error_tok(ty->name_pos, "function name omitted"); char *name_str = get_ident(ty->name); - Obj *fn = find_func(name_str); if (fn) { // Redeclaration if (!fn->is_function) error_tok(tok, "redeclared as a different kind of symbol"); - if (fn->is_definition && equal(tok, "{")) + if (fn->is_definition && EQUAL(tok, "{")) error_tok(tok, "redefinition of %s", name_str); if (!fn->is_static && attr->is_static) error_tok(tok, "static declaration follows a non-static declaration"); - fn->is_definition = fn->is_definition || equal(tok, "{"); + fn->is_definition = fn->is_definition || EQUAL(tok, "{"); + fn->is_weak |= attr->is_weak; + fn->is_noreturn |= attr->is_noreturn; } else { fn = new_gvar(name_str, ty); fn->is_function = true; - fn->is_definition = equal(tok, "{"); + fn->is_definition = EQUAL(tok, "{"); fn->is_static = attr->is_static || (attr->is_inline && !attr->is_extern); fn->is_inline = attr->is_inline; + fn->is_weak = attr->is_weak; + fn->is_aligned = attr->is_aligned; + fn->is_noreturn = attr->is_noreturn; + fn->is_destructor = attr->is_destructor; + fn->is_constructor = attr->is_constructor; + fn->is_externally_visible = attr->is_externally_visible; + fn->align = attr->align; + fn->section = attr->section; + fn->visibility = attr->visibility; } - fn->is_root = !(fn->is_static && fn->is_inline); - - if (consume(&tok, tok, ";")) return tok; - + if (consume_attribute(&tok, tok, "asm")) { + tok = skip(tok, "("); + fn->asmname = ConsumeStringLiteral(&tok, tok); + tok = skip(tok, ")"); + } + tok = attribute_list(tok, &attr, thing_attributes); + if (CONSUME(&tok, tok, ";")) return tok; current_fn = fn; locals = NULL; enter_scope(); create_param_lvars(ty->params); - // A buffer for a struct/union return value is passed // as the hidden first parameter. Type *rty = ty->return_ty; if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16) new_lvar("", pointer_to(rty)); - fn->params = locals; - if (ty->is_variadic) fn->va_area = new_lvar("__va_area__", array_of(ty_char, 136)); fn->alloca_bottom = new_lvar("__alloca_size__", pointer_to(ty_char)); - tok = skip(tok, "{"); - // [C18 6.4.2.2] "__func__" is automatically defined as a // local variable containing the current function name. push_scope("__func__")->var = new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1)); - // [GNU] __FUNCTION__ is yet another name of __func__. push_scope("__FUNCTION__")->var = new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1)); - fn->body = compound_stmt(&tok, tok); fn->locals = locals; leave_scope(); @@ -3194,24 +3136,27 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) { static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) { bool first = true; - - while (!consume(&tok, tok, ";")) { + while (!CONSUME(&tok, tok, ";")) { if (!first) tok = skip(tok, ","); first = false; - Type *ty = declarator(&tok, tok, basety); if (!ty->name) error_tok(ty->name_pos, "variable name omitted"); - Obj *var = new_gvar(get_ident(ty->name), ty); + if (consume_attribute(&tok, tok, "asm")) { + tok = skip(tok, "("); + var->asmname = ConsumeStringLiteral(&tok, tok); + tok = skip(tok, ")"); + } + /* tok = attribute_list(tok, &attr, thing_attributes); */ var->is_definition = !attr->is_extern; var->is_static = attr->is_static; var->is_tls = attr->is_tls; if (attr->align) var->align = attr->align; - - if (equal(tok, "=")) + if (EQUAL(tok, "=")) { gvar_initializer(&tok, tok->next, var); - else if (!attr->is_extern) + } else if (!attr->is_extern) { var->is_tentative = true; + } } return tok; } @@ -3219,8 +3164,7 @@ static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) { // Lookahead tokens and returns true if a given token is a start // of a function definition or declaration. static bool is_function(Token *tok) { - if (equal(tok, ";")) return false; - + if (EQUAL(tok, ";")) return false; Type dummy = {}; Type *ty = declarator(&tok, tok, &dummy); return ty->kind == TY_FUNC; @@ -3230,72 +3174,133 @@ static bool is_function(Token *tok) { static void scan_globals(void) { Obj head; Obj *cur = &head; - for (Obj *var = globals; var; var = var->next) { if (!var->is_tentative) { cur = cur->next = var; continue; } - // Find another definition of the same identifier. Obj *var2 = globals; - for (; var2; var2 = var2->next) - if (var != var2 && var2->is_definition && !strcmp(var->name, var2->name)) + for (; var2; var2 = var2->next) { + if (var != var2 && var2->is_definition && + !strcmp(var->name, var2->name)) { break; - + } + } // If there's another definition, the tentative definition // is redundant if (!var2) cur = cur->next = var; } - cur->next = NULL; globals = head.next; } -static void declare_builtin_functions(void) { - Type *ty = func_type(pointer_to(ty_void)); - ty->params = copy_type(ty_int); - builtin_alloca = new_gvar("alloca", ty); - builtin_alloca->is_definition = false; +static Obj *declare1(char *name, Type *ret, Type *p1) { + Type *ty = func_type(ret); + ty->params = copy_type(p1); + return new_gvar(name, ty); +} + +static Obj *declare_builtin0(char *name, Type *ret) { + return new_gvar(xstrcat("__builtin_", name), func_type(ret)); +} + +static Obj *declare_builtin1(char *name, Type *ret, Type *p1) { + return declare1(xstrcat("__builtin_", name), ret, p1); +} + +static Obj *declare_builtin2(char *name, Type *ret, Type *p1, Type *p2) { + Type *ty = func_type(ret); + ty->params = copy_type(p1); + ty->params->next = copy_type(p2); + return new_gvar(xstrcat("__builtin_", name), ty); +} + +static Obj *declare_builtin3(char *s, Type *r, Type *a, Type *b, Type *c) { + Type *ty = func_type(r); + ty->params = copy_type(a); + ty->params->next = copy_type(b); + ty->params->next->next = copy_type(c); + return new_gvar(xstrcat("__builtin_", s), ty); +} + +void declare_builtin_functions(void) { + Type *pvoid = pointer_to(ty_void); + Type *pchar = pointer_to(ty_char); + builtin_alloca = declare1("alloca", pointer_to(ty_void), ty_int); + declare_builtin0("trap", ty_int); + declare_builtin0("unreachable", ty_int); + declare_builtin0("inff", ty_float); + declare_builtin0("inf", ty_double); + declare_builtin0("infl", ty_ldouble); + declare_builtin1("ctz", ty_int, ty_int); + declare_builtin1("ctzl", ty_long, ty_long); + declare_builtin1("ctzll", ty_long, ty_long); + declare_builtin1("clz", ty_int, ty_int); + declare_builtin1("clzl", ty_long, ty_long); + declare_builtin1("clzll", ty_long, ty_long); + declare_builtin1("ffs", ty_int, ty_int); + declare_builtin1("ffsl", ty_int, ty_long); + declare_builtin1("ffsll", ty_int, ty_long); + declare_builtin1("bswap16", ty_ushort, ty_ushort); + declare_builtin1("bswap32", ty_uint, ty_uint); + declare_builtin1("bswap64", ty_ulong, ty_ulong); + declare_builtin1("popcount", ty_int, ty_uint); + declare_builtin1("popcountl", ty_long, ty_ulong); + declare_builtin1("popcountll", ty_long, ty_ulong); + declare_builtin1("signbitf", ty_int, ty_float); + declare_builtin1("signbit", ty_long, ty_double); + declare_builtin1("signbitl", ty_int, ty_ldouble); + declare_builtin1("nanf", ty_float, pchar); + declare_builtin1("nan", ty_double, pchar); + declare_builtin1("nanl", ty_ldouble, pchar); + declare_builtin1("isnan", ty_int, ty_double); + declare_builtin1("isinf", ty_int, ty_double); + declare_builtin1("isfinite", ty_int, ty_double); + declare_builtin2("isgreater", ty_int, ty_double, ty_double); + declare_builtin2("isgreaterequal", ty_int, ty_double, ty_double); + declare_builtin2("isless", ty_int, ty_double, ty_double); + declare_builtin2("islessequal", ty_int, ty_double, ty_double); + declare_builtin2("islessgreater", ty_int, ty_double, ty_double); + declare_builtin2("isunordered", ty_int, ty_double, ty_double); + declare_builtin2("strpbrk", pchar, pchar, pchar); + declare_builtin3("memcpy", pvoid, pvoid, pvoid, ty_ulong); + declare_builtin3("memset", pvoid, pvoid, ty_int, ty_ulong); + declare_builtin1("strlen", ty_ulong, pchar); + declare_builtin2("strchr", pchar, pchar, ty_int); + declare_builtin2("strstr", pchar, pchar, pchar); } // program = (typedef | function-definition | global-variable)* Obj *parse(Token *tok) { declare_builtin_functions(); globals = NULL; - while (tok->kind != TK_EOF) { - if (equal(tok, "asm") || equal(tok, "__asm__")) { + if (EQUAL(tok, "asm") || EQUAL(tok, "__asm__")) { StaticAsm *a = calloc(1, sizeof(StaticAsm)); a->next = staticasms; a->body = asm_stmt(&tok, tok); staticasms = a; continue; } - VarAttr attr = {}; + tok = attribute_list(tok, &attr, thing_attributes); Type *basety = typespec(&tok, tok, &attr); - - // Typedef if (attr.is_typedef) { tok = parse_typedef(tok, basety); continue; } - - // Function if (is_function(tok)) { tok = function(tok, basety, &attr); continue; } - - // Global variable tok = global_variable(tok, basety, &attr); } - - for (Obj *var = globals; var; var = var->next) - if (var->is_root) mark_live(var); - - // Remove redundant tentative definitions. - scan_globals(); + for (Obj *var = globals; var; var = var->next) { + if (var->is_root) { + mark_live(var); + } + } + scan_globals(); // remove redundant tentative definitions return globals; } diff --git a/third_party/chibicc/preprocess.c b/third_party/chibicc/preprocess.c index fd3a9f60..44452084 100644 --- a/third_party/chibicc/preprocess.c +++ b/third_party/chibicc/preprocess.c @@ -24,13 +24,27 @@ #include "third_party/chibicc/chibicc.h" +typedef struct CondIncl CondIncl; +typedef struct Hideset Hideset; +typedef struct Macro Macro; +typedef struct MacroArg MacroArg; typedef struct MacroParam MacroParam; + +typedef Token *macro_handler_fn(Token *); + +typedef enum { + STR_NONE, + STR_UTF8, + STR_UTF16, + STR_UTF32, + STR_WIDE, +} StringKind; + struct MacroParam { MacroParam *next; char *name; }; -typedef struct MacroArg MacroArg; struct MacroArg { MacroArg *next; char *name; @@ -38,9 +52,6 @@ struct MacroArg { Token *tok; }; -typedef Token *macro_handler_fn(Token *); - -typedef struct Macro Macro; struct Macro { char *name; bool is_objlike; // Object-like or function-like @@ -51,7 +62,6 @@ struct Macro { }; // `#if` can be nested, so we use a stack to manage nested `#if`s. -typedef struct CondIncl CondIncl; struct CondIncl { CondIncl *next; enum { IN_THEN, IN_ELIF, IN_ELSE } ctx; @@ -59,7 +69,6 @@ struct CondIncl { bool included; }; -typedef struct Hideset Hideset; struct Hideset { Hideset *next; char *name; @@ -70,20 +79,11 @@ static CondIncl *cond_incl; static HashMap pragma_once; static int include_next_idx; -static Token *preprocess2(Token *tok); -static Macro *find_macro(Token *tok); - -char *format(char *fmt, ...) { - char *res; - va_list va; - va_start(va, fmt); - res = xvasprintf(fmt, va); - va_end(va); - return res; -} +static Token *preprocess2(Token *); +static Macro *find_macro(Token *); static bool is_hash(Token *tok) { - return tok->at_bol && equal(tok, "#"); + return tok->at_bol && EQUAL(tok, "#"); } // Some preprocessor directives such as #include allow extraneous @@ -118,23 +118,30 @@ static Hideset *new_hideset(char *name) { static Hideset *hideset_union(Hideset *hs1, Hideset *hs2) { Hideset head = {}; Hideset *cur = &head; - for (; hs1; hs1 = hs1->next) cur = cur->next = new_hideset(hs1->name); + for (; hs1; hs1 = hs1->next) { + cur = cur->next = new_hideset(hs1->name); + } cur->next = hs2; return head.next; } static bool hideset_contains(Hideset *hs, char *s, int len) { - for (; hs; hs = hs->next) - if (strlen(hs->name) == len && !strncmp(hs->name, s, len)) return true; + for (; hs; hs = hs->next) { + if (strlen(hs->name) == len && !strncmp(hs->name, s, len)) { + return true; + } + } return false; } static Hideset *hideset_intersection(Hideset *hs1, Hideset *hs2) { Hideset head = {}; Hideset *cur = &head; - for (; hs1; hs1 = hs1->next) - if (hideset_contains(hs2, hs1->name, strlen(hs1->name))) + for (; hs1; hs1 = hs1->next) { + if (hideset_contains(hs2, hs1->name, strlen(hs1->name))) { cur = cur->next = new_hideset(hs1->name); + } + } return head.next; } @@ -162,12 +169,12 @@ static Token *append(Token *tok1, Token *tok2) { static Token *skip_cond_incl2(Token *tok) { while (tok->kind != TK_EOF) { - if (is_hash(tok) && (equal(tok->next, "if") || equal(tok->next, "ifdef") || - equal(tok->next, "ifndef"))) { + if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") || + EQUAL(tok->next, "ifndef"))) { tok = skip_cond_incl2(tok->next->next); continue; } - if (is_hash(tok) && equal(tok->next, "endif")) return tok->next->next; + if (is_hash(tok) && EQUAL(tok->next, "endif")) return tok->next->next; tok = tok->next; } return tok; @@ -177,13 +184,13 @@ static Token *skip_cond_incl2(Token *tok) { // Nested `#if` and `#endif` are skipped. static Token *skip_cond_incl(Token *tok) { while (tok->kind != TK_EOF) { - if (is_hash(tok) && (equal(tok->next, "if") || equal(tok->next, "ifdef") || - equal(tok->next, "ifndef"))) { + if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") || + EQUAL(tok->next, "ifndef"))) { tok = skip_cond_incl2(tok->next->next); continue; } - if (is_hash(tok) && (equal(tok->next, "elif") || equal(tok->next, "else") || - equal(tok->next, "endif"))) + if (is_hash(tok) && (EQUAL(tok->next, "elif") || EQUAL(tok->next, "else") || + EQUAL(tok->next, "endif"))) break; tok = tok->next; } @@ -239,9 +246,9 @@ static Token *read_const_expr(Token **rest, Token *tok) { while (tok->kind != TK_EOF) { // "defined(foo)" or "defined foo" becomes "1" if macro "foo" // is defined. Otherwise "0". - if (equal(tok, "defined")) { + if (EQUAL(tok, "defined")) { Token *start = tok; - bool has_paren = consume(&tok, tok->next, "("); + bool has_paren = CONSUME(&tok, tok->next, "("); if (tok->kind != TK_IDENT) error_tok(start, "macro name must be an identifier"); Macro *m = find_macro(tok); @@ -310,15 +317,15 @@ static MacroParam *read_macro_params(Token **rest, Token *tok, char **va_args_name) { MacroParam head = {}; MacroParam *cur = &head; - while (!equal(tok, ")")) { + while (!EQUAL(tok, ")")) { if (cur != &head) tok = skip(tok, ","); - if (equal(tok, "...")) { + if (EQUAL(tok, "...")) { *va_args_name = "__VA_ARGS__"; *rest = skip(tok->next, ")"); return head.next; } if (tok->kind != TK_IDENT) error_tok(tok, "expected an identifier"); - if (equal(tok->next, "...")) { + if (EQUAL(tok->next, "...")) { *va_args_name = strndup(tok->loc, tok->len); *rest = skip(tok->next->next, ")"); return head.next; @@ -336,7 +343,7 @@ static void read_macro_definition(Token **rest, Token *tok) { if (tok->kind != TK_IDENT) error_tok(tok, "macro name must be an identifier"); char *name = strndup(tok->loc, tok->len); tok = tok->next; - if (!tok->has_space && equal(tok, "(")) { + if (!tok->has_space && EQUAL(tok, "(")) { // Function-like macro char *va_args_name = NULL; MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name); @@ -354,12 +361,12 @@ static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) { Token *cur = &head; int level = 0; for (;;) { - if (level == 0 && equal(tok, ")")) break; - if (level == 0 && !read_rest && equal(tok, ",")) break; + if (level == 0 && EQUAL(tok, ")")) break; + if (level == 0 && !read_rest && EQUAL(tok, ",")) break; if (tok->kind == TK_EOF) error_tok(tok, "premature end of input"); - if (equal(tok, "(")) + if (EQUAL(tok, "(")) level++; - else if (equal(tok, ")")) + else if (EQUAL(tok, ")")) level--; cur = cur->next = copy_token(tok); tok = tok->next; @@ -385,7 +392,7 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params, } if (va_args_name) { MacroArg *arg; - if (equal(tok, ")")) { + if (EQUAL(tok, ")")) { arg = calloc(1, sizeof(MacroArg)); arg->tok = new_eof(tok); } else { @@ -454,8 +461,11 @@ static Token *paste(Token *lhs, Token *rhs) { } static bool has_varargs(MacroArg *args) { - for (MacroArg *ap = args; ap; ap = ap->next) - if (!strcmp(ap->name, "__VA_ARGS__")) return ap->tok->kind != TK_EOF; + for (MacroArg *ap = args; ap; ap = ap->next) { + if (!strcmp(ap->name, "__VA_ARGS__")) { + return ap->tok->kind != TK_EOF; + } + } return false; } @@ -463,10 +473,9 @@ static bool has_varargs(MacroArg *args) { static Token *subst(Token *tok, MacroArg *args) { Token head = {}; Token *cur = &head; - while (tok->kind != TK_EOF) { // "#" followed by a parameter is replaced with stringized actuals. - if (equal(tok, "#")) { + if (EQUAL(tok, "#")) { MacroArg *arg = find_arg(args, tok->next); if (!arg) error_tok(tok->next, "'#' is not followed by a macro parameter"); @@ -474,11 +483,10 @@ static Token *subst(Token *tok, MacroArg *args) { tok = tok->next->next; continue; } - // [GNU] If __VA_ARG__ is empty, `,##__VA_ARGS__` is expanded // to the empty token list. Otherwise, its expaned to `,` and // __VA_ARGS__. - if (equal(tok, ",") && equal(tok->next, "##")) { + if (EQUAL(tok, ",") && EQUAL(tok->next, "##")) { MacroArg *arg = find_arg(args, tok->next->next); if (arg && arg->is_va_args) { if (arg->tok->kind == TK_EOF) { @@ -490,14 +498,11 @@ static Token *subst(Token *tok, MacroArg *args) { continue; } } - - if (equal(tok, "##")) { + if (EQUAL(tok, "##")) { if (cur == &head) error_tok(tok, "'##' cannot appear at start of macro expansion"); - if (tok->next->kind == TK_EOF) error_tok(tok, "'##' cannot appear at end of macro expansion"); - MacroArg *arg = find_arg(args, tok->next); if (arg) { if (arg->tok->kind != TK_EOF) { @@ -508,17 +513,13 @@ static Token *subst(Token *tok, MacroArg *args) { tok = tok->next->next; continue; } - *cur = *paste(cur, tok->next); tok = tok->next->next; continue; } - MacroArg *arg = find_arg(args, tok); - - if (arg && equal(tok->next, "##")) { + if (arg && EQUAL(tok->next, "##")) { Token *rhs = tok->next->next; - if (arg->tok->kind == TK_EOF) { MacroArg *arg2 = find_arg(args, rhs); if (arg2) { @@ -530,16 +531,14 @@ static Token *subst(Token *tok, MacroArg *args) { tok = rhs->next; continue; } - for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next) cur = cur->next = copy_token(t); tok = tok->next; continue; } - // If __VA_ARG__ is empty, __VA_OPT__(x) is expanded to the // empty token list. Otherwise, __VA_OPT__(x) is expanded to x. - if (equal(tok, "__VA_OPT__") && equal(tok->next, "(")) { + if (EQUAL(tok, "__VA_OPT__") && EQUAL(tok->next, "(")) { MacroArg *arg = read_macro_arg_one(&tok, tok->next->next, true); if (has_varargs(args)) for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next) @@ -547,7 +546,6 @@ static Token *subst(Token *tok, MacroArg *args) { tok = skip(tok, ")"); continue; } - // Handle a macro token. Macro arguments are completely macro-expanded // before they are substituted into a macro body. if (arg) { @@ -558,13 +556,11 @@ static Token *subst(Token *tok, MacroArg *args) { tok = tok->next; continue; } - // Handle a non-macro token. cur = cur->next = copy_token(tok); tok = tok->next; continue; } - cur->next = tok; return head.next; } @@ -585,7 +581,9 @@ static bool expand_macro(Token **rest, Token *tok) { if (m->is_objlike) { Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name)); Token *body = add_hideset(m->body, hs); - for (Token *t = body; t->kind != TK_EOF; t = t->next) t->origin = tok; + for (Token *t = body; t->kind != TK_EOF; t = t->next) { + t->origin = tok; + } *rest = append(body, tok->next); (*rest)->at_bol = tok->at_bol; (*rest)->has_space = tok->has_space; @@ -593,7 +591,7 @@ static bool expand_macro(Token **rest, Token *tok) { } // If a funclike macro token is not followed by an argument list, // treat it as a normal identifier. - if (!equal(tok->next, "(")) return false; + if (!EQUAL(tok->next, "(")) return false; // Function-like macro application Token *macro_token = tok; MacroArg *args = read_macro_args(&tok, tok, m->params, m->va_args_name); @@ -614,12 +612,6 @@ static bool expand_macro(Token **rest, Token *tok) { return true; } -// Returns true if a given file exists. -bool file_exists(char *path) { - struct stat st; - return !stat(path, &st); -} - char *search_include_paths(char *filename) { if (filename[0] == '/') return filename; static HashMap cache; @@ -627,8 +619,8 @@ char *search_include_paths(char *filename) { if (cached) return cached; // Search a file from the include paths. for (int i = 0; i < include_paths.len; i++) { - char *path = format("%s/%s", include_paths.data[i], filename); - if (!file_exists(path)) continue; + char *path = xasprintf("%s/%s", include_paths.data[i], filename); + if (!fileexists(path)) continue; hashmap_put(&cache, filename, path); include_next_idx = i + 1; return path; @@ -639,8 +631,8 @@ char *search_include_paths(char *filename) { static char *search_include_next(char *filename) { for (; include_next_idx < include_paths.len; include_next_idx++) { char *path = - format("%s/%s", include_paths.data[include_next_idx], filename); - if (file_exists(path)) return path; + xasprintf("%s/%s", include_paths.data[include_next_idx], filename); + if (fileexists(path)) return path; } return NULL; } @@ -659,12 +651,12 @@ static char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) { return strndup(tok->loc + 1, tok->len - 2); } // Pattern 2: #include - if (equal(tok, "<")) { + if (EQUAL(tok, "<")) { // Reconstruct a filename from a sequence of tokens between // "<" and ">". Token *start = tok; // Find closing ">". - for (; !equal(tok, ">"); tok = tok->next) + for (; !EQUAL(tok, ">"); tok = tok->next) if (tok->at_bol || tok->kind == TK_EOF) error_tok(tok, "expected '>'"); *is_dquote = false; *rest = skip_line(tok->next); @@ -688,13 +680,13 @@ static char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) { // #endif static char *detect_include_guard(Token *tok) { // Detect the first two lines. - if (!is_hash(tok) || !equal(tok->next, "ifndef")) return NULL; + if (!is_hash(tok) || !EQUAL(tok->next, "ifndef")) return NULL; tok = tok->next->next; if (tok->kind != TK_IDENT) return NULL; char *macro = strndup(tok->loc, tok->len); tok = tok->next; - if (!is_hash(tok) || !equal(tok->next, "define") || - !equal(tok->next->next, macro)) + if (!is_hash(tok) || !EQUAL(tok->next, "define") || + !EQUAL(tok->next->next, macro)) return NULL; // Read until the end of the file. while (tok->kind != TK_EOF) { @@ -702,9 +694,9 @@ static char *detect_include_guard(Token *tok) { tok = tok->next; continue; } - if (equal(tok->next, "endif") && tok->next->next->kind == TK_EOF) + if (EQUAL(tok->next, "endif") && tok->next->next->kind == TK_EOF) return macro; - if (equal(tok, "if") || equal(tok, "ifdef") || equal(tok, "ifndef")) + if (EQUAL(tok, "if") || EQUAL(tok, "ifdef") || EQUAL(tok, "ifndef")) tok = skip_cond_incl(tok->next); else tok = tok->next; @@ -732,14 +724,11 @@ static Token *include_file(Token *tok, char *path) { static void read_line_marker(Token **rest, Token *tok) { Token *start = tok; tok = preprocess(copy_line(rest, tok)); - if (tok->kind != TK_NUM || tok->ty->kind != TY_INT) error_tok(tok, "invalid line marker"); start->file->line_delta = tok->val - start->line_no; - tok = tok->next; if (tok->kind == TK_EOF) return; - if (tok->kind != TK_STR) error_tok(tok, "filename expected"); start->file->display_name = tok->str; } @@ -749,11 +738,9 @@ static void read_line_marker(Token **rest, Token *tok) { static Token *preprocess2(Token *tok) { Token head = {}; Token *cur = &head; - while (tok->kind != TK_EOF) { // If it is a macro, expand it. if (expand_macro(&tok, tok)) continue; - // Pass through if it is not a "#". if (!is_hash(tok)) { tok->line_delta = tok->file->line_delta; @@ -762,42 +749,35 @@ static Token *preprocess2(Token *tok) { tok = tok->next; continue; } - Token *start = tok; tok = tok->next; - - if (equal(tok, "include")) { + if (EQUAL(tok, "include")) { bool is_dquote; char *filename = read_include_filename(&tok, tok->next, &is_dquote); - if (filename[0] != '/' && is_dquote) { char *path = - format("%s/%s", dirname(strdup(start->file->name)), filename); - if (file_exists(path)) { + xasprintf("%s/%s", dirname(strdup(start->file->name)), filename); + if (fileexists(path)) { tok = include_file(tok, path); continue; } } - char *path = search_include_paths(filename); tok = include_file(tok, path ? path : filename); continue; } - - if (equal(tok, "include_next")) { + if (EQUAL(tok, "include_next")) { bool ignore; char *filename = read_include_filename(&tok, tok->next, &ignore); char *path = search_include_next(filename); tok = include_file(tok, path ? path : filename); continue; } - - if (equal(tok, "define")) { + if (EQUAL(tok, "define")) { read_macro_definition(&tok, tok->next); continue; } - - if (equal(tok, "undef")) { + if (EQUAL(tok, "undef")) { tok = tok->next; if (tok->kind != TK_IDENT) error_tok(tok, "macro name must be an identifier"); @@ -805,90 +785,74 @@ static Token *preprocess2(Token *tok) { tok = skip_line(tok->next); continue; } - - if (equal(tok, "if")) { + if (EQUAL(tok, "if")) { long val = eval_const_expr(&tok, tok); push_cond_incl(start, val); if (!val) tok = skip_cond_incl(tok); continue; } - - if (equal(tok, "ifdef")) { + if (EQUAL(tok, "ifdef")) { bool defined = find_macro(tok->next); push_cond_incl(tok, defined); tok = skip_line(tok->next->next); if (!defined) tok = skip_cond_incl(tok); continue; } - - if (equal(tok, "ifndef")) { + if (EQUAL(tok, "ifndef")) { bool defined = find_macro(tok->next); push_cond_incl(tok, !defined); tok = skip_line(tok->next->next); if (defined) tok = skip_cond_incl(tok); continue; } - - if (equal(tok, "elif")) { + if (EQUAL(tok, "elif")) { if (!cond_incl || cond_incl->ctx == IN_ELSE) error_tok(start, "stray #elif"); cond_incl->ctx = IN_ELIF; - if (!cond_incl->included && eval_const_expr(&tok, tok)) cond_incl->included = true; else tok = skip_cond_incl(tok); continue; } - - if (equal(tok, "else")) { + if (EQUAL(tok, "else")) { if (!cond_incl || cond_incl->ctx == IN_ELSE) error_tok(start, "stray #else"); cond_incl->ctx = IN_ELSE; tok = skip_line(tok->next); - if (cond_incl->included) tok = skip_cond_incl(tok); continue; } - - if (equal(tok, "endif")) { + if (EQUAL(tok, "endif")) { if (!cond_incl) error_tok(start, "stray #endif"); cond_incl = cond_incl->next; tok = skip_line(tok->next); continue; } - - if (equal(tok, "line")) { + if (EQUAL(tok, "line")) { read_line_marker(&tok, tok->next); continue; } - if (tok->kind == TK_PP_NUM) { read_line_marker(&tok, tok); continue; } - - if (equal(tok, "pragma") && equal(tok->next, "once")) { + if (EQUAL(tok, "pragma") && EQUAL(tok->next, "once")) { hashmap_put(&pragma_once, tok->file->name, (void *)1); tok = skip_line(tok->next->next); continue; } - - if (equal(tok, "pragma")) { + if (EQUAL(tok, "pragma")) { do { tok = tok->next; } while (!tok->at_bol); continue; } - - if (equal(tok, "error")) error_tok(tok, "error"); - + if (EQUAL(tok, "error")) error_tok(tok, "error"); // `#`-only line is legal. It's called a null directive. if (tok->at_bol) continue; - error_tok(tok, "invalid preprocessor directive"); } - cur->next = tok; return head.next; } @@ -944,7 +908,7 @@ static Token *base_file_macro(Token *tmpl) { // __DATE__ is expanded to the current date, e.g. "May 17 2020". static char *format_date(struct tm *tm) { - static char mon[][4] = { + _Alignas(char) static char mon[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; @@ -962,48 +926,320 @@ static char *format_time(struct tm *tm) { } void init_macros(void) { - // Define predefined macros - define_macro("_LP64", "1"); - define_macro("__STRICT_ANSI__", "1"); - define_macro("__C99_MACRO_WITH_VA_ARGS", "1"); - define_macro("__ELF__", "1"); - define_macro("__LP64__", "1"); - define_macro("__SIZEOF_DOUBLE__", "8"); - define_macro("__SIZEOF_FLOAT__", "4"); - define_macro("__SIZEOF_INT__", "4"); - define_macro("__SIZEOF_LONG_DOUBLE__", "8"); - define_macro("__SIZEOF_LONG_LONG__", "8"); - define_macro("__SIZEOF_LONG__", "8"); - define_macro("__SIZEOF_POINTER__", "8"); - define_macro("__SIZEOF_PTRDIFF_T__", "8"); - define_macro("__SIZEOF_SHORT__", "2"); - define_macro("__SIZEOF_SIZE_T__", "8"); - define_macro("__SIZE_TYPE__", "unsigned long"); - define_macro("__STDC_HOSTED__", "1"); - define_macro("__STDC_NO_COMPLEX__", "1"); - define_macro("__STDC_UTF_16__", "1"); - define_macro("__STDC_UTF_32__", "1"); - define_macro("__STDC_VERSION__", "201112L"); - define_macro("__STDC__", "1"); - define_macro("__USER_LABEL_PREFIX__", ""); - define_macro("__alignof__", "_Alignof"); - define_macro("__amd64", "1"); - define_macro("__amd64__", "1"); - define_macro("__chibicc__", "1"); - define_macro("__const__", "const"); - define_macro("__gnu_linux__", "1"); - define_macro("__inline__", "inline"); - define_macro("__linux", "1"); - define_macro("__linux__", "1"); - define_macro("__signed__", "signed"); - define_macro("__typeof__", "typeof"); - define_macro("__unix", "1"); - define_macro("__unix__", "1"); - define_macro("__volatile__", "volatile"); - define_macro("__x86_64", "1"); - define_macro("__x86_64__", "1"); - define_macro("linux", "1"); - define_macro("unix", "1"); + char *val, *name = "\ +__chibicc__\000\ +1\000\ +__cosmopolitan__\000\ +1\000\ +__GNUC__\000\ +6\000\ +__GNUC_MINOR__\000\ +6\000\ +__GNUC_PATCHLEVEL__\000\ +6\000\ +__NO_INLINE__\000\ +16\000\ +__BIGGEST_ALIGNMENT__\000\ +16\000\ +__C99_MACRO_WITH_VA_ARGS\000\ +1\000\ +__GCC_ASM_FLAG_OUTPUTS__\000\ +1\000\ +__ELF__\000\ +1\000\ +__LP64__\000\ +1\000\ +_LP64\000\ +1\000\ +__STDC__\000\ +1\000\ +__STDC_HOSTED__\000\ +1\000\ +__STDC_NO_COMPLEX__\000\ +1\000\ +__STDC_UTF_16__\000\ +1\000\ +__STDC_UTF_32__\000\ +1\000\ +__STDC_VERSION__\000\ +201112L\000\ +__USER_LABEL_PREFIX__\000\ +\000\ +__alignof__\000\ +_Alignof\000\ +__const__\000\ +const\000\ +__inline__\000\ +inline\000\ +__signed__\000\ +signed\000\ +__typeof__\000\ +typeof\000\ +__volatile__\000\ +volatile\000\ +__unix\000\ +1\000\ +__unix__\000\ +1\000\ +__linux\000\ +1\000\ +__linux__\000\ +1\000\ +__gnu_linux__\000\ +1\000\ +__BYTE_ORDER__\000\ +1234\000\ +__FLOAT_WORD_ORDER__\000\ +1234\000\ +__ORDER_BIG_ENDIAN__\000\ +4321\000\ +__ORDER_LITTLE_ENDIAN__\000\ +1234\000\ +__INT8_MAX__\000\ +0x7f\000\ +__UINT8_MAX__\000\ +0xff\000\ +__INT16_MAX__\000\ +0x7fff\000\ +__UINT16_MAX__\000\ +0xffff\000\ +__SHRT_MAX__\000\ +0x7fff\000\ +__INT_MAX__\000\ +0x7fffffff\000\ +__INT32_MAX__\000\ +0x7fffffff\000\ +__UINT32_MAX__\000\ +0xffffffffu\000\ +__INT64_MAX__\000\ +0x7fffffffffffffffl\000\ +__UINT64_MAX__\000\ +0xfffffffffffffffful\000\ +__SIZE_MAX__\000\ +0xfffffffffffffffful\000\ +__INTPTR_MAX__\000\ +0x7fffffffffffffffl\000\ +__UINTPTR_MAX__\000\ +0xfffffffffffffffful\000\ +__WINT_MAX__\000\ +0xffffffffu\000\ +__CHAR_BIT__\000\ +8\000\ +__SIZEOF_SHORT__\000\ +2\000\ +__SIZEOF_INT__\000\ +4\000\ +__SIZEOF_LONG__\000\ +8\000\ +__SIZEOF_LONG_LONG__\000\ +8\000\ +__SIZEOF_POINTER__\000\ +8\000\ +__SIZEOF_PTRDIFF_T__\000\ +8\000\ +__SIZEOF_SIZE_T__\000\ +8\000\ +__SIZEOF_WCHAR_T__\000\ +4\000\ +__SIZEOF_WINT_T__\000\ +4\000\ +__SIZEOF_FLOAT__\000\ +4\000\ +__SIZEOF_FLOAT128__\000\ +16\000\ +__SIZEOF_DOUBLE__\000\ +8\000\ +__SIZEOF_FLOAT80__\000\ +16\000\ +__SIZEOF_LONG_DOUBLE__\000\ +16\000\ +__INT8_TYPE__\000\ +signed char\000\ +__UINT8_TYPE__\000\ +unsigned char\000\ +__INT16_TYPE__\000\ +short int\000\ +__UINT16_TYPE__\000\ +short unsigned int\000\ +__INT32_TYPE__\000\ +int\000\ +__UINT32_TYPE__\000\ +unsigned int\000\ +__INT64_TYPE__\000\ +long int\000\ +__UINT64_TYPE__\000\ +long unsigned int\000\ +__INTPTR_TYPE__\000\ +long int\000\ +__UINTPTR_TYPE__\000\ +long unsigned int\000\ +__PTRDIFF_TYPE__\000\ +long int\000\ +__SIZE_TYPE__\000\ +long unsigned int\000\ +__WCHAR_TYPE__\000\ +int\000\ +__CHAR16_TYPE__\000\ +short unsigned int\000\ +__CHAR32_TYPE__\000\ +unsigned int\000\ +__WINT_TYPE__\000\ +unsigned int\000\ +__CHAR16_TYPE__\000\ +short unsigned int\000\ +__WCHAR_TYPE__\000\ +int\000\ +__CHAR32_TYPE__\000\ +unsigned int\000\ +__INT_LEAST8_TYPE__\000\ +signed char\000\ +__UINT_LEAST8_TYPE__\000\ +unsigned char\000\ +__INT_LEAST16_TYPE__\000\ +int\000\ +__UINT_LEAST16_TYPE__\000\ +unsigned short\000\ +__INT_LEAST32_TYPE__\000\ +short\000\ +__UINT_LEAST32_TYPE__\000\ +unsigned int\000\ +__INT_LEAST64_TYPE__\000\ +long\000\ +__UINT_LEAST64_TYPE__\000\ +unsigned long\000\ +__INT_FAST8_TYPE__\000\ +signed char\000\ +__UINT_FAST8_TYPE__\000\ +unsigned char\000\ +__INT_FAST16_TYPE__\000\ +int\000\ +__UINT_FAST16_TYPE__\000\ +unsigned\000\ +__INT_FAST32_TYPE__\000\ +int\000\ +__UINT_FAST32_TYPE__\000\ +unsigned\000\ +__INT_FAST64_TYPE__\000\ +long\000\ +__UINT_FAST64_TYPE__\000\ +unsigned long\000\ +__DBL_DECIMAL_DIG__\000\ +17\000\ +__DBL_DENORM_MIN__\000\ +((double)4.94065645841246544176568792868221372e-324L)\000\ +__DBL_DIG__\000\ +15\000\ +__DBL_EPSILON__\000\ +((double)2.22044604925031308084726333618164062e-16L)\000\ +__DBL_HAS_DENORM__\000\ +1\000\ +__DBL_HAS_INFINITY__\000\ +1\000\ +__DBL_HAS_QUIET_NAN__\000\ +1\000\ +__DBL_MANT_DIG__\000\ +53\000\ +__DBL_MAX_10_EXP__\000\ +308\000\ +__DBL_MAX_EXP__\000\ +1024\000\ +__DBL_MAX__\000\ +((double)1.79769313486231570814527423731704357e+308L)\000\ +__DBL_MIN_10_EXP__\000\ +(-307)\000\ +__DBL_MIN_EXP__\000\ +(-1021)\000\ +__DBL_MIN__\000\ +((double)2.22507385850720138309023271733240406e-308L)\000\ +__FLT_DECIMAL_DIG__\000\ +9\000\ +__FLT_DENORM_MIN__\000\ +1.40129846432481707092372958328991613e-45F\000\ +__FLT_DIG__\000\ +6\000\ +__FLT_EPSILON__\000\ +1.19209289550781250000000000000000000e-7F\000\ +__FLT_EVAL_METHOD_TS_18661_3__\000\ +0\000\ +__FLT_EVAL_METHOD__\000\ +0\000\ +__FLT_HAS_DENORM__\000\ +1\000\ +__FLT_HAS_INFINITY__\000\ +1\000\ +__FLT_HAS_QUIET_NAN__\000\ +1\000\ +__FLT_MANT_DIG__\000\ +24\000\ +__FLT_MAX_10_EXP__\000\ +38\000\ +__FLT_MAX_EXP__\000\ +128\000\ +__FLT_MAX__\000\ +3.40282346638528859811704183484516925e+38F\000\ +__FLT_MIN_10_EXP__\000\ +(-37)\000\ +__FLT_MIN_EXP__\000\ +(-125)\000\ +__FLT_MIN__\000\ +1.17549435082228750796873653722224568e-38F\000\ +__FLT_RADIX__\000\ +2\000\ +__LDBL_DECIMAL_DIG__\000\ +21\000\ +__LDBL_DENORM_MIN__\000\ +3.64519953188247460252840593361941982e-4951L\000\ +__LDBL_DIG__\000\ +18\000\ +__LDBL_EPSILON__\000\ +1.08420217248550443400745280086994171e-19L\000\ +__LDBL_HAS_DENORM__\000\ +1\000\ +__LDBL_HAS_INFINITY__\000\ +1\000\ +__LDBL_HAS_QUIET_NAN__\000\ +1\000\ +__LDBL_MANT_DIG__\000\ +64\000\ +__LDBL_MAX_10_EXP__\000\ +4932\000\ +__LDBL_MAX_EXP__\000\ +16384\000\ +__LDBL_MAX__\000\ +1.18973149535723176502126385303097021e+4932L\000\ +__LDBL_MIN_10_EXP__\000\ +(-4931)\000\ +__LDBL_MIN_EXP__\000\ +(-16381)\000\ +__LDBL_MIN__\000\ +3.36210314311209350626267781732175260e-4932L\000\ +__x86_64\000\ +1\000\ +__x86_64__\000\ +1\000\ +__amd64\000\ +1\000\ +__amd64__\000\ +1\000\ +__MMX__\000\ +1\000\ +__SSE__\000\ +1\000\ +__SSE_MATH__\000\ +1\000\ +__SSE2__\000\ +1\000\ +__SSE2_MATH__\000\ +1\000\ +\000"; + do { + val = name + strlen(name) + 1; + define_macro(name, val); + name = val + strlen(val) + 1; + } while (*name); +#ifdef __SSE3__ + define_macro("__SSE3__", "1"); +#endif add_builtin("__FILE__", file_macro); add_builtin("__LINE__", line_macro); add_builtin("__COUNTER__", counter_macro); @@ -1015,14 +1251,6 @@ void init_macros(void) { define_macro("__TIME__", format_time(tm)); } -typedef enum { - STR_NONE, - STR_UTF8, - STR_UTF16, - STR_UTF32, - STR_WIDE, -} StringKind; - static StringKind getStringKind(Token *tok) { if (!strcmp(tok->loc, "u8")) return STR_UTF8; switch (tok->loc[0]) { @@ -1090,10 +1318,13 @@ static void join_adjacent_string_literals(Token *tok) { // Entry point function of the preprocessor. Token *preprocess(Token *tok) { tok = preprocess2(tok); - if (cond_incl) + if (cond_incl) { error_tok(cond_incl->tok, "unterminated conditional directive"); + } convert_pp_tokens(tok); join_adjacent_string_literals(tok); - for (Token *t = tok; t; t = t->next) t->line_no += t->line_delta; + for (Token *t = tok; t; t = t->next) { + t->line_no += t->line_delta; + } return tok; } diff --git a/third_party/chibicc/strarray.c b/third_party/chibicc/strarray.c index 1feb6d9e..501cd9a5 100644 --- a/third_party/chibicc/strarray.c +++ b/third_party/chibicc/strarray.c @@ -5,12 +5,10 @@ void strarray_push(StringArray *arr, char *s) { arr->data = calloc(8, sizeof(char *)); arr->capacity = 8; } - if (arr->capacity == arr->len) { arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2); arr->capacity *= 2; for (int i = arr->len; i < arr->capacity; i++) arr->data[i] = NULL; } - arr->data[arr->len++] = s; } diff --git a/third_party/chibicc/test/alignof_test.c b/third_party/chibicc/test/alignof_test.c new file mode 100644 index 00000000..35eeda54 --- /dev/null +++ b/third_party/chibicc/test/alignof_test.c @@ -0,0 +1,103 @@ +#include "third_party/chibicc/test/test.h" + +int _Alignas(512) g1; +int _Alignas(512) g2; +char g3; +int g4; +long g5; +char g6; + +int main() { + ASSERT(1, _Alignof(char)); + ASSERT(2, _Alignof(short)); + ASSERT(4, _Alignof(int)); + ASSERT(8, _Alignof(long)); + ASSERT(8, _Alignof(long long)); + ASSERT(1, _Alignof(char[3])); + ASSERT(4, _Alignof(int[3])); + ASSERT(1, _Alignof(struct { + char a; + char b; + }[2])); + ASSERT(8, _Alignof(struct { + char a; + long b; + }[2])); + + ASSERT(1, ({ + _Alignas(char) char x, y; + &y - &x; + })); + ASSERT(8, ({ + _Alignas(long) char x, y; + &y - &x; + })); + ASSERT(32, ({ + _Alignas(32) char x, y; + &y - &x; + })); + ASSERT(32, ({ + _Alignas(32) int *x, *y; + ((char *)&y) - ((char *)&x); + })); + ASSERT(16, ({ + struct { + _Alignas(16) char x, y; + } a; + &a.y - &a.x; + })); + ASSERT(8, ({ + struct T { + _Alignas(8) char a; + }; + _Alignof(struct T); + })); + + ASSERT(0, (long)(char *)&g1 % 512); + ASSERT(0, (long)(char *)&g2 % 512); + ASSERT(0, (long)(char *)&g4 % 4); + ASSERT(0, (long)(char *)&g5 % 8); + + ASSERT(1, ({ + char x; + _Alignof(x); + })); + ASSERT(4, ({ + int x; + _Alignof(x); + })); + ASSERT(1, ({ + char x; + _Alignof x; + })); + ASSERT(4, ({ + int x; + _Alignof x; + })); + + ASSERT(1, _Alignof(char) << 31 >> 31); + ASSERT(1, _Alignof(char) << 63 >> 63); + ASSERT(1, ({ + char x; + _Alignof(x) << 63 >> 63; + })); + + ASSERT(0, ({ + char x[16]; + (unsigned long)&x % 16; + })); + ASSERT(0, ({ + char x[17]; + (unsigned long)&x % 16; + })); + ASSERT(0, ({ + char x[100]; + (unsigned long)&x % 16; + })); + ASSERT(0, ({ + char x[101]; + (unsigned long)&x % 16; + })); + + return 0; +} diff --git a/third_party/chibicc/test/alloca_test.c b/third_party/chibicc/test/alloca_test.c new file mode 100644 index 00000000..d232d103 --- /dev/null +++ b/third_party/chibicc/test/alloca_test.c @@ -0,0 +1,29 @@ +#include "third_party/chibicc/test/test.h" + +void *fn(int x, void *p, int y) { + return p; +} + +int main() { + int i = 0; + + char *p1 = alloca(16); + char *p2 = alloca(16); + char *p3 = 1 + (char *)alloca(3) + 1; + p3 -= 2; + char *p4 = fn(1, alloca(16), 3); + + ASSERT(16, p1 - p2); + ASSERT(16, p2 - p3); + ASSERT(16, p3 - p4); + + memcpy(p1, "0123456789abcdef", 16); + memcpy(p2, "ghijklmnopqrstuv", 16); + memcpy(p3, "wxy", 3); + + ASSERT(0, memcmp(p1, "0123456789abcdef", 16)); + ASSERT(0, memcmp(p2, "ghijklmnopqrstuv", 16)); + ASSERT(0, memcmp(p3, "wxy", 3)); + + return 0; +} diff --git a/third_party/chibicc/test/arith_test.c b/third_party/chibicc/test/arith_test.c new file mode 100644 index 00000000..6d10a39a --- /dev/null +++ b/third_party/chibicc/test/arith_test.c @@ -0,0 +1,341 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(0, 0); + ASSERT(42, 42); + ASSERT(21, 5 + 20 - 4); + ASSERT(41, 12 + 34 - 5); + ASSERT(47, 5 + 6 * 7); + ASSERT(15, 5 * (9 - 6)); + ASSERT(4, (3 + 5) / 2); + ASSERT(10, -10 + 20); + + ASSERT(0, 0 == 1); + ASSERT(1, 42 == 42); + ASSERT(1, 0 != 1); + ASSERT(0, 42 != 42); + + ASSERT(1, 0 < 1); + ASSERT(0, 1 < 1); + ASSERT(0, 2 < 1); + ASSERT(1, 0 <= 1); + ASSERT(1, 1 <= 1); + ASSERT(0, 2 <= 1); + + ASSERT(1, 1 > 0); + ASSERT(0, 1 > 1); + ASSERT(0, 1 > 2); + ASSERT(1, 1 >= 0); + ASSERT(1, 1 >= 1); + ASSERT(0, 1 >= 2); + + ASSERT(0, 1073741824 * 100 / 100); + + ASSERT(7, ({ + int i = 2; + i += 5; + i; + })); + ASSERT(7, ({ + int i = 2; + i += 5; + })); + ASSERT(3, ({ + int i = 5; + i -= 2; + i; + })); + ASSERT(3, ({ + int i = 5; + i -= 2; + })); + ASSERT(6, ({ + int i = 3; + i *= 2; + i; + })); + ASSERT(6, ({ + int i = 3; + i *= 2; + })); + ASSERT(3, ({ + int i = 6; + i /= 2; + i; + })); + ASSERT(3, ({ + int i = 6; + i /= 2; + })); + + ASSERT(3, ({ + int i = 2; + ++i; + })); + ASSERT(2, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + ++*p; + })); + ASSERT(0, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + --*p; + })); + + ASSERT(2, ({ + int i = 2; + i++; + })); + ASSERT(2, ({ + int i = 2; + i--; + })); + ASSERT(3, ({ + int i = 2; + i++; + i; + })); + ASSERT(1, ({ + int i = 2; + i--; + i; + })); + ASSERT(1, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + *p++; + })); + ASSERT(1, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + *p--; + })); + + ASSERT(0, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*p++)--; + a[0]; + })); + ASSERT(0, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*(p--))--; + a[1]; + })); + ASSERT(2, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*p)--; + a[2]; + })); + ASSERT(2, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*p)--; + p++; + *p; + })); + + ASSERT(0, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*p++)--; + a[0]; + })); + ASSERT(0, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*p++)--; + a[1]; + })); + ASSERT(2, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*p++)--; + a[2]; + })); + ASSERT(2, ({ + int a[3]; + a[0] = 0; + a[1] = 1; + a[2] = 2; + int *p = a + 1; + (*p++)--; + *p; + })); + + ASSERT(0, !1); + ASSERT(0, !2); + ASSERT(1, !0); + ASSERT(1, !(char)0); + ASSERT(0, !(long)3); + ASSERT(4, sizeof(!(char)0)); + ASSERT(4, sizeof(!(long)0)); + + ASSERT(-1, ~0); + ASSERT(0, ~-1); + + ASSERT(5, 17 % 6); + ASSERT(5, ((long)17) % 6); + ASSERT(2, ({ + int i = 10; + i %= 4; + i; + })); + ASSERT(2, ({ + long i = 10; + i %= 4; + i; + })); + + ASSERT(0, 0 & 1); + ASSERT(1, 3 & 1); + ASSERT(3, 7 & 3); + ASSERT(10, -1 & 10); + + ASSERT(1, 0 | 1); + ASSERT(0b10011, 0b10000 | 0b00011); + + ASSERT(0, 0 ^ 0); + ASSERT(0, 0b1111 ^ 0b1111); + ASSERT(0b110100, 0b111000 ^ 0b001100); + + ASSERT(2, ({ + int i = 6; + i &= 3; + i; + })); + ASSERT(7, ({ + int i = 6; + i |= 3; + i; + })); + ASSERT(10, ({ + int i = 15; + i ^= 5; + i; + })); + + ASSERT(1, 1 << 0); + ASSERT(8, 1 << 3); + ASSERT(10, 5 << 1); + ASSERT(2, 5 >> 1); + ASSERT(-1, -1 >> 1); + ASSERT(1, ({ + int i = 1; + i <<= 0; + i; + })); + ASSERT(8, ({ + int i = 1; + i <<= 3; + i; + })); + ASSERT(10, ({ + int i = 5; + i <<= 1; + i; + })); + ASSERT(2, ({ + int i = 5; + i >>= 1; + i; + })); + ASSERT(-1, -1); + ASSERT(-1, ({ + int i = -1; + i; + })); + ASSERT(-1, ({ + int i = -1; + i >>= 1; + i; + })); + + ASSERT(2, 0 ? 1 : 2); + ASSERT(1, 1 ? 1 : 2); + ASSERT(-1, 0 ? -2 : -1); + ASSERT(-2, 1 ? -2 : -1); + ASSERT(4, sizeof(0 ? 1 : 2)); + ASSERT(8, sizeof(0 ? (long)1 : (long)2)); + ASSERT(-1, 0 ? (long)-2 : -1); + ASSERT(-1, 0 ? -2 : (long)-1); + ASSERT(-2, 1 ? (long)-2 : -1); + ASSERT(-2, 1 ? -2 : (long)-1); + + 1 ? -2 : (void)-1; + + ASSERT(20, ({ + int x; + int *p = &x; + p + 20 - p; + })); + ASSERT(1, ({ + int x; + int *p = &x; + p + 20 - p > 0; + })); + ASSERT(-20, ({ + int x; + int *p = &x; + p - 20 - p; + })); + ASSERT(1, ({ + int x; + int *p = &x; + p - 20 - p < 0; + })); + + ASSERT(15, (char *)0xffffffffffffffff - (char *)0xfffffffffffffff0); + ASSERT(-15, (char *)0xfffffffffffffff0 - (char *)0xffffffffffffffff); + ASSERT(1, (void *)0xffffffffffffffff > (void *)0); + + ASSERT(3, 3 ?: 5); + ASSERT(5, 0 ?: 5); + ASSERT(4, ({ + int i = 3; + ++i ?: 10; + })); + + ASSERT(3, (long double)3); + ASSERT(5, (long double)3 + 2); + ASSERT(6, (long double)3 * 2); + ASSERT(5, (long double)3 + 2.0); + + return 0; +} diff --git a/third_party/chibicc/test/asm_test.c b/third_party/chibicc/test/asm_test.c new file mode 100644 index 00000000..bcd45bd9 --- /dev/null +++ b/third_party/chibicc/test/asm_test.c @@ -0,0 +1,132 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or 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. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/chibicc/test/test.h" + +char *asm_fn1(void) { + asm("mov\t$50,%rax\n\t" + "mov\t%rbp,%rsp\n\t" + "leave\n\t" + "ret"); +} + +char *asm_fn2(void) { + asm inline volatile("mov\t$55,%rax\n\t" + "mov\t%rbp,%rsp\n\t" + "leave\n\t" + "ret"); +} + +void *repmovsb(void *dst, void *src, unsigned long n) { + asm("rep movsb" + : "=D"(dst), "=S"(src), "=c"(n), "=m"(*(char(*)[n])dst) + : "0"(dst), "1"(src), "2"(n), "m"(*(const char(*)[n])src)); + return dst; +} + +void *repmovsbeax(void *dst, void *src, unsigned long n) { + void *res; + asm("rep movsb\n\t" + "xchg\t%0,%1" + : "=a"(res), "=D"(dst), "=S"(src), "=c"(n), "=m"(*(char(*)[n])dst) + : "1"(dst), "2"(src), "3"(n), "m"(*(const char(*)[n])src) + : "rbx", "rbp", "r12", "r13", "r14", "r15", "cc"); + return res; +} + +void testSmashStackFrame_clobberIsRestored(void) { + asm volatile("xor\t%%ebp,%%ebp" + : /* no outputs */ + : /* no inputs */ + : "rbp", "cc"); +} + +void testFlagOutputs(void) { + bool zf, cf, sf; + asm("xor\t%%eax,%%eax\n\t" + "inc\t%%eax" + : "=@ccz"(zf), "=@ccs"(cf) + : /* no inputs */ + : "rax"); + ASSERT(false, zf); + ASSERT(false, sf); + asm("xor\t%%eax,%%eax\n\t" + "dec\t%%eax" + : "=@ccz"(zf), "=@ccs"(cf) + : /* no inputs */ + : "rax"); + ASSERT(false, zf); + ASSERT(true, sf); + asm("xor\t%%eax,%%eax\n\t" + "cmc" + : "=@ccz"(zf), "=@ccc"(cf), "=@ccs"(sf) + : /* no inputs */ + : "rax"); + ASSERT(true, zf); + ASSERT(true, cf); + ASSERT(false, sf); +} + +int main() { + ASSERT(50, asm_fn1()); + ASSERT(55, asm_fn2()); + + { + char buf[] = "HELLO"; + char *s = "hello"; + char *p = repmovsb(buf, s, 4); + ASSERT(4, p - buf); + ASSERT('h', buf[0]); + ASSERT('e', buf[1]); + ASSERT('l', buf[2]); + ASSERT('l', buf[3]); + ASSERT('O', buf[4]); + } + + { + char buf[] = "HELLO"; + char *s = "hello"; + char *p = repmovsbeax(buf, s, 4); + ASSERT(4, p - buf); + ASSERT('h', buf[0]); + ASSERT('e', buf[1]); + ASSERT('l', buf[2]); + ASSERT('l', buf[3]); + ASSERT('O', buf[4]); + } + + testSmashStackFrame_clobberIsRestored(); + + short v1[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + short v2[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + short v3[8] = {2, 2, 2, 2, 2, 2, 2, 2}; + asm("paddsw\t%1,%0\n\t" + "paddsw\t%2,%0" + : "+x"(v1) + : "xm"(v2), "xm"(v3)); + ASSERT(3, v1[0]); + ASSERT(4, v1[1]); + ASSERT(5, v1[2]); + ASSERT(6, v1[3]); + ASSERT(7, v1[4]); + ASSERT(8, v1[5]); + ASSERT(9, v1[6]); + ASSERT(10, v1[7]); + + return 0; +} diff --git a/third_party/chibicc/test/attribute_test.c b/third_party/chibicc/test/attribute_test.c new file mode 100644 index 00000000..af74438a --- /dev/null +++ b/third_party/chibicc/test/attribute_test.c @@ -0,0 +1,160 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(5, ({ + struct { + char a; + int b; + } __attribute__((packed)) x; + sizeof(x); + })); + ASSERT(0, offsetof( + struct __attribute__((packed)) { + char a; + int b; + }, + a)); + ASSERT(1, offsetof( + struct __attribute__((packed)) { + char a; + int b; + }, + b)); + + ASSERT(5, ({ + struct __attribute__((packed)) { + char a; + int b; + } x; + sizeof(x); + })); + ASSERT(0, offsetof( + struct { + char a; + int b; + } __attribute__((packed)), + a)); + ASSERT(1, offsetof( + struct { + char a; + int b; + } __attribute__((packed)), + b)); + + ASSERT(9, ({ + typedef struct { + char a; + int b[2]; + } __attribute__((packed)) T; + sizeof(T); + })); + ASSERT(9, ({ + typedef struct __attribute__((packed)) { + char a; + int b[2]; + } T; + sizeof(T); + })); + + ASSERT(1, offsetof( + struct __attribute__((packed)) T { + char a; + int b[2]; + }, + b)); + ASSERT(1, _Alignof(struct __attribute__((packed)) { + char a; + int b[2]; + })); + + ASSERT(8, ({ + struct __attribute__((aligned(8))) { + int a; + } x; + _Alignof(x); + })); + ASSERT(8, ({ + struct { + int a; + } __attribute__((aligned(8))) x; + _Alignof(x); + })); + + ASSERT(8, ({ + struct __attribute__((aligned(8), packed)) { + char a; + int b; + } x; + _Alignof(x); + })); + ASSERT(8, ({ + struct { + char a; + int b; + } __attribute__((aligned(8), packed)) x; + _Alignof(x); + })); + ASSERT(1, offsetof( + struct __attribute__((aligned(8), packed)) { + char a; + int b; + }, + b)); + ASSERT(1, offsetof( + struct { + char a; + int b; + } __attribute__((aligned(8), packed)), + b)); + + ASSERT(8, ({ + struct __attribute__((aligned(8))) __attribute__((packed)) { + char a; + int b; + } x; + _Alignof(x); + })); + ASSERT(8, ({ + struct { + char a; + int b; + } __attribute__((aligned(8))) __attribute__((packed)) x; + _Alignof(x); + })); + ASSERT(1, offsetof( + struct __attribute__((aligned(8))) __attribute__((packed)) { + char a; + int b; + }, + b)); + ASSERT(1, offsetof( + struct { + char a; + int b; + } __attribute__((aligned(8))) __attribute__((packed)), + b)); + + ASSERT(8, ({ + struct __attribute__((aligned(8))) { + char a; + int b; + } __attribute__((packed)) x; + _Alignof(x); + })); + ASSERT(1, offsetof( + struct __attribute__((aligned(8))) { + char a; + int b; + } __attribute__((packed)), + b)); + + ASSERT(16, ({ + struct __attribute__((aligned(8 + 8))) { + char a; + int b; + } x; + _Alignof(x); + })); + + return 0; +} diff --git a/third_party/chibicc/test/bitfield_test.c b/third_party/chibicc/test/bitfield_test.c new file mode 100644 index 00000000..33b93cc6 --- /dev/null +++ b/third_party/chibicc/test/bitfield_test.c @@ -0,0 +1,128 @@ +#include "third_party/chibicc/test/test.h" + +struct { + char a; + int b : 5; + int c : 10; +} g45 = {1, 2, 3}, g46 = {}; + +int main() { + ASSERT(4, sizeof(struct { int x : 1; })); + ASSERT(8, sizeof(struct { long x : 1; })); + + struct bit1 { + short a; + char b; + int c : 2; + int d : 3; + int e : 3; + }; + + ASSERT(4, sizeof(struct bit1)); + ASSERT(1, ({ + struct bit1 x; + x.a = 1; + x.b = 2; + x.c = 3; + x.d = 4; + x.e = 5; + x.a; + })); + ASSERT(1, ({ + struct bit1 x = {1, 2, 3, 4, 5}; + x.a; + })); + ASSERT(2, ({ + struct bit1 x = {1, 2, 3, 4, 5}; + x.b; + })); + ASSERT(-1, ({ + struct bit1 x = {1, 2, 3, 4, 5}; + x.c; + })); + ASSERT(-4, ({ + struct bit1 x = {1, 2, 3, 4, 5}; + x.d; + })); + ASSERT(-3, ({ + struct bit1 x = {1, 2, 3, 4, 5}; + x.e; + })); + + ASSERT(1, g45.a); + ASSERT(2, g45.b); + ASSERT(3, g45.c); + + ASSERT(0, g46.a); + ASSERT(0, g46.b); + ASSERT(0, g46.c); + + typedef struct { + int a : 10; + int b : 10; + int c : 10; + } T3; + + ASSERT(1, ({ + T3 x = {1, 2, 3}; + x.a++; + })); + ASSERT(2, ({ + T3 x = {1, 2, 3}; + x.b++; + })); + ASSERT(3, ({ + T3 x = {1, 2, 3}; + x.c++; + })); + + ASSERT(2, ({ + T3 x = {1, 2, 3}; + ++x.a; + })); + ASSERT(3, ({ + T3 x = {1, 2, 3}; + ++x.b; + })); + ASSERT(4, ({ + T3 x = {1, 2, 3}; + ++x.c; + })); + + ASSERT(4, sizeof(struct { + int a : 3; + int c : 1; + int c : 5; + })); + ASSERT(8, sizeof(struct { + int a : 3; + int : 0; + int c : 5; + })); + ASSERT(4, sizeof(struct { + int a : 3; + int : 0; + })); + + typedef struct { + long p : 1; + long a : 40; + long b : 20; + } T4; + + ASSERT(0xfffffffffffaaaaa, ({ + T4 x = {1, 0x31337313371337, 0xaaaaaaaaaaaaaaaa}; + x.b++; + })); + ASSERT(0x7313371337, ({ + T4 x = {1, 0x31337313371337, 0xaaaaaaaaaaaaaaaa}; + x.a++; + })); + ASSERT(0xffffffffffffffd4, ({ + T4 x; + x.b = -44; + x.b++; + })); + + return 0; +} diff --git a/third_party/chibicc/test/builtin_test.c b/third_party/chibicc/test/builtin_test.c new file mode 100644 index 00000000..5c1a6491 --- /dev/null +++ b/third_party/chibicc/test/builtin_test.c @@ -0,0 +1,242 @@ +#include "third_party/chibicc/test/test.h" + +#define FPNAN 0 +#define FPINFINITE 1 +#define FPZERO 2 +#define FPSUBNORMAL 3 +#define FPNORMAL 4 +#define FPCLASSIFY(x) \ + __builtin_fpclassify(FPNAN, FPINFINITE, FPNORMAL, FPSUBNORMAL, FPZERO, x) + +void test_constant(void) { + ASSERT(1, __builtin_constant_p(1)); + ASSERT(0, __builtin_constant_p(stdin)); + ASSERT(1, __builtin_constant_p(__builtin_popcount(0b10111011))); +} + +void test_fpclassify(void) { + float minf = __FLT_MIN__; + double min = __DBL_MIN__; + long double minl = __LDBL_MIN__; + ASSERT(FPZERO, FPCLASSIFY(.0f)); + ASSERT(FPZERO, FPCLASSIFY(.0)); + ASSERT(FPZERO, FPCLASSIFY(.0L)); + ASSERT(FPNORMAL, FPCLASSIFY(1.f)); + ASSERT(FPNORMAL, FPCLASSIFY(1.)); + ASSERT(FPNORMAL, FPCLASSIFY(1.L)); + ASSERT(FPNORMAL, FPCLASSIFY(1.f)); + ASSERT(FPNORMAL, FPCLASSIFY(1.)); + ASSERT(FPNORMAL, FPCLASSIFY(1.L)); + ASSERT(FPNORMAL, FPCLASSIFY(minf)); + ASSERT(FPNORMAL, FPCLASSIFY(min)); + ASSERT(FPNORMAL, FPCLASSIFY(minl)); + ASSERT(FPSUBNORMAL, FPCLASSIFY(minf / 2)); + ASSERT(FPSUBNORMAL, FPCLASSIFY(min / 2)); + ASSERT(FPSUBNORMAL, FPCLASSIFY(minl / 2)); + ASSERT(FPNAN, FPCLASSIFY(__builtin_nanf(""))); + ASSERT(FPNAN, FPCLASSIFY(__builtin_nan(""))); + ASSERT(FPNAN, FPCLASSIFY(__builtin_nanl(""))); +} + +void __attribute__((__aligned__(16))) test_clz(void) { + ASSERT(31, __builtin_clz(1)); + ASSERT(63, __builtin_clzl(1)); + ASSERT(63, __builtin_clzll(1)); + ASSERT(25, __builtin_clz(77)); + ASSERT(4, __builtin_clz(0x08000000)); + ASSERT(4, __builtin_clz(0xfff08000000)); +} + +__attribute__((__weak__)) void test_ctz(void) { + ASSERT(0, __builtin_ctz(1)); + ASSERT(0, __builtin_ctz(77)); + ASSERT(27, __builtin_ctz(0x08000000)); + ASSERT(27, __builtin_ctz(0xffff08000000)); + ASSERT(63, __builtin_ctzl(0x8000000000000000)); + ASSERT(63, __builtin_ctzll(0x8000000000000000)); +} + +void test_ffs(void) { + ASSERT(0, __builtin_ffs(0)); + ASSERT(1, __builtin_ffs(1)); + ASSERT(1, __builtin_ffs(77)); + ASSERT(28, __builtin_ffs(0x08000000)); + ASSERT(28, __builtin_ffs(0xffff08000000)); +} + +void test_popcnt(void) { + ASSERT(0, __builtin_popcount(0)); + ASSERT(1, __builtin_popcount(1)); + ASSERT(6, __builtin_popcount(0b10111011)); + ASSERT(6, __builtin_popcountl(0b10111011)); + ASSERT(6, __builtin_popcountll(0xbb00000000000000)); +} + +void test_bswap(void) { + ASSERT(0x3412, __builtin_bswap16(0x1234)); + ASSERT(0x78563412, __builtin_bswap32(0x12345678)); + ASSERT(0xefcdab8967452301, __builtin_bswap64(0x0123456789abcdef)); + ASSERT(0xefcdab89, __builtin_bswap32(0x0123456789abcdef)); +} + +void test_memcpy(void) { + { + char x[5] = {4, 3, 2, 1, 0}; + char y[5] = {0, 1, 2, 3, 4}; + char z[5] = {2, 3, 4, 1, 0}; + ASSERT(1, x == __builtin_memcpy(x, y + 2, 3)); + ASSERT(0, memcmp(x, z, 5)); + } + { + int n = 3; + char x[5] = {4, 3, 2, 1, 0}; + char y[5] = {0, 1, 2, 3, 4}; + char z[5] = {2, 3, 4, 1, 0}; + ASSERT(1, x == __builtin_memcpy(x, y + 2, n)); + ASSERT(0, memcmp(x, z, 5)); + } +} + +void test_inf(void) { + ASSERT(0, __builtin_isinf(0)); + ASSERT(0, __builtin_isinf(1)); + ASSERT(1, __builtin_isinf(__builtin_inff())); + ASSERT(1, __builtin_isinf(-__builtin_inff())); + ASSERT(1, __builtin_isinf(__builtin_inf())); + ASSERT(1, __builtin_isinf(-__builtin_inf())); + ASSERT(1, __builtin_isinf(__builtin_infl())); + ASSERT(1, __builtin_isinf(-__builtin_infl())); + ASSERT(1, __builtin_isfinite(0)); + ASSERT(1, __builtin_isfinite(1)); + ASSERT(0, __builtin_isfinite(__builtin_inff())); + ASSERT(0, __builtin_isfinite(-__builtin_inff())); + ASSERT(0, __builtin_isfinite(__builtin_inf())); + ASSERT(0, __builtin_isfinite(-__builtin_inf())); + ASSERT(0, __builtin_isfinite(__builtin_infl())); + ASSERT(0, __builtin_isfinite(-__builtin_infl())); +} + +void test_signbit(void) { + ASSERT(0, !!__builtin_signbitf(0)); + ASSERT(0, !!__builtin_signbitf(0.f)); + ASSERT(0, !!__builtin_signbit(0.)); + ASSERT(0, !!__builtin_signbitl(0.L)); + ASSERT(1, !!__builtin_signbitf(-0.f)); + ASSERT(1, !!__builtin_signbit(-0.)); + ASSERT(1, !!__builtin_signbitl(-0.L)); + ASSERT(0, !!__builtin_signbitf(__builtin_nanf(""))); + ASSERT(1, !!__builtin_signbitf(-__builtin_nanf(""))); + ASSERT(0, !!__builtin_signbit(__builtin_nan(""))); + ASSERT(1, !!__builtin_signbit(-__builtin_nan(""))); + ASSERT(0, !!__builtin_signbitl(__builtin_nanl(""))); + ASSERT(1, !!__builtin_signbitl(-__builtin_nanl(""))); + ASSERT(0, !!__builtin_signbitf(__builtin_inff())); + ASSERT(1, !!__builtin_signbitf(-__builtin_inff())); + ASSERT(0, !!__builtin_signbit(__builtin_inf())); + ASSERT(1, !!__builtin_signbit(-__builtin_inf())); + ASSERT(0, !!__builtin_signbitl(__builtin_infl())); + ASSERT(1, !!__builtin_signbitl(-__builtin_infl())); +} + +void test_nan(void) { + ASSERT(0, __builtin_isnan(0)); + ASSERT(0, __builtin_isnan(1)); + ASSERT(1, __builtin_isnan(__builtin_nanf(""))); + ASSERT(1, __builtin_isnan(-__builtin_nanf(""))); + ASSERT(1, __builtin_isnan(__builtin_nan(""))); + ASSERT(1, __builtin_isnan(-__builtin_nan(""))); + ASSERT(1, __builtin_isnan(__builtin_nanl(""))); + ASSERT(1, __builtin_isnan(-__builtin_nanl(""))); + ASSERT(0, __builtin_isunordered(0, 0)); + ASSERT(0, __builtin_isunordered(-1, 1)); + ASSERT(1, __builtin_isunordered(0, __builtin_nanf(""))); + ASSERT(1, __builtin_isunordered(__builtin_nanf(""), 0)); + ASSERT(1, __builtin_isunordered(__builtin_nanf(""), __builtin_nanf(""))); +} + +void test_double(void) { /* TODO */ + /* ASSERT(1, __DBL_MIN__ < 0.0L); */ + /* ASSERT(1, __DBL_MAX__ > 0.0L); */ +} + +void test_types_compatible_p(void) { + ASSERT(1, __builtin_types_compatible_p(int, int)); + ASSERT(1, __builtin_types_compatible_p(double, double)); + ASSERT(0, __builtin_types_compatible_p(int, long)); + ASSERT(0, __builtin_types_compatible_p(long, float)); + ASSERT(1, __builtin_types_compatible_p(int *, int *)); + ASSERT(0, __builtin_types_compatible_p(short *, int *)); + ASSERT(0, __builtin_types_compatible_p(int **, int *)); + ASSERT(1, __builtin_types_compatible_p(const int, int)); + ASSERT(0, __builtin_types_compatible_p(unsigned, int)); + ASSERT(1, __builtin_types_compatible_p(signed, int)); + ASSERT(0, __builtin_types_compatible_p( + struct { int a; }, struct { int a; })); + ASSERT(1, __builtin_types_compatible_p(int (*)(void), int (*)(void))); + ASSERT(1, __builtin_types_compatible_p(void (*)(int), void (*)(int))); + ASSERT(1, __builtin_types_compatible_p(void (*)(int, double), + void (*)(int, double))); + ASSERT(1, __builtin_types_compatible_p(int (*)(float, double), + int (*)(float, double))); + ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int)); + ASSERT(0, + __builtin_types_compatible_p(int (*)(float, double), int (*)(float))); + ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), + int (*)(float, double, int))); + ASSERT(1, __builtin_types_compatible_p(double (*)(...), double (*)(...))); + ASSERT(0, __builtin_types_compatible_p(double (*)(...), double (*)(void))); + ASSERT(1, ({ + typedef struct { + int a; + } T; + __builtin_types_compatible_p(T, T); + })); + ASSERT(1, ({ + typedef struct { + int a; + } T; + __builtin_types_compatible_p(T, const T); + })); + ASSERT(1, ({ + struct { + int a; + int b; + } x; + __builtin_types_compatible_p(typeof(x.a), typeof(x.b)); + })); +} + +void test_offsetof(void) { + ASSERT(0, ({ + struct T { + int a; + int b; + }; + __builtin_offsetof(struct T, a); + })); + ASSERT(4, ({ + struct T { + int a; + int b; + }; + __builtin_offsetof(struct T, b); + })); +} + +int main() { + test_constant(); + test_types_compatible_p(); + test_clz(); + test_ctz(); + test_ffs(); + test_bswap(); + test_popcnt(); + test_inf(); + test_nan(); + test_double(); + test_fpclassify(); + test_signbit(); + test_memcpy(); + test_offsetof(); + return 0; +} diff --git a/third_party/chibicc/test/cast_test.c b/third_party/chibicc/test/cast_test.c new file mode 100644 index 00000000..35036fd1 --- /dev/null +++ b/third_party/chibicc/test/cast_test.c @@ -0,0 +1,80 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(131585, (int)8590066177); + ASSERT(513, (short)8590066177); + ASSERT(1, (char)8590066177); + ASSERT(1, (long)1); + ASSERT(0, (long)&*(int *)0); + ASSERT(513, ({ + int x = 512; + *(char *)&x = 1; + x; + })); + ASSERT(5, ({ + int x = 5; + long y = (long)&x; + *(int *)y; + })); + + (void)1; + + ASSERT(-1, (char)255); + ASSERT(-1, (signed char)255); + ASSERT(255, (unsigned char)255); + ASSERT(-1, (short)65535); + ASSERT(65535, (unsigned short)65535); + ASSERT(-1, (int)0xffffffff); + ASSERT(0xffffffff, (unsigned)0xffffffff); + + ASSERT(1, -1 < 1); + ASSERT(0, -1 < (unsigned)1); + ASSERT(254, (char)127 + (char)127); + ASSERT(65534, (short)32767 + (short)32767); + ASSERT(-1, -1 >> 1); + ASSERT(-1, (unsigned long)-1); + ASSERT(2147483647, ((unsigned)-1) >> 1); + ASSERT(-50, (-100) / 2); + ASSERT(2147483598, ((unsigned)-100) / 2); + ASSERT(9223372036854775758, ((unsigned long)-100) / 2); + ASSERT(0, ((long)-1) / (unsigned)100); + ASSERT(-2, (-100) % 7); + ASSERT(2, ((unsigned)-100) % 7); + ASSERT(6, ((unsigned long)-100) % 9); + + ASSERT(65535, (int)(unsigned short)65535); + ASSERT(65535, ({ + unsigned short x = 65535; + x; + })); + ASSERT(65535, ({ + unsigned short x = 65535; + (int)x; + })); + + ASSERT(-1, ({ + typedef short T; + T x = 65535; + (int)x; + })); + ASSERT(65535, ({ + typedef unsigned short T; + T x = 65535; + (int)x; + })); + + ASSERT(0, (_Bool)0.0); + ASSERT(1, (_Bool)0.1); + ASSERT(3, (char)3.0); + ASSERT(1000, (short)1000.3); + ASSERT(3, (int)3.99); + ASSERT(2000000000000000, (long)2e15); + ASSERT(3, (float)3.5); + ASSERT(5, (double)(float)5.5); + ASSERT(3, (float)3); + ASSERT(3, (double)3); + ASSERT(3, (float)3L); + ASSERT(3, (double)3L); + + return 0; +} diff --git a/third_party/chibicc/test/common.c b/third_party/chibicc/test/common.c new file mode 100644 index 00000000..baada926 --- /dev/null +++ b/third_party/chibicc/test/common.c @@ -0,0 +1,195 @@ +#include "third_party/chibicc/test/test.h" + +void Assert(long expected, long actual, char *code) { + if (expected != actual) { + fprintf(stderr, "%s => %ld expected but got %ld\n", code, expected, actual); + exit(1); + } +} + +void Assert2(long expected, long actual, char *code, char *func, int line) { + if (expected != actual) { + fprintf(stderr, "%s:%d: %s => expected %ld but got %ld\n", func, line, code, + expected, actual); + exit(1); + } +} + +void Assert128(__int128 k, __int128 x, char *code, char *func, int line) { + if (k != x) { + fprintf(stderr, "%s:%d: %s => want %jd but got %jd\n", func, line, code, k, + x); + exit(1); + } +} + +static int static_fn() { + return 5; +} + +int ext1 = 5; +int *ext2 = &ext1; +int ext3 = 7; + +int ext_fn1(int x) { + return x; +} + +int ext_fn2(int x) { + return x; +} + +int common_ext2 = 3; +static int common_local; + +int false_fn() { + return 512; +} + +int true_fn() { + return 513; +} + +int char_fn() { + return (2 << 8) + 3; +} + +int short_fn() { + return (2 << 16) + 5; +} + +int uchar_fn() { + return (2 << 10) - 1 - 4; +} + +int ushort_fn() { + return (2 << 20) - 1 - 7; +} + +int schar_fn() { + return (2 << 10) - 1 - 4; +} + +int sshort_fn() { + return (2 << 20) - 1 - 7; +} + +int add_all(int n, ...) { + va_list ap; + va_start(ap, n); + int sum = 0; + for (int i = 0; i < n; i++) sum += va_arg(ap, int); + va_end(ap); + return sum; +} + +float add_float(float x, float y) { + return x + y; +} + +double add_double(double x, double y) { + return x + y; +} + +int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, + int x9, int x10) { + return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; +} + +float add10_float(float x1, float x2, float x3, float x4, float x5, float x6, + float x7, float x8, float x9, float x10) { + return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; +} + +double add10_double(double x1, double x2, double x3, double x4, double x5, + double x6, double x7, double x8, double x9, double x10) { + return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; +} + +typedef struct { + int a, b; + short c; + char d; +} Ty4; + +typedef struct { + int a; + float b; + double c; +} Ty5; + +typedef struct { + unsigned char a[3]; +} Ty6; + +typedef struct { + long a, b, c; +} Ty7; + +int struct_test4(Ty4 x, int n) { + switch (n) { + case 0: + return x.a; + case 1: + return x.b; + case 2: + return x.c; + default: + return x.d; + } +} + +int struct_test5(Ty5 x, int n) { + switch (n) { + case 0: + return x.a; + case 1: + return x.b; + default: + return x.c; + } +} + +int struct_test6(Ty6 x, int n) { + return x.a[n]; +} + +int struct_test7(Ty7 x, int n) { + switch (n) { + case 0: + return x.a; + case 1: + return x.b; + default: + return x.c; + } +} + +Ty4 struct_test24(void) { + return (Ty4){10, 20, 30, 40}; +} + +Ty5 struct_test25(void) { + return (Ty5){10, 20, 30}; +} + +Ty6 struct_test26(void) { + return (Ty6){{10, 20, 30}}; +} + +typedef struct { + unsigned char a[10]; +} Ty20; + +typedef struct { + unsigned char a[20]; +} Ty21; + +Ty20 struct_test27(void) { + return (Ty20){{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}}; +} + +Ty21 struct_test28(void) { + return (Ty21){ + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}}; +} diff --git a/third_party/chibicc/test/compat_test.c b/third_party/chibicc/test/compat_test.c new file mode 100644 index 00000000..b6398ee8 --- /dev/null +++ b/third_party/chibicc/test/compat_test.c @@ -0,0 +1,18 @@ +#include "third_party/chibicc/test/test.h" + +_Noreturn noreturn_fn(int restrict x) { + exit(0); +} + +void funcy_type(int arg[restrict static 3]) { +} + +int main() { + { volatile x; } + { int volatile x; } + { volatile int x; } + { volatile int volatile volatile x; } + { int volatile *volatile volatile x; } + { auto **restrict __restrict __restrict__ const volatile *x; } + return 0; +} diff --git a/third_party/chibicc/test/complit_test.c b/third_party/chibicc/test/complit_test.c new file mode 100644 index 00000000..4caf08ee --- /dev/null +++ b/third_party/chibicc/test/complit_test.c @@ -0,0 +1,31 @@ +#include "third_party/chibicc/test/test.h" + +typedef struct Tree { + int val; + struct Tree *lhs; + struct Tree *rhs; +} Tree; + +Tree *tree = &(Tree){1, &(Tree){2, &(Tree){3, 0, 0}, &(Tree){4, 0, 0}}, 0}; + +int main() { + ASSERT(1, (int){1}); + ASSERT(2, ((int[]){0, 1, 2})[2]); + ASSERT('a', ((struct { + char a; + int b; + }){'a', 3}) + .a); + ASSERT(3, ({ + int x = 3; + (int){x}; + })); + (int){3} = 5; + + ASSERT(1, tree->val); + ASSERT(2, tree->lhs->val); + ASSERT(3, tree->lhs->lhs->val); + ASSERT(4, tree->lhs->rhs->val); + + return 0; +} diff --git a/third_party/chibicc/test/const_test.c b/third_party/chibicc/test/const_test.c new file mode 100644 index 00000000..0df89d47 --- /dev/null +++ b/third_party/chibicc/test/const_test.c @@ -0,0 +1,23 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + { const x; } + { int const x; } + { const int x; } + { const int const const x; } + ASSERT(5, ({ + const x = 5; + x; + })); + ASSERT(8, ({ + const x = 8; + int *const y = &x; + *y; + })); + ASSERT(6, ({ + const x = 6; + *(const *const) & x; + })); + + return 0; +} diff --git a/third_party/chibicc/test/constexpr_test.c b/third_party/chibicc/test/constexpr_test.c new file mode 100644 index 00000000..580a3c3b --- /dev/null +++ b/third_party/chibicc/test/constexpr_test.c @@ -0,0 +1,181 @@ +#include "third_party/chibicc/test/test.h" + +float g40 = 1.5; +double g41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (double)2 * (int)2.0); + +int main() { + ASSERT(10, ({ + enum { ten = 1 + 2 + 3 + 4 }; + ten; + })); + ASSERT(1, ({ + int i = 0; + switch (3) { + case 5 - 2 + 0 * 3: + i++; + } + i; + })); + ASSERT(8, ({ + int x[1 + 1]; + sizeof(x); + })); + ASSERT(6, ({ + char x[8 - 2]; + sizeof(x); + })); + ASSERT(6, ({ + char x[2 * 3]; + sizeof(x); + })); + ASSERT(3, ({ + char x[12 / 4]; + sizeof(x); + })); + ASSERT(2, ({ + char x[12 % 10]; + sizeof(x); + })); + ASSERT(0b100, ({ + char x[0b110 & 0b101]; + sizeof(x); + })); + ASSERT(0b111, ({ + char x[0b110 | 0b101]; + sizeof(x); + })); + ASSERT(0b110, ({ + char x[0b111 ^ 0b001]; + sizeof(x); + })); + ASSERT(4, ({ + char x[1 << 2]; + sizeof(x); + })); + ASSERT(2, ({ + char x[4 >> 1]; + sizeof(x); + })); + ASSERT(2, ({ + char x[(1 == 1) + 1]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(1 != 1) + 1]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(1 < 1) + 1]; + sizeof(x); + })); + ASSERT(2, ({ + char x[(1 <= 1) + 1]; + sizeof(x); + })); + ASSERT(2, ({ + char x[1 ? 2 : 3]; + sizeof(x); + })); + ASSERT(3, ({ + char x[0 ? 2 : 3]; + sizeof(x); + })); + ASSERT(3, ({ + char x[(1, 3)]; + sizeof(x); + })); + ASSERT(2, ({ + char x[!0 + 1]; + sizeof(x); + })); + ASSERT(1, ({ + char x[!1 + 1]; + sizeof(x); + })); + ASSERT(2, ({ + char x[~-3]; + sizeof(x); + })); + ASSERT(2, ({ + char x[(5 || 6) + 1]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(0 || 0) + 1]; + sizeof(x); + })); + ASSERT(2, ({ + char x[(1 && 1) + 1]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(1 && 0) + 1]; + sizeof(x); + })); + ASSERT(3, ({ + char x[(int)3]; + sizeof(x); + })); + ASSERT(15, ({ + char x[(char)0xffffff0f]; + sizeof(x); + })); + ASSERT(0x10f, ({ + char x[(short)0xffff010f]; + sizeof(x); + })); + ASSERT(4, ({ + char x[(int)0xfffffffffff + 5]; + sizeof(x); + })); + ASSERT(8, ({ + char x[(int*)0 + 2]; + sizeof(x); + })); + ASSERT(12, ({ + char x[(int*)16 - 1]; + sizeof(x); + })); + ASSERT(3, ({ + char x[(int*)16 - (int*)4]; + sizeof(x); + })); + + ASSERT(4, ({ + char x[(-1 >> 31) + 5]; + sizeof(x); + })); + ASSERT(255, ({ + char x[(unsigned char)0xffffffff]; + sizeof(x); + })); + ASSERT(0x800f, ({ + char x[(unsigned short)0xffff800f]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(unsigned int)0xfffffffffff >> 31]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(long)-1 / ((long)1 << 62) + 1]; + sizeof(x); + })); + ASSERT(4, ({ + char x[(unsigned long)-1 / ((long)1 << 62) + 1]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(unsigned)1 < -1]; + sizeof(x); + })); + ASSERT(1, ({ + char x[(unsigned)1 <= -1]; + sizeof(x); + })); + + ASSERT(1, g40 == 1.5); + ASSERT(1, g41 == 11); + + return 0; +} diff --git a/third_party/chibicc/test/control_test.c b/third_party/chibicc/test/control_test.c new file mode 100644 index 00000000..807e7bf2 --- /dev/null +++ b/third_party/chibicc/test/control_test.c @@ -0,0 +1,542 @@ +#include "third_party/chibicc/test/test.h" + +/* + * This is a block comment. + */ + +int main() { + ASSERT(3, ({ + int x; + if (0) + x = 2; + else + x = 3; + x; + })); + ASSERT(3, ({ + int x; + if (1 - 1) + x = 2; + else + x = 3; + x; + })); + ASSERT(2, ({ + int x; + if (1) + x = 2; + else + x = 3; + x; + })); + ASSERT(2, ({ + int x; + if (2 - 1) + x = 2; + else + x = 3; + x; + })); + + ASSERT(55, ({ + int i = 0; + int j = 0; + for (i = 0; i <= 10; i = i + 1) j = i + j; + j; + })); + + ASSERT(10, ({ + int i = 0; + while (i < 10) i = i + 1; + i; + })); + + ASSERT(3, ({ + 1; + { 2; } + 3; + })); + ASSERT(5, ({ + ; + ; + ; + 5; + })); + + ASSERT(10, ({ + int i = 0; + while (i < 10) i = i + 1; + i; + })); + ASSERT(55, ({ + int i = 0; + int j = 0; + while (i <= 10) { + j = i + j; + i = i + 1; + } + j; + })); + + ASSERT(3, (1, 2, 3)); + ASSERT(5, ({ + int i = 2, j = 3; + (i = 5, j) = 6; + i; + })); + ASSERT(6, ({ + int i = 2, j = 3; + (i = 5, j) = 6; + j; + })); + + ASSERT(55, ({ + int j = 0; + for (int i = 0; i <= 10; i = i + 1) j = j + i; + j; + })); + ASSERT(3, ({ + int i = 3; + int j = 0; + for (int i = 0; i <= 10; i = i + 1) j = j + i; + i; + })); + + ASSERT(1, 0 || 1); + ASSERT(1, 0 || (2 - 2) || 5); + ASSERT(0, 0 || 0); + ASSERT(0, 0 || (2 - 2)); + + ASSERT(0, 0 && 1); + ASSERT(0, (2 - 2) && 5); + ASSERT(1, 1 && 5); + + ASSERT(3, ({ + int i = 0; + goto a; + a: + i++; + b: + i++; + c: + i++; + i; + })); + ASSERT(2, ({ + int i = 0; + goto e; + d: + i++; + e: + i++; + f: + i++; + i; + })); + ASSERT(1, ({ + int i = 0; + goto i; + g: + i++; + h: + i++; + i: + i++; + i; + })); + + ASSERT(1, ({ + typedef int foo; + goto foo; + foo:; + 1; + })); + + ASSERT(3, ({ + int i = 0; + for (; i < 10; i++) { + if (i == 3) break; + } + i; + })); + ASSERT(4, ({ + int i = 0; + while (1) { + if (i++ == 3) break; + } + i; + })); + ASSERT(3, ({ + int i = 0; + for (; i < 10; i++) { + for (;;) break; + if (i == 3) break; + } + i; + })); + ASSERT(4, ({ + int i = 0; + while (1) { + while (1) break; + if (i++ == 3) break; + } + i; + })); + + ASSERT(10, ({ + int i = 0; + int j = 0; + for (; i < 10; i++) { + if (i > 5) continue; + j++; + } + i; + })); + ASSERT(6, ({ + int i = 0; + int j = 0; + for (; i < 10; i++) { + if (i > 5) continue; + j++; + } + j; + })); + ASSERT(10, ({ + int i = 0; + int j = 0; + for (; !i;) { + for (; j != 10; j++) continue; + break; + } + j; + })); + ASSERT(11, ({ + int i = 0; + int j = 0; + while (i++ < 10) { + if (i > 5) continue; + j++; + } + i; + })); + ASSERT(5, ({ + int i = 0; + int j = 0; + while (i++ < 10) { + if (i > 5) continue; + j++; + } + j; + })); + ASSERT(11, ({ + int i = 0; + int j = 0; + while (!i) { + while (j++ != 10) continue; + break; + } + j; + })); + + ASSERT(5, ({ + int i = 0; + switch (0) { + case 0: + i = 5; + break; + case 1: + i = 6; + break; + case 2: + i = 7; + break; + } + i; + })); + ASSERT(6, ({ + int i = 0; + switch (1) { + case 0: + i = 5; + break; + case 1: + i = 6; + break; + case 2: + i = 7; + break; + } + i; + })); + ASSERT(7, ({ + int i = 0; + switch (2) { + case 0: + i = 5; + break; + case 1: + i = 6; + break; + case 2: + i = 7; + break; + } + i; + })); + ASSERT(0, ({ + int i = 0; + switch (3) { + case 0: + i = 5; + break; + case 1: + i = 6; + break; + case 2: + i = 7; + break; + } + i; + })); + ASSERT(5, ({ + int i = 0; + switch (0) { + case 0: + i = 5; + break; + default: + i = 7; + } + i; + })); + ASSERT(7, ({ + int i = 0; + switch (1) { + case 0: + i = 5; + break; + default: + i = 7; + } + i; + })); + ASSERT(2, ({ + int i = 0; + switch (1) { + case 0: + 0; + case 1: + 0; + case 2: + 0; + i = 2; + } + i; + })); + ASSERT(0, ({ + int i = 0; + switch (3) { + case 0: + 0; + case 1: + 0; + case 2: + 0; + i = 2; + } + i; + })); + + ASSERT(3, ({ + int i = 0; + switch (-1) { + case 0xffffffff: + i = 3; + break; + } + i; + })); + + ASSERT(7, ({ + int i = 0; + int j = 0; + do { + j++; + } while (i++ < 6); + j; + })); + ASSERT(4, ({ + int i = 0; + int j = 0; + int k = 0; + do { + if (++j > 3) break; + continue; + k++; + } while (1); + j; + })); + + ASSERT(0, 0.0 && 0.0); + ASSERT(0, 0.0 && 0.1); + ASSERT(0, 0.3 && 0.0); + ASSERT(1, 0.3 && 0.5); + ASSERT(0, 0.0 || 0.0); + ASSERT(1, 0.0 || 0.1); + ASSERT(1, 0.3 || 0.0); + ASSERT(1, 0.3 || 0.5); + ASSERT(5, ({ + int x; + if (0.0) + x = 3; + else + x = 5; + x; + })); + ASSERT(3, ({ + int x; + if (0.1) + x = 3; + else + x = 5; + x; + })); + ASSERT(5, ({ + int x = 5; + if (0.0) x = 3; + x; + })); + ASSERT(3, ({ + int x = 5; + if (0.1) x = 3; + x; + })); + ASSERT(10, ({ + double i = 10.0; + int j = 0; + for (; i; i--, j++) + ; + j; + })); + ASSERT(10, ({ + double i = 10.0; + int j = 0; + do + j++; + while (--i); + j; + })); + + ASSERT(2, ({ + int i = 0; + switch (7) { + case 0 ... 5: + i = 1; + break; + case 6 ... 20: + i = 2; + break; + } + i; + })); + ASSERT(1, ({ + int i = 0; + switch (7) { + case 0 ... 7: + i = 1; + break; + case 8 ... 10: + i = 2; + break; + } + i; + })); + ASSERT(1, ({ + int i = 0; + switch (7) { + case 0: + i = 1; + break; + case 7 ... 7: + i = 1; + break; + } + i; + })); + + ASSERT(3, ({ + void *p = &&v11; + int i = 0; + goto *p; + v11: + i++; + v12: + i++; + v13: + i++; + i; + })); + ASSERT(2, ({ + void *p = &&v22; + int i = 0; + goto *p; + v21: + i++; + v22: + i++; + v23: + i++; + i; + })); + ASSERT(1, ({ + void *p = &&v33; + int i = 0; + goto *p; + v31: + i++; + v32: + i++; + v33: + i++; + i; + })); + + ASSERT(3, ({ + static void *p[] = {&&v41, &&v42, &&v43}; + int i = 0; + goto *p[0]; + v41: + i++; + v42: + i++; + v43: + i++; + i; + })); + ASSERT(2, ({ + static void *p[] = {&&v52, &&v52, &&v53}; + int i = 0; + goto *p[1]; + v51: + i++; + v52: + i++; + v53: + i++; + i; + })); + ASSERT(1, ({ + static void *p[] = {&&v62, &&v62, &&v63}; + int i = 0; + goto *p[2]; + v61: + i++; + v62: + i++; + v63: + i++; + i; + })); + + return 0; +} diff --git a/third_party/chibicc/test/decl_test.c b/third_party/chibicc/test/decl_test.c new file mode 100644 index 00000000..38733f07 --- /dev/null +++ b/third_party/chibicc/test/decl_test.c @@ -0,0 +1,51 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(1, ({ + char x; + sizeof(x); + })); + ASSERT(2, ({ + short int x; + sizeof(x); + })); + ASSERT(2, ({ + int short x; + sizeof(x); + })); + ASSERT(4, ({ + int x; + sizeof(x); + })); + ASSERT(8, ({ + long int x; + sizeof(x); + })); + ASSERT(8, ({ + int long x; + sizeof(x); + })); + + ASSERT(8, ({ + long long x; + sizeof(x); + })); + + ASSERT(0, ({ + _Bool x = 0; + x; + })); + ASSERT(1, ({ + _Bool x = 1; + x; + })); + ASSERT(1, ({ + _Bool x = 2; + x; + })); + ASSERT(1, (_Bool)1); + ASSERT(1, (_Bool)2); + ASSERT(0, (_Bool)(char)256); + + return 0; +} diff --git a/third_party/chibicc/test/enum_test.c b/third_party/chibicc/test/enum_test.c new file mode 100644 index 00000000..89b280e6 --- /dev/null +++ b/third_party/chibicc/test/enum_test.c @@ -0,0 +1,50 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(0, ({ + enum { zero, one, two }; + zero; + })); + ASSERT(1, ({ + enum { zero, one, two }; + one; + })); + ASSERT(2, ({ + enum { zero, one, two }; + two; + })); + ASSERT(5, ({ + enum { five = 5, six, seven }; + five; + })); + ASSERT(6, ({ + enum { five = 5, six, seven }; + six; + })); + ASSERT(0, ({ + enum { zero, five = 5, three = 3, four }; + zero; + })); + ASSERT(5, ({ + enum { zero, five = 5, three = 3, four }; + five; + })); + ASSERT(3, ({ + enum { zero, five = 5, three = 3, four }; + three; + })); + ASSERT(4, ({ + enum { zero, five = 5, three = 3, four }; + four; + })); + ASSERT(4, ({ + enum { zero, one, two } x; + sizeof(x); + })); + ASSERT(4, ({ + enum t { zero, one, two }; + enum t y; + sizeof(y); + })); + return 0; +} diff --git a/third_party/chibicc/test/extern_test.c b/third_party/chibicc/test/extern_test.c new file mode 100644 index 00000000..41850f1e --- /dev/null +++ b/third_party/chibicc/test/extern_test.c @@ -0,0 +1,24 @@ +#include "third_party/chibicc/test/test.h" + +extern int ext1; +extern int *ext2; + +inline int inline_fn(void) { + return 3; +} + +int main() { + ASSERT(5, ext1); + ASSERT(5, *ext2); + + extern int ext3; + ASSERT(7, ext3); + + int ext_fn1(int x); + ASSERT(5, ext_fn1(5)); + + extern int ext_fn2(int x); + ASSERT(8, ext_fn2(8)); + + return 0; +} diff --git a/third_party/chibicc/test/float_test.c b/third_party/chibicc/test/float_test.c new file mode 100644 index 00000000..7a2fc250 --- /dev/null +++ b/third_party/chibicc/test/float_test.c @@ -0,0 +1,92 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(35, (float)(char)35); + ASSERT(35, (float)(short)35); + ASSERT(35, (float)(int)35); + ASSERT(35, (float)(long)35); + ASSERT(35, (float)(unsigned char)35); + ASSERT(35, (float)(unsigned short)35); + ASSERT(35, (float)(unsigned int)35); + ASSERT(35, (float)(unsigned long)35); + + ASSERT(35, (double)(char)35); + ASSERT(35, (double)(short)35); + ASSERT(35, (double)(int)35); + ASSERT(35, (double)(long)35); + ASSERT(35, (double)(unsigned char)35); + ASSERT(35, (double)(unsigned short)35); + ASSERT(35, (double)(unsigned int)35); + ASSERT(35, (double)(unsigned long)35); + + ASSERT(35, (char)(float)35); + ASSERT(35, (short)(float)35); + ASSERT(35, (int)(float)35); + ASSERT(35, (long)(float)35); + ASSERT(35, (unsigned char)(float)35); + ASSERT(35, (unsigned short)(float)35); + ASSERT(35, (unsigned int)(float)35); + ASSERT(35, (unsigned long)(float)35); + + ASSERT(35, (char)(double)35); + ASSERT(35, (short)(double)35); + ASSERT(35, (int)(double)35); + ASSERT(35, (long)(double)35); + ASSERT(35, (unsigned char)(double)35); + ASSERT(35, (unsigned short)(double)35); + ASSERT(35, (unsigned int)(double)35); + ASSERT(35, (unsigned long)(double)35); + + ASSERT(0x8000000000000000, (double)(unsigned long)(long)-1); + + ASSERT(1, 2e3 == 2e3); + ASSERT(0, 2e3 == 2e5); + ASSERT(1, 2.0 == 2); + ASSERT(0, 5.1 < 5); + ASSERT(0, 5.0 < 5); + ASSERT(1, 4.9 < 5); + ASSERT(0, 5.1 <= 5); + ASSERT(1, 5.0 <= 5); + ASSERT(1, 4.9 <= 5); + + ASSERT(1, 2e3f == 2e3); + ASSERT(0, 2e3f == 2e5); + ASSERT(1, 2.0f == 2); + ASSERT(0, 5.1f < 5); + ASSERT(0, 5.0f < 5); + ASSERT(1, 4.9f < 5); + ASSERT(0, 5.1f <= 5); + ASSERT(1, 5.0f <= 5); + ASSERT(1, 4.9f <= 5); + + ASSERT(6, 2.3 + 3.8); + ASSERT(-1, 2.3 - 3.8); + ASSERT(-3, -3.8); + ASSERT(13, 3.3 * 4); + ASSERT(2, 5.0 / 2); + + ASSERT(6, 2.3f + 3.8f); + ASSERT(6, 2.3f + 3.8); + ASSERT(-1, 2.3f - 3.8); + ASSERT(-3, -3.8f); + ASSERT(13, 3.3f * 4); + ASSERT(2, 5.0f / 2); + + ASSERT(0, 0.0 / 0.0 == 0.0 / 0.0); + ASSERT(1, 0.0 / 0.0 != 0.0 / 0.0); + + ASSERT(0, 0.0 / 0.0 < 0); + ASSERT(0, 0.0 / 0.0 <= 0); + ASSERT(0, 0.0 / 0.0 > 0); + ASSERT(0, 0.0 / 0.0 >= 0); + + ASSERT(0, !3.); + ASSERT(1, !0.); + ASSERT(0, !3.f); + ASSERT(1, !0.f); + + ASSERT(5, 0.0 ? 3 : 5); + ASSERT(3, 1.2 ? 3 : 5); + + return 0; +} diff --git a/third_party/chibicc/test/function_test.c b/third_party/chibicc/test/function_test.c new file mode 100644 index 00000000..623be40e --- /dev/null +++ b/third_party/chibicc/test/function_test.c @@ -0,0 +1,534 @@ +#include "third_party/chibicc/test/test.h" + +int ret3(void) { + return 3; + return 5; +} + +int add2(int x, int y) { + return x + y; +} + +int sub2(int x, int y) { + return x - y; +} + +int add6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} + +int addx(int *x, int y) { + return *x + y; +} + +int sub_char(char a, char b, char c) { + return a - b - c; +} + +int fib(int x) { + if (x <= 1) return 1; + return fib(x - 1) + fib(x - 2); +} + +int sub_long(long a, long b, long c) { + return a - b - c; +} + +int sub_short(short a, short b, short c) { + return a - b - c; +} + +int g1; + +int *g1_ptr(void) { + return &g1; +} +char int_to_char(int x) { + return x; +} + +int div_long(long a, long b) { + return a / b; +} + +_Bool bool_fn_add(_Bool x) { + return x + 1; +} +_Bool bool_fn_sub(_Bool x) { + return x - 1; +} + +static int static_fn(void) { + return 3; +} + +int param_decay(int x[]) { + return x[0]; +} + +int counter() { + static int i; + static int j = 1 + 1; + return i++ + j++; +} + +void ret_none() { + return; +} + +_Bool true_fn(); +_Bool false_fn(); +char char_fn(); +short short_fn(); + +unsigned char uchar_fn(); +unsigned short ushort_fn(); + +char schar_fn(); +short sshort_fn(); + +int add_all(int n, ...); + +typedef struct { + int gp_offset; + int fp_offset; + void *overflow_arg_area; + void *reg_save_area; +} __va_elem; + +typedef __va_elem va_list[1]; + +int add_all(int n, ...); +int sprintf(char *buf, char *fmt, ...); +int vsprintf(char *buf, char *fmt, va_list ap); + +char *fmt(char *buf, char *fmt, ...) { + va_list ap; + *ap = *(__va_elem *)__va_area__; + vsprintf(buf, fmt, ap); +} + +double add_double(double x, double y); +float add_float(float x, float y); + +float add_float3(float x, float y, float z) { + return x + y + z; +} + +double add_double3(double x, double y, double z) { + return x + y + z; +} + +int (*fnptr(int (*fn)(int n, ...)))(int, ...) { + return fn; +} + +int param_decay2(int x()) { + return x(); +} + +char *func_fn(void) { + return __func__; +} + +char *function_fn(void) { + return __FUNCTION__; +} + +int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, + int x9, int x10); +float add10_float(float x1, float x2, float x3, float x4, float x5, float x6, + float x7, float x8, float x9, float x10); +double add10_double(double x1, double x2, double x3, double x4, double x5, + double x6, double x7, double x8, double x9, double x10); + +int many_args1(int a, int b, int c, int d, int e, int f, int g, int h) { + return g / h; +} + +double many_args2(double a, double b, double c, double d, double e, double f, + double g, double h, double i, double j) { + return i / j; +} + +int many_args3(int a, double b, int c, int d, double e, int f, double g, int h, + double i, double j, double k, double l, double m, int n, int o, + double p) { + return o / p; +} + +typedef struct { + int a, b; + short c; + char d; +} Ty4; +typedef struct { + int a; + float b; + double c; +} Ty5; +typedef struct { + unsigned char a[3]; +} Ty6; +typedef struct { + long a, b, c; +} Ty7; + +int struct_test5(Ty5 x, int n); +int struct_test4(Ty4 x, int n); +int struct_test6(Ty6 x, int n); +int struct_test7(Ty7 x, int n); + +int struct_test14(Ty4 x, int n) { + switch (n) { + case 0: + return x.a; + case 1: + return x.b; + case 2: + return x.c; + default: + return x.d; + } +} + +int struct_test15(Ty5 x, int n) { + switch (n) { + case 0: + return x.a; + case 1: + return x.b; + default: + return x.c; + } +} + +typedef struct { + unsigned char a[10]; +} Ty20; +typedef struct { + unsigned char a[20]; +} Ty21; + +Ty4 struct_test24(void); +Ty5 struct_test25(void); +Ty6 struct_test26(void); +Ty20 struct_test27(void); +Ty21 struct_test28(void); + +Ty4 struct_test34(void) { + return (Ty4){10, 20, 30, 40}; +} + +Ty5 struct_test35(void) { + return (Ty5){10, 20, 30}; +} + +Ty6 struct_test36(void) { + return (Ty6){10, 20, 30}; +} + +Ty20 struct_test37(void) { + return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; +} + +Ty21 struct_test38(void) { + return (Ty21){1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; +} + +inline int inline_fn(void) { + return 3; +} + +double to_double(long double x) { + return x; +} + +long double to_ldouble(int x) { + return x; +} + +int main() { + FILE *f = fopen("/dev/null", "w"); + + ASSERT(3, ret3()); + ASSERT(8, add2(3, 5)); + ASSERT(2, sub2(5, 3)); + ASSERT(21, add6(1, 2, 3, 4, 5, 6)); + ASSERT(66, add6(1, 2, add6(3, 4, 5, 6, 7, 8), 9, 10, 11)); + ASSERT(136, add6(1, 2, add6(3, add6(4, 5, 6, 7, 8, 9), 10, 11, 12, 13), 14, + 15, 16)); + + ASSERT(7, add2(3, 4)); + ASSERT(1, sub2(4, 3)); + ASSERT(55, fib(9)); + + ASSERT(1, ({ sub_char(7, 3, 3); })); + + ASSERT(1, sub_long(7, 3, 3)); + ASSERT(1, sub_short(7, 3, 3)); + + g1 = 3; + + ASSERT(3, *g1_ptr()); + ASSERT(5, int_to_char(261)); + ASSERT(5, int_to_char(261)); + ASSERT(-5, div_long(-10, 2)); + + ASSERT(1, bool_fn_add(3)); + ASSERT(0, bool_fn_sub(3)); + ASSERT(1, bool_fn_add(-3)); + ASSERT(0, bool_fn_sub(-3)); + ASSERT(1, bool_fn_add(0)); + ASSERT(1, bool_fn_sub(0)); + + ASSERT(3, static_fn()); + + ASSERT(3, ({ + int x[2]; + x[0] = 3; + param_decay(x); + })); + + ASSERT(2, counter()); + ASSERT(4, counter()); + ASSERT(6, counter()); + + ret_none(); + + ASSERT(1, true_fn()); + ASSERT(0, false_fn()); + ASSERT(3, char_fn()); + ASSERT(5, short_fn()); + + ASSERT(6, add_all(3, 1, 2, 3)); + ASSERT(5, add_all(4, 1, 2, 3, -1)); + + { + char buf[100]; + fmt(buf, "%d %d %s", 1, 2, "foo"); + fprintf(f, "%s\n", buf); + } + + ASSERT(0, ({ + char buf[100]; + sprintf(buf, "%d %d %s", 1, 2, "foo"); + strcmp("1 2 foo", buf); + })); + + ASSERT(0, ({ + char buf[100]; + fmt(buf, "%d %d %s", 1, 2, "foo"); + strcmp("1 2 foo", buf); + })); + + ASSERT(251, uchar_fn()); + ASSERT(65528, ushort_fn()); + ASSERT(-5, schar_fn()); + ASSERT(-8, sshort_fn()); + + ASSERT(6, add_float(2.3, 3.8)); + ASSERT(6, add_double(2.3, 3.8)); + + ASSERT(7, add_float3(2.5, 2.5, 2.5)); + ASSERT(7, add_double3(2.5, 2.5, 2.5)); + + ASSERT(0, ({ + char buf[100]; + sprintf(buf, "%.1f", (float)3.5); + strcmp(buf, "3.5"); + })); + + ASSERT(0, ({ + char buf[100]; + fmt(buf, "%.1f", (float)3.5); + strcmp(buf, "3.5"); + })); + + ASSERT(5, (add2)(2, 3)); + ASSERT(5, (&add2)(2, 3)); + ASSERT(7, ({ + int (*fn)(int, int) = add2; + fn(2, 5); + })); + ASSERT(6, fnptr(add_all)(3, 1, 2, 3)); + + ASSERT(3, param_decay2(ret3)); + + ASSERT(5, sizeof(__func__)); + ASSERT(0, strcmp("main", __func__)); + ASSERT(0, strcmp("func_fn", func_fn())); + ASSERT(0, strcmp("main", __FUNCTION__)); + ASSERT(0, strcmp("function_fn", function_fn())); + + ASSERT(55, add10_int(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + ASSERT(55, add10_float(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + ASSERT(55, add10_double(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + + ASSERT(0, ({ + char buf[200]; + sprintf(buf, + "%d %.1f %.1f %.1f %d %d %.1f %d %d %d %d %.1f %d %d %.1f " + "%.1f %.1f %.1f %d", + 1, 1.0, 1.0, 1.0, 1, 1, 1.0, 1, 1, 1, 1, 1.0, 1, 1, 1.0, 1.0, + 1.0, 1.0, 1); + strcmp("1 1.0 1.0 1.0 1 1 1.0 1 1 1 1 1.0 1 1 1.0 1.0 1.0 1.0 1", + buf); + })); + + ASSERT(4, many_args1(1, 2, 3, 4, 5, 6, 40, 10)); + ASSERT(4, many_args2(1, 2, 3, 4, 5, 6, 7, 8, 40, 10)); + ASSERT(8, many_args3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 80, 10)); + + ASSERT(10, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test4(x, 0); + })); + ASSERT(20, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test4(x, 1); + })); + ASSERT(30, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test4(x, 2); + })); + ASSERT(40, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test4(x, 3); + })); + + ASSERT(10, ({ + Ty5 x = {10, 20, 30}; + struct_test5(x, 0); + })); + ASSERT(20, ({ + Ty5 x = {10, 20, 30}; + struct_test5(x, 1); + })); + ASSERT(30, ({ + Ty5 x = {10, 20, 30}; + struct_test5(x, 2); + })); + + ASSERT(10, ({ + Ty6 x = {10, 20, 30}; + struct_test6(x, 0); + })); + ASSERT(20, ({ + Ty6 x = {10, 20, 30}; + struct_test6(x, 1); + })); + ASSERT(30, ({ + Ty6 x = {10, 20, 30}; + struct_test6(x, 2); + })); + + ASSERT(10, ({ + Ty7 x = {10, 20, 30}; + struct_test7(x, 0); + })); + ASSERT(20, ({ + Ty7 x = {10, 20, 30}; + struct_test7(x, 1); + })); + ASSERT(30, ({ + Ty7 x = {10, 20, 30}; + struct_test7(x, 2); + })); + + ASSERT(10, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test14(x, 0); + })); + ASSERT(20, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test14(x, 1); + })); + ASSERT(30, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test14(x, 2); + })); + ASSERT(40, ({ + Ty4 x = {10, 20, 30, 40}; + struct_test14(x, 3); + })); + + ASSERT(10, ({ + Ty5 x = {10, 20, 30}; + struct_test15(x, 0); + })); + ASSERT(20, ({ + Ty5 x = {10, 20, 30}; + struct_test15(x, 1); + })); + ASSERT(30, ({ + Ty5 x = {10, 20, 30}; + struct_test15(x, 2); + })); + + ASSERT(10, struct_test24().a); + ASSERT(20, struct_test24().b); + ASSERT(30, struct_test24().c); + ASSERT(40, struct_test24().d); + + ASSERT(10, struct_test25().a); + ASSERT(20, struct_test25().b); + ASSERT(30, struct_test25().c); + + ASSERT(10, struct_test26().a[0]); + ASSERT(20, struct_test26().a[1]); + ASSERT(30, struct_test26().a[2]); + + ASSERT(10, struct_test27().a[0]); + ASSERT(60, struct_test27().a[5]); + ASSERT(100, struct_test27().a[9]); + + ASSERT(1, struct_test28().a[0]); + ASSERT(5, struct_test28().a[4]); + ASSERT(10, struct_test28().a[9]); + ASSERT(15, struct_test28().a[14]); + ASSERT(20, struct_test28().a[19]); + + ASSERT(10, struct_test34().a); + ASSERT(20, struct_test34().b); + ASSERT(30, struct_test34().c); + ASSERT(40, struct_test34().d); + + ASSERT(10, struct_test35().a); + ASSERT(20, struct_test35().b); + ASSERT(30, struct_test35().c); + + ASSERT(10, struct_test36().a[0]); + ASSERT(20, struct_test36().a[1]); + ASSERT(30, struct_test36().a[2]); + + ASSERT(10, struct_test37().a[0]); + ASSERT(60, struct_test37().a[5]); + ASSERT(100, struct_test37().a[9]); + + ASSERT(1, struct_test38().a[0]); + ASSERT(5, struct_test38().a[4]); + ASSERT(10, struct_test38().a[9]); + ASSERT(15, struct_test38().a[14]); + ASSERT(20, struct_test38().a[19]); + + ASSERT(5, (***add2)(2, 3)); + + ASSERT(3, inline_fn()); + + ASSERT(0, ({ + char buf[100]; + sprintf(buf, "%Lf", (long double)12.3); + strncmp(buf, "12.3", 4); + })); + + ASSERT(1, to_double(3.5) == 3.5); + ASSERT(0, to_double(3.5) == 3); + + ASSERT(1, (long double)5.0 == (long double)5.0); + ASSERT(0, (long double)5.0 == (long double)5.2); + + ASSERT(1, to_ldouble(5.0) == 5.0); + ASSERT(0, to_ldouble(5.0) == 5.2); +} diff --git a/third_party/chibicc/test/generic_test.c b/third_party/chibicc/test/generic_test.c new file mode 100644 index 00000000..41532e8b --- /dev/null +++ b/third_party/chibicc/test/generic_test.c @@ -0,0 +1,10 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(1, _Generic(100.0, double : 1, int * : 2, int : 3, float : 4)); + ASSERT(2, _Generic((int *)0, double : 1, int * : 2, int : 3, float : 4)); + ASSERT(2, _Generic((int[3]){}, double : 1, int * : 2, int : 3, float : 4)); + ASSERT(3, _Generic(100, double : 1, int * : 2, int : 3, float : 4)); + ASSERT(4, _Generic(100f, double : 1, int * : 2, int : 3, float : 4)); + return 0; +} diff --git a/third_party/chibicc/test/include1.h b/third_party/chibicc/test/include1.h new file mode 100644 index 00000000..5d8f5744 --- /dev/null +++ b/third_party/chibicc/test/include1.h @@ -0,0 +1,5 @@ +#include "third_party/chibicc/test/include2.h" + +char *include1_filename = __FILE__; +int include1_line = __LINE__; +int include1 = 5; diff --git a/third_party/chibicc/test/include2.h b/third_party/chibicc/test/include2.h new file mode 100644 index 00000000..1a5ee9dc --- /dev/null +++ b/third_party/chibicc/test/include2.h @@ -0,0 +1 @@ +int include2 = 7; diff --git a/third_party/chibicc/test/include3.h b/third_party/chibicc/test/include3.h new file mode 100644 index 00000000..820d4a6a --- /dev/null +++ b/third_party/chibicc/test/include3.h @@ -0,0 +1 @@ +#define foo 3 diff --git a/third_party/chibicc/test/include4.h b/third_party/chibicc/test/include4.h new file mode 100644 index 00000000..1fea1a23 --- /dev/null +++ b/third_party/chibicc/test/include4.h @@ -0,0 +1 @@ +#define foo 4 diff --git a/third_party/chibicc/test/initializer_test.c b/third_party/chibicc/test/initializer_test.c new file mode 100644 index 00000000..b119851d --- /dev/null +++ b/third_party/chibicc/test/initializer_test.c @@ -0,0 +1,793 @@ +#include "third_party/chibicc/test/test.h" + +char g3 = 3; +short g4 = 4; +int g5 = 5; +long g6 = 6; +int g9[3] = {0, 1, 2}; +struct { + char a; + int b; +} g11[2] = {{1, 2}, {3, 4}}; +struct { + int a[2]; +} g12[2] = {{{1, 2}}}; +union { + int a; + char b[8]; +} g13[2] = {0x01020304, 0x05060708}; +char g17[] = "foobar"; +char g18[10] = "foobar"; +char g19[3] = "foobar"; +char *g20 = g17 + 0; +char *g21 = g17 + 3; +char *g22 = &g17 - 3; +char *g23[] = {g17 + 0, g17 + 3, g17 - 3}; +int g24 = 3; +int *g25 = &g24; +int g26[3] = {1, 2, 3}; +int *g27 = g26 + 1; +int *g28 = &g11[1].a; +long g29 = (long)(long)g26; +struct { + struct { + int a[3]; + } a; +} g30 = {{{1, 2, 3}}}; +int *g31 = g30.a.a; +struct { + int a[2]; +} g40[2] = {{1, 2}, 3, 4}; +struct { + int a[2]; +} g41[2] = {1, 2, 3, 4}; +char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0}; +char *g44 = {"foo"}; +union { + int a; + char b[4]; +} g50 = {.b[2] = 0x12}; +union { + int a; +} g51[2] = {}; + +typedef char T60[]; +T60 g60 = {1, 2, 3}; +T60 g61 = {1, 2, 3, 4, 5, 6}; + +typedef struct { + char a, b[]; +} T65; +T65 g65 = {'f', 'o', 'o', 0}; +T65 g66 = {'f', 'o', 'o', 'b', 'a', 'r', 0}; + +int main() { + ASSERT(1, ({ + int x[3] = {1, 2, 3}; + x[0]; + })); + ASSERT(2, ({ + int x[3] = {1, 2, 3}; + x[1]; + })); + ASSERT(3, ({ + int x[3] = {1, 2, 3}; + x[2]; + })); + ASSERT(3, ({ + int x[3] = {1, 2, 3}; + x[2]; + })); + + ASSERT(2, ({ + int x[2][3] = {{1, 2, 3}, {4, 5, 6}}; + x[0][1]; + })); + ASSERT(4, ({ + int x[2][3] = {{1, 2, 3}, {4, 5, 6}}; + x[1][0]; + })); + ASSERT(6, ({ + int x[2][3] = {{1, 2, 3}, {4, 5, 6}}; + x[1][2]; + })); + + ASSERT(0, ({ + int x[3] = {}; + x[0]; + })); + ASSERT(0, ({ + int x[3] = {}; + x[1]; + })); + ASSERT(0, ({ + int x[3] = {}; + x[2]; + })); + + ASSERT(2, ({ + int x[2][3] = {{1, 2}}; + x[0][1]; + })); + ASSERT(0, ({ + int x[2][3] = {{1, 2}}; + x[1][0]; + })); + ASSERT(0, ({ + int x[2][3] = {{1, 2}}; + x[1][2]; + })); + + ASSERT('a', ({ + char x[4] = "abc"; + x[0]; + })); + ASSERT('c', ({ + char x[4] = "abc"; + x[2]; + })); + ASSERT(0, ({ + char x[4] = "abc"; + x[3]; + })); + ASSERT('a', ({ + char x[2][4] = {"abc", "def"}; + x[0][0]; + })); + ASSERT(0, ({ + char x[2][4] = {"abc", "def"}; + x[0][3]; + })); + ASSERT('d', ({ + char x[2][4] = {"abc", "def"}; + x[1][0]; + })); + ASSERT('f', ({ + char x[2][4] = {"abc", "def"}; + x[1][2]; + })); + + ASSERT(4, ({ + int x[] = {1, 2, 3, 4}; + x[3]; + })); + ASSERT(16, ({ + int x[] = {1, 2, 3, 4}; + sizeof(x); + })); + ASSERT(4, ({ + char x[] = "foo"; + sizeof(x); + })); + + ASSERT(4, ({ + typedef char T[]; + T x = "foo"; + T y = "x"; + sizeof(x); + })); + ASSERT(2, ({ + typedef char T[]; + T x = "foo"; + T y = "x"; + sizeof(y); + })); + ASSERT(2, ({ + typedef char T[]; + T x = "x"; + T y = "foo"; + sizeof(x); + })); + ASSERT(4, ({ + typedef char T[]; + T x = "x"; + T y = "foo"; + sizeof(y); + })); + + ASSERT(1, ({ + struct { + int a; + int b; + int c; + } x = {1, 2, 3}; + x.a; + })); + ASSERT(2, ({ + struct { + int a; + int b; + int c; + } x = {1, 2, 3}; + x.b; + })); + ASSERT(3, ({ + struct { + int a; + int b; + int c; + } x = {1, 2, 3}; + x.c; + })); + ASSERT(1, ({ + struct { + int a; + int b; + int c; + } x = {1}; + x.a; + })); + ASSERT(0, ({ + struct { + int a; + int b; + int c; + } x = {1}; + x.b; + })); + ASSERT(0, ({ + struct { + int a; + int b; + int c; + } x = {1}; + x.c; + })); + + ASSERT(1, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[0].a; + })); + ASSERT(2, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[0].b; + })); + ASSERT(3, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[1].a; + })); + ASSERT(4, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[1].b; + })); + + ASSERT(0, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}}; + x[1].b; + })); + + ASSERT(0, ({ + struct { + int a; + int b; + } x = {}; + x.a; + })); + ASSERT(0, ({ + struct { + int a; + int b; + } x = {}; + x.b; + })); + + ASSERT(5, ({ + typedef struct { + int a, b, c, d, e, f; + } T; + T x = {1, 2, 3, 4, 5, 6}; + T y; + y = x; + y.e; + })); + ASSERT(2, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y, z; + z = y = x; + z.b; + })); + + ASSERT(1, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y = x; + y.a; + })); + + ASSERT(4, ({ + union { + int a; + char b[4]; + } x = {0x01020304}; + x.b[0]; + })); + ASSERT(3, ({ + union { + int a; + char b[4]; + } x = {0x01020304}; + x.b[1]; + })); + + ASSERT(0x01020304, ({ + union { + struct { + char a, b, c, d; + } e; + int f; + } x = {{4, 3, 2, 1}}; + x.f; + })); + + ASSERT(3, g3); + ASSERT(4, g4); + ASSERT(5, g5); + ASSERT(6, g6); + + ASSERT(0, g9[0]); + ASSERT(1, g9[1]); + ASSERT(2, g9[2]); + + ASSERT(1, g11[0].a); + ASSERT(2, g11[0].b); + ASSERT(3, g11[1].a); + ASSERT(4, g11[1].b); + + ASSERT(1, g12[0].a[0]); + ASSERT(2, g12[0].a[1]); + ASSERT(0, g12[1].a[0]); + ASSERT(0, g12[1].a[1]); + + ASSERT(4, g13[0].b[0]); + ASSERT(3, g13[0].b[1]); + ASSERT(8, g13[1].b[0]); + ASSERT(7, g13[1].b[1]); + + ASSERT(7, sizeof(g17)); + ASSERT(10, sizeof(g18)); + ASSERT(3, sizeof(g19)); + + ASSERT(0, memcmp(g17, "foobar", 7)); + ASSERT(0, memcmp(g18, "foobar\0\0\0", 10)); + ASSERT(0, memcmp(g19, "foo", 3)); + + ASSERT(0, strcmp(g20, "foobar")); + ASSERT(0, strcmp(g21, "bar")); + ASSERT(0, strcmp(g22 + 3, "foobar")); + + ASSERT(0, strcmp(g23[0], "foobar")); + ASSERT(0, strcmp(g23[1], "bar")); + ASSERT(0, strcmp(g23[2] + 3, "foobar")); + + ASSERT(3, g24); + ASSERT(3, *g25); + ASSERT(2, *g27); + ASSERT(3, *g28); + ASSERT(1, *(int *)g29); + + ASSERT(1, g31[0]); + ASSERT(2, g31[1]); + ASSERT(3, g31[2]); + + ASSERT(1, g40[0].a[0]); + ASSERT(2, g40[0].a[1]); + ASSERT(3, g40[1].a[0]); + ASSERT(4, g40[1].a[1]); + + ASSERT(1, g41[0].a[0]); + ASSERT(2, g41[0].a[1]); + ASSERT(3, g41[1].a[0]); + ASSERT(4, g41[1].a[1]); + + ASSERT(0, ({ + int x[2][3] = {0, 1, 2, 3, 4, 5}; + x[0][0]; + })); + ASSERT(3, ({ + int x[2][3] = {0, 1, 2, 3, 4, 5}; + x[1][0]; + })); + + ASSERT(0, ({ + struct { + int a; + int b; + } x[2] = {0, 1, 2, 3}; + x[0].a; + })); + ASSERT(2, ({ + struct { + int a; + int b; + } x[2] = {0, 1, 2, 3}; + x[1].a; + })); + + ASSERT(0, strcmp(g43[0], "foo")); + ASSERT(0, strcmp(g43[1], "bar")); + ASSERT(0, strcmp(g44, "foo")); + + ASSERT(3, ({ + int a[] = { + 1, + 2, + 3, + }; + a[2]; + })); + ASSERT(1, ({ + struct { + int a, b, c; + } x = { + 1, + 2, + 3, + }; + x.a; + })); + ASSERT(2, ({ + enum { + x, + y, + z, + }; + z; + })); + + ASSERT(3, sizeof(g60)); + ASSERT(6, sizeof(g61)); + + ASSERT(4, sizeof(g65)); + ASSERT(7, sizeof(g66)); + ASSERT(0, strcmp(g65.b, "oo")); + ASSERT(0, strcmp(g66.b, "oobar")); + + ASSERT(4, ({ + int x[3] = {1, 2, 3, [0] = 4, 5}; + x[0]; + })); + ASSERT(5, ({ + int x[3] = {1, 2, 3, [0] = 4, 5}; + x[1]; + })); + ASSERT(3, ({ + int x[3] = {1, 2, 3, [0] = 4, 5}; + x[2]; + })); + + ASSERT(10, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[0][0]; + })); + ASSERT(11, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[0][1]; + })); + ASSERT(8, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[0][2]; + })); + ASSERT(12, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[1][0]; + })); + ASSERT(5, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[1][1]; + })); + ASSERT(6, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[1][2]; + })); + + ASSERT(7, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[0][0]; + })); + ASSERT(8, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[0][1]; + })); + ASSERT(3, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[0][2]; + })); + ASSERT(9, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[1][0]; + })); + ASSERT(10, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[1][1]; + })); + ASSERT(6, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[1][2]; + })); + + ASSERT(7, ((int[10]){[3] = 7})[3]); + ASSERT(0, ((int[10]){[3] = 7})[4]); + + ASSERT(10, ({ + char x[] = {[10 - 3] = 1, 2, 3}; + sizeof(x); + })); + ASSERT(20, ({ + char x[][2] = {[8][1] = 1, 2}; + sizeof(x); + })); + + ASSERT(3, sizeof(g60)); + ASSERT(6, sizeof(g61)); + + ASSERT(4, sizeof(g65)); + ASSERT(7, sizeof(g66)); + ASSERT(0, strcmp(g65.b, "oo")); + ASSERT(0, strcmp(g66.b, "oobar")); + + ASSERT(7, ((int[10]){[3] 7})[3]); + ASSERT(0, ((int[10]){[3] 7})[4]); + + ASSERT(4, ({ + struct { + int a, b; + } x = {1, 2, .b = 3, .a = 4}; + x.a; + })); + ASSERT(3, ({ + struct { + int a, b; + } x = {1, 2, .b = 3, .a = 4}; + x.b; + })); + + ASSERT(1, ({ + struct { + struct { + int a, b; + } c; + } x = {.c = 1, 2}; + x.c.a; + })); + ASSERT(2, ({ + struct { + struct { + int a, b; + } c; + } x = {.c = 1, 2}; + x.c.b; + })); + + ASSERT(0, ({ + struct { + struct { + int a, b; + } c; + } x = {.c.b = 1}; + x.c.a; + })); + ASSERT(1, ({ + struct { + struct { + int a, b; + } c; + } x = {.c.b = 1}; + x.c.b; + })); + + ASSERT(1, ({ + struct { + int a[2]; + } x = {.a = 1, 2}; + x.a[0]; + })); + ASSERT(2, ({ + struct { + int a[2]; + } x = {.a = 1, 2}; + x.a[1]; + })); + + ASSERT(0, ({ + struct { + int a[2]; + } x = {.a[1] = 1}; + x.a[0]; + })); + ASSERT(1, ({ + struct { + int a[2]; + } x = {.a[1] = 1}; + x.a[1]; + })); + + ASSERT(3, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[0].a; + })); + ASSERT(4, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[0].b; + })); + ASSERT(0, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[1].a; + })); + ASSERT(1, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[1].b; + })); + ASSERT(2, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[2].a; + })); + ASSERT(0, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[2].b; + })); + + ASSERT(1, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x}; + y[0].a; + })); + ASSERT(2, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x}; + y[0].b; + })); + ASSERT(0, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x, [0].b = 3}; + y[0].a; + })); + ASSERT(3, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x, [0].b = 3}; + y[0].b; + })); + + ASSERT(5, ((struct { int a, b, c; }){.c = 5}).c); + ASSERT(0, ((struct { int a, b, c; }){.c = 5}).a); + + ASSERT(0x00ff, ({ + union { + unsigned short a; + char b[2]; + } x = {.b[0] = 0xff}; + x.a; + })); + ASSERT(0xff00, ({ + union { + unsigned short a; + char b[2]; + } x = {.b[1] = 0xff}; + x.a; + })); + + ASSERT(0x00120000, g50.a); + ASSERT(0, g51[0].a); + ASSERT(0, g51[1].a); + + ASSERT(1, ({ + struct { + struct { + int a; + struct { + int b; + }; + }; + int c; + } x = {1, 2, 3, .b = 4, 5}; + x.a; + })); + ASSERT(4, ({ + struct { + struct { + int a; + struct { + int b; + }; + }; + int c; + } x = {1, 2, 3, .b = 4, 5}; + x.b; + })); + ASSERT(5, ({ + struct { + struct { + int a; + struct { + int b; + }; + }; + int c; + } x = {1, 2, 3, .b = 4, 5}; + x.c; + })); + + ASSERT(16, ({ + char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'}; + sizeof(x); + })); + ASSERT(0, ({ + char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'}; + memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16); + })); + + return 0; +} diff --git a/third_party/chibicc/test/int128_test.c b/third_party/chibicc/test/int128_test.c new file mode 100644 index 00000000..bf82245c --- /dev/null +++ b/third_party/chibicc/test/int128_test.c @@ -0,0 +1,8183 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or 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. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/chibicc/test/test.h" + +#define BANE 0x8000000000000000 +#define BANE1 0x8000000000000001 +#define BANE2 0x8000000000000002 +#define IMAX 0x7fffffffffffffff +#define IMAX2 0xfffffffffffffffd +#define I128(HI, LO) ((LO) | (unsigned __int128)(HI) << 64) + +__int128 add128(__int128 x, __int128 y) { + return x + y; +} + +__int128 sub128x5(__int128 a, __int128 b, __int128 c, __int128 d, __int128 e) { + return a - b - c - d - e; +} + +void testLang128(void) { + ASSERT(16, sizeof(__int128)); + ASSERT(16, sizeof(unsigned __int128)); + ASSERT(16, _Alignof(__int128)); + ASSERT(16, ({ + struct T { + __int128 x; + }; + _Alignof(struct T); + })); + ASSERT(2, ({ + struct __attribute__((__aligned__(2))) T { + __int128 x; + }; + _Alignof(struct T); + })); + ASSERT128(7, ({ + __int128 i = 2; + i += 5; + i; + })); + ASSERT128(I128(0xffffffffffffffff, 0xffffffffffffffff), ({ + __int128 i = 0; + add128(i, -1); + })); + ASSERT128(I128(0x3a8eaaa2e9af03f5, 0xd7ed730a55920176), + sub128x5(I128(0x0db9cd085ab6ba38, 0xdaf9c05f15896b5f), + I128(0xb6429ba7b5b38454, 0x4061839d268a0a78), + I128(0x19a0da005190a5ac, 0x755fa06484419e38), + I128(0xafc6e44400b9eadd, 0x05e5afdb2e66cdb8), + I128(0x5380c8796909a165, 0x47657977e6c4f381))); +} + +void testCompare128(void) { + __int128 x = 1, y = 2; + ASSERT(0, x == y); + ASSERT(1, x != y); + ASSERT(1, x < y); + ASSERT(1, x <= y); + ASSERT(0, x > y); + ASSERT(0, x >= y); + ASSERT(1, x >= x); + x = I128(-1ul, 2); + y = I128(0xfffffffffffffff0, 2); + ASSERT(0, x == y); +} + +void testCastDblInt128(void) { + int k; + double f; + __int128 i, w; + k = 110; + i = 1; + i <<= k; + f = i; + f /= 2; + i = f; + w = 1; + w <<= k - 1; + ASSERT128(w, i); +} + +void testCastDblUint128(void) { + double f; + unsigned __int128 i; + i = 0x0000ffffffffffff; + ++i; + f = i; + --f; + i = f; + --i; + ASSERT128(0x0000fffffffffffe, i); +} + +void testCastLdblInt128(void) { + int k; + __int128 i, w; + long double f; + k = 110; + i = 1; + i <<= k; + f = i; + f /= 2; + i = f; + w = 1; + w <<= k - 1; + ASSERT128(w, i); +} + +void testCastLdblUint128(void) { + long double f; + unsigned __int128 i; + i = 0xffffffffffffffff; + ++i; + f = i; + --f; + i = f; + --i; + ASSERT128(0xfffffffffffffffe, i); +} + +void testAdd128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 0); + ASSERT128(I128(0, 0), x + y); + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 2), x + y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x + y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x + y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(2, 0), x + y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(2, 2), x + y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x + y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x + y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x + y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x + y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x + y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x + y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x + y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x + y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x + y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x + y); + x = I128(0, 2); + y = I128(0, 0); + ASSERT128(I128(0, 2), x + y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 4), x + y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, BANE2), x + y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(1, 1), x + y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(2, 2), x + y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(2, 4), x + y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(2, BANE2), x + y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(3, 1), x + y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 2), x + y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 4), x + y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE2), x + y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE1, 1), x + y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x + y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 4), x + y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x + y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 1), x + y); + x = I128(0, BANE); + y = I128(0, 0); + ASSERT128(I128(0, BANE), x + y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, BANE2), x + y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(1, 0), x + y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(1, IMAX), x + y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(2, BANE), x + y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(2, BANE2), x + y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(3, 0), x + y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(3, IMAX), x + y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, BANE), x + y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, BANE2), x + y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE1, 0), x + y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE1, IMAX), x + y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x + y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE2), x + y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x + y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, IMAX), x + y); + x = I128(0, -1ul); + y = I128(0, 0); + ASSERT128(I128(0, -1ul), x + y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(1, 1), x + y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(1, IMAX), x + y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(1, 0xfffffffffffffffe), x + y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(2, -1ul), x + y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(3, 1), x + y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(3, IMAX), x + y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(3, 0xfffffffffffffffe), x + y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, -1ul), x + y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE1, 1), x + y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE1, IMAX), x + y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE1, 0xfffffffffffffffe), x + y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x + y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 1), x + y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, IMAX), x + y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0xfffffffffffffffe), x + y); + x = I128(2, 0); + y = I128(0, 0); + ASSERT128(I128(2, 0), x + y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(2, 2), x + y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(2, BANE), x + y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(2, -1ul), x + y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(4, 0), x + y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(4, 2), x + y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(4, BANE), x + y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(4, -1ul), x + y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 0), x + y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 2), x + y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, BANE), x + y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, -1ul), x + y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(1, 0), x + y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(1, 2), x + y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(1, BANE), x + y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(1, -1ul), x + y); + x = I128(2, 2); + y = I128(0, 0); + ASSERT128(I128(2, 2), x + y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(2, 4), x + y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(2, BANE2), x + y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(3, 1), x + y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(4, 2), x + y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(4, 4), x + y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(4, BANE2), x + y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(5, 1), x + y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 2), x + y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 4), x + y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, BANE2), x + y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0x8000000000000003, 1), x + y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(1, 2), x + y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(1, 4), x + y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(1, BANE2), x + y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 1), x + y); + x = I128(2, BANE); + y = I128(0, 0); + ASSERT128(I128(2, BANE), x + y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(2, BANE2), x + y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(3, 0), x + y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(3, IMAX), x + y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(4, BANE), x + y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(4, BANE2), x + y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(5, 0), x + y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(5, IMAX), x + y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, BANE), x + y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, BANE2), x + y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0x8000000000000003, 0), x + y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0x8000000000000003, IMAX), x + y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(1, BANE), x + y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(1, BANE2), x + y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(2, 0), x + y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, IMAX), x + y); + x = I128(2, -1ul); + y = I128(0, 0); + ASSERT128(I128(2, -1ul), x + y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(3, 1), x + y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(3, IMAX), x + y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(3, 0xfffffffffffffffe), x + y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(4, -1ul), x + y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(5, 1), x + y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(5, IMAX), x + y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(5, 0xfffffffffffffffe), x + y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, -1ul), x + y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0x8000000000000003, 1), x + y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0x8000000000000003, IMAX), x + y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0x8000000000000003, 0xfffffffffffffffe), x + y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(1, -1ul), x + y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(2, 1), x + y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(2, IMAX), x + y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 0xfffffffffffffffe), x + y); + x = I128(BANE, 0); + y = I128(0, 0); + ASSERT128(I128(BANE, 0), x + y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(BANE, 2), x + y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(BANE, BANE), x + y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(BANE, -1ul), x + y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(BANE2, 0), x + y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(BANE2, 2), x + y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(BANE2, BANE), x + y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, -1ul), x + y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x + y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x + y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x + y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, -1ul), x + y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, 0), x + y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, 2), x + y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX, BANE), x + y); + x = I128(BANE, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, -1ul), x + y); + x = I128(BANE, 2); + y = I128(0, 0); + ASSERT128(I128(BANE, 2), x + y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(BANE, 4), x + y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(BANE, BANE2), x + y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(BANE1, 1), x + y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(BANE2, 2), x + y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(BANE2, 4), x + y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(BANE2, BANE2), x + y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(0x8000000000000003, 1), x + y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 2), x + y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 4), x + y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE2), x + y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(1, 1), x + y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, 2), x + y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, 4), x + y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX, BANE2), x + y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, 1), x + y); + x = I128(BANE, BANE); + y = I128(0, 0); + ASSERT128(I128(BANE, BANE), x + y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(BANE, BANE2), x + y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(BANE1, 0), x + y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(BANE1, IMAX), x + y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(BANE2, BANE), x + y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(BANE2, BANE2), x + y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(0x8000000000000003, 0), x + y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0x8000000000000003, IMAX), x + y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, BANE), x + y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, BANE2), x + y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(1, 0), x + y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(1, IMAX), x + y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, BANE), x + y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, BANE2), x + y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, 0), x + y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, IMAX), x + y); + x = I128(BANE, -1ul); + y = I128(0, 0); + ASSERT128(I128(BANE, -1ul), x + y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(BANE1, 1), x + y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(BANE1, IMAX), x + y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(BANE1, 0xfffffffffffffffe), x + y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(BANE2, -1ul), x + y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(0x8000000000000003, 1), x + y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0x8000000000000003, IMAX), x + y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0x8000000000000003, 0xfffffffffffffffe), x + y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, -1ul), x + y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(1, 1), x + y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(1, IMAX), x + y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(1, 0xfffffffffffffffe), x + y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, -1ul), x + y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 1), x + y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, IMAX), x + y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, 0xfffffffffffffffe), x + y); + x = I128(-1ul, 0); + y = I128(0, 0); + ASSERT128(I128(-1ul, 0), x + y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(-1ul, 2), x + y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE), x + y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x + y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(1, 0), x + y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(1, 2), x + y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(1, BANE), x + y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(1, -1ul), x + y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 0), x + y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 2), x + y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE), x + y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, -1ul), x + y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x + y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0xfffffffffffffffe, 2), x + y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0xfffffffffffffffe, BANE), x + y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0xfffffffffffffffe, -1ul), x + y); + x = I128(-1ul, 2); + y = I128(0, 0); + ASSERT128(I128(-1ul, 2), x + y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(-1ul, 4), x + y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE2), x + y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 1), x + y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(1, 2), x + y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(1, 4), x + y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(1, BANE2), x + y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, 1), x + y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 2), x + y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 4), x + y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE2), x + y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 1), x + y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, 2), x + y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0xfffffffffffffffe, 4), x + y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0xfffffffffffffffe, BANE2), x + y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 1), x + y); + x = I128(-1ul, BANE); + y = I128(0, 0); + ASSERT128(I128(-1ul, BANE), x + y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(-1ul, BANE2), x + y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x + y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, IMAX), x + y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(1, BANE), x + y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(1, BANE2), x + y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x + y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, IMAX), x + y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, BANE), x + y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, BANE2), x + y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x + y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, IMAX), x + y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, BANE), x + y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0xfffffffffffffffe, BANE2), x + y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x + y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, IMAX), x + y); + x = I128(-1ul, -1ul); + y = I128(0, 0); + ASSERT128(I128(-1ul, -1ul), x + y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 1), x + y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x + y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 0xfffffffffffffffe), x + y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(1, -1ul), x + y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(2, 1), x + y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(2, IMAX), x + y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(2, 0xfffffffffffffffe), x + y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, -1ul), x + y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 1), x + y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, IMAX), x + y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 0xfffffffffffffffe), x + y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, -1ul), x + y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 1), x + y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, IMAX), x + y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x + y); +} + +void testSub128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 0); + ASSERT128(I128(0, 0), x - y); + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x - y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE), x - y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, 1), x - y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x - y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(IMAX2, 0xfffffffffffffffe), x - y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, BANE), x - y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, 1), x - y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x - y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 0xfffffffffffffffe), x - y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE), x - y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 1), x - y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(1, 0), x - y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0xfffffffffffffffe), x - y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE), x - y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 1), x - y); + x = I128(0, 2); + y = I128(0, 0); + ASSERT128(I128(0, 2), x - y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x - y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE2), x - y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, 3), x - y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 2), x - y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffe, 0), x - y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, BANE2), x - y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, 3), x - y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 2), x - y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0), x - y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE2), x - y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 3), x - y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(1, 2), x - y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(1, 0), x - y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE2), x - y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 3), x - y); + x = I128(0, BANE); + y = I128(0, 0); + ASSERT128(I128(0, BANE), x - y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x - y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x - y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE1), x - y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, BANE), x - y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffe, 0x7ffffffffffffffe), x - y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(0xfffffffffffffffe, 0), x - y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, BANE1), x - y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, BANE), x - y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0x7ffffffffffffffe), x - y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x - y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, BANE1), x - y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(1, BANE), x - y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(1, 0x7ffffffffffffffe), x - y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(1, 0), x - y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, BANE1), x - y); + x = I128(0, -1ul); + y = I128(0, 0); + ASSERT128(I128(0, -1ul), x - y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, IMAX2), x - y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x - y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x - y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, -1ul), x - y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffe, IMAX2), x - y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0xfffffffffffffffe, IMAX), x - y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0), x - y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, -1ul), x - y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, IMAX2), x - y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, IMAX), x - y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 0), x - y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(1, -1ul), x - y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(1, IMAX2), x - y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(1, IMAX), x - y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(1, 0), x - y); + x = I128(2, 0); + y = I128(0, 0); + ASSERT128(I128(2, 0), x - y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(1, 0xfffffffffffffffe), x - y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(1, BANE), x - y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(1, 1), x - y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x - y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x - y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE), x - y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 1), x - y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 0), x - y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE1, 0xfffffffffffffffe), x - y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE1, BANE), x - y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE1, 1), x - y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(3, 0), x - y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(2, 0xfffffffffffffffe), x - y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(2, BANE), x - y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 1), x - y); + x = I128(2, 2); + y = I128(0, 0); + ASSERT128(I128(2, 2), x - y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(2, 0), x - y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(1, BANE2), x - y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(1, 3), x - y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(0, 2), x - y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0), x - y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE2), x - y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 3), x - y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 2), x - y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 0), x - y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE1, BANE2), x - y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE1, 3), x - y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(3, 2), x - y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(3, 0), x - y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(2, BANE2), x - y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 3), x - y); + x = I128(2, BANE); + y = I128(0, 0); + ASSERT128(I128(2, BANE), x - y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(2, 0x7ffffffffffffffe), x - y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(2, 0), x - y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(1, BANE1), x - y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(0, BANE), x - y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x - y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x - y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, BANE1), x - y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, BANE), x - y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 0x7ffffffffffffffe), x - y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, 0), x - y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE1, BANE1), x - y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(3, BANE), x - y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(3, 0x7ffffffffffffffe), x - y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(3, 0), x - y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, BANE1), x - y); + x = I128(2, -1ul); + y = I128(0, 0); + ASSERT128(I128(2, -1ul), x - y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(2, IMAX2), x - y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(2, IMAX), x - y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(2, 0), x - y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, -1ul), x - y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, IMAX2), x - y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, IMAX), x - y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x - y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, -1ul), x - y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, IMAX2), x - y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, IMAX), x - y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, 0), x - y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(3, -1ul), x - y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(3, IMAX2), x - y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(3, IMAX), x - y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(3, 0), x - y); + x = I128(BANE, 0); + y = I128(0, 0); + ASSERT128(I128(BANE, 0), x - y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(IMAX, 0xfffffffffffffffe), x - y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(IMAX, BANE), x - y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(IMAX, 1), x - y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(0x7ffffffffffffffe, 0), x - y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(0x7ffffffffffffffd, 0xfffffffffffffffe), x - y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(0x7ffffffffffffffd, BANE), x - y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(0x7ffffffffffffffd, 1), x - y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x - y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x - y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x - y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, 1), x - y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(BANE1, 0), x - y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 0xfffffffffffffffe), x - y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE), x - y); + x = I128(BANE, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, 1), x - y); + x = I128(BANE, 2); + y = I128(0, 0); + ASSERT128(I128(BANE, 2), x - y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(BANE, 0), x - y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(IMAX, BANE2), x - y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(IMAX, 3), x - y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(0x7ffffffffffffffe, 2), x - y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(0x7ffffffffffffffe, 0), x - y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(0x7ffffffffffffffd, BANE2), x - y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(0x7ffffffffffffffd, 3), x - y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 2), x - y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x - y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE2), x - y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, 3), x - y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(BANE1, 2), x - y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(BANE1, 0), x - y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE2), x - y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, 3), x - y); + x = I128(BANE, BANE); + y = I128(0, 0); + ASSERT128(I128(BANE, BANE), x - y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(BANE, 0x7ffffffffffffffe), x - y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(BANE, 0), x - y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(IMAX, BANE1), x - y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(0x7ffffffffffffffe, BANE), x - y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(0x7ffffffffffffffe, 0x7ffffffffffffffe), x - y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(0x7ffffffffffffffe, 0), x - y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0x7ffffffffffffffd, BANE1), x - y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, BANE), x - y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x - y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x - y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, BANE1), x - y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(BANE1, BANE), x - y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(BANE1, 0x7ffffffffffffffe), x - y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE1, 0), x - y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, BANE1), x - y); + x = I128(BANE, -1ul); + y = I128(0, 0); + ASSERT128(I128(BANE, -1ul), x - y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(BANE, IMAX2), x - y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(BANE, IMAX), x - y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(BANE, 0), x - y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(0x7ffffffffffffffe, -1ul), x - y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(0x7ffffffffffffffe, IMAX2), x - y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0x7ffffffffffffffe, IMAX), x - y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, 0), x - y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, -1ul), x - y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, IMAX2), x - y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, IMAX), x - y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x - y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(BANE1, -1ul), x - y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(BANE1, IMAX2), x - y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE1, IMAX), x - y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE1, 0), x - y); + x = I128(-1ul, 0); + y = I128(0, 0); + ASSERT128(I128(-1ul, 0), x - y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(0xfffffffffffffffe, 0xfffffffffffffffe), x - y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(0xfffffffffffffffe, BANE), x - y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 1), x - y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(IMAX2, 0), x - y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffc, 0xfffffffffffffffe), x - y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(0xfffffffffffffffc, BANE), x - y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffc, 1), x - y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 0), x - y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(0x7ffffffffffffffe, 0xfffffffffffffffe), x - y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0x7ffffffffffffffe, BANE), x - y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, 1), x - y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x - y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x - y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x - y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 1), x - y); + x = I128(-1ul, 2); + y = I128(0, 0); + ASSERT128(I128(-1ul, 2), x - y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(-1ul, 0), x - y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(0xfffffffffffffffe, BANE2), x - y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 3), x - y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(IMAX2, 2), x - y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(IMAX2, 0), x - y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(0xfffffffffffffffc, BANE2), x - y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffc, 3), x - y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 2), x - y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 0), x - y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0x7ffffffffffffffe, BANE2), x - y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, 3), x - y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 2), x - y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x - y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x - y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 3), x - y); + x = I128(-1ul, BANE); + y = I128(0, 0); + ASSERT128(I128(-1ul, BANE), x - y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(-1ul, 0x7ffffffffffffffe), x - y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(-1ul, 0), x - y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0xfffffffffffffffe, BANE1), x - y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(IMAX2, BANE), x - y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(IMAX2, 0x7ffffffffffffffe), x - y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, 0), x - y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffc, BANE1), x - y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, BANE), x - y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 0x7ffffffffffffffe), x - y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, 0), x - y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, BANE1), x - y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, BANE), x - y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x - y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x - y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, BANE1), x - y); + x = I128(-1ul, -1ul); + y = I128(0, 0); + ASSERT128(I128(-1ul, -1ul), x - y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(-1ul, IMAX2), x - y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(-1ul, IMAX), x - y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, 0), x - y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(IMAX2, -1ul), x - y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(IMAX2, IMAX2), x - y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, IMAX), x - y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, 0), x - y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, -1ul), x - y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, IMAX2), x - y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, IMAX), x - y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 0), x - y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, -1ul), x - y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, IMAX2), x - y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, IMAX), x - y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x - y); +} + +void testMul128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 2); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 4), x * y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(1, 0), x * y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(1, 0xfffffffffffffffe), x * y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(4, 0), x * y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(4, 4), x * y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(5, 0), x * y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(5, 0xfffffffffffffffe), x * y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 4), x * y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(1, 0), x * y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(1, 0xfffffffffffffffe), x * y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0xfffffffffffffffe, 4), x * y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x * y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x * y); + x = I128(0, BANE); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(1, 0), x * y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(1, 0), x * y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(1, 0), x * y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(BANE1, 0), x * y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0xc000000000000000, 0), x * y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(0, -1ul); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(1, 0xfffffffffffffffe), x * y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 1), x * y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x * y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0x7ffffffffffffffd, BANE), x * y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffc, 1), x * y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE1, 0xfffffffffffffffe), x * y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, 1), x * y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(1, 0), x * y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(2, 0xfffffffffffffffe), x * y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE), x * y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 1), x * y); + x = I128(2, 0); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(4, 0), x * y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(4, 0), x * y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(4, 0), x * y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(4, 0), x * y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(2, 2); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(4, 4), x * y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(1, 0), x * y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x * y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(4, 0), x * y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(0x0000000000000008, 4), x * y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(5, 0), x * y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(3, 0xfffffffffffffffe), x * y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(4, 4), x * y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(1, 0), x * y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x * y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(2, 4), x * y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x * y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, 0xfffffffffffffffe), x * y); + x = I128(2, BANE); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(5, 0), x * y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0x7ffffffffffffffd, BANE), x * y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(5, 0), x * y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0x7ffffffffffffffd, BANE), x * y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(5, 0), x * y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffd, BANE), x * y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0x8000000000000005, 0), x * y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0xc000000000000000, 0), x * y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, BANE), x * y); + x = I128(2, -1ul); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(5, 0xfffffffffffffffe), x * y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0xfffffffffffffffc, 1), x * y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(3, 0xfffffffffffffffe), x * y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0x7ffffffffffffffd, BANE), x * y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffa, 1), x * y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0x8000000000000005, 0xfffffffffffffffe), x * y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffc, 1), x * y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(1, 0), x * y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0x0000000000000006, 0xfffffffffffffffe), x * y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE), x * y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, 1), x * y); + x = I128(BANE, 0); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(BANE, 0), x * y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(BANE, 0), x * y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 0), x * y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, 0), x * y); + x = I128(BANE, 2); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(0, 4), x * y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(1, 0), x * y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(BANE1, 0xfffffffffffffffe), x * y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(4, 0), x * y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(4, 4), x * y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(5, 0), x * y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(0x8000000000000005, 0xfffffffffffffffe), x * y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 4), x * y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(1, 0), x * y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE1, 0xfffffffffffffffe), x * y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0xfffffffffffffffe, 4), x * y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x * y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, 0xfffffffffffffffe), x * y); + x = I128(BANE, BANE); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(1, 0), x * y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(1, 0), x * y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(1, 0), x * y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(BANE1, 0), x * y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0xc000000000000000, 0), x * y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(BANE, -1ul); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(1, 0xfffffffffffffffe), x * y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, 1), x * y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x * y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0x7ffffffffffffffd, BANE), x * y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0x7ffffffffffffffc, 1), x * y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE1, 0xfffffffffffffffe), x * y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 1), x * y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(1, 0), x * y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(2, 0xfffffffffffffffe), x * y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE), x * y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, 1), x * y); + x = I128(-1ul, 0); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(BANE, 0), x * y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(1, 0), x * y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(BANE, 0), x * y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(1, 0), x * y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x * y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(1, 0), x * y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, 0), x * y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(1, 0), x * y); + x = I128(-1ul, 2); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(0xfffffffffffffffe, 4), x * y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(BANE1, 0), x * y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(2, 0xfffffffffffffffe), x * y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(4, 0), x * y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(2, 4), x * y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(0x8000000000000005, 0), x * y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(0x0000000000000006, 0xfffffffffffffffe), x * y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(0xfffffffffffffffe, 4), x * y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE1, 0), x * y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(2, 0xfffffffffffffffe), x * y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0xfffffffffffffffc, 4), x * y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX, 0), x * y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0xfffffffffffffffe), x * y); + x = I128(-1ul, BANE); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(-1ul, 0), x * y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(0xc000000000000000, 0), x * y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(BANE, BANE), x * y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0), x * y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(0xc000000000000000, 0), x * y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(BANE, BANE), x * y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, 0), x * y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0xc000000000000000, 0), x * y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, BANE), x * y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, 0), x * y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0x4000000000000000, 0), x * y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, BANE), x * y); + x = I128(-1ul, -1ul); + y = I128(0, 0); + ASSERT128(I128(0, 0), x * y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x * y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE), x * y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, 1), x * y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), x * y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(IMAX2, 0xfffffffffffffffe), x * y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, BANE), x * y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, 1), x * y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x * y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 0xfffffffffffffffe), x * y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE), x * y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 1), x * y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(1, 0), x * y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0xfffffffffffffffe), x * y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE), x * y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 1), x * y); +} + +void testDiv128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x / y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, BANE), x / y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, IMAX), x / y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, -1ul), x / y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x / y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 1), x / y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(1, 0), x / y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 4), x / y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x / y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0xfffffffffffffffc), x / y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0), x / y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(1, 1), x / y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 4), x / y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x / y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0xfffffffffffffffc), x / y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, 0xfffffffffffffffe), x / y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(1, 0x4000000000000000), x / y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 5), x / y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x / y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0xfffffffffffffffb), x / y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, BANE), x / y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(1, IMAX), x / y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, 5), x / y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 3), x / y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, IMAX2), x / y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0xfffffffffffffffb), x / y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, 1), x / y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(0xc000000000000000, 0), x / y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(-1ul, 0), x / y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE), x / y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(-1ul, 0xc000000000000000), x / y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0xc000000000000001), x / y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(-1ul, 0xcccccccccccccccd), x / y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 0xd555555555555556), x / y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, BANE), x / y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, BANE1), x / y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(1, 0), x / y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(0xc000000000000000, 1), x / y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, 1), x / y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE), x / y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(-1ul, 0xc000000000000001), x / y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0xc000000000000001), x / y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(-1ul, 0xcccccccccccccccd), x / y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 0xd555555555555556), x / y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, IMAX), x / y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, BANE1), x / y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, -1ul), x / y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, 0xfffffffffffffffe), x / y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(0xc000000000000000, 0x4000000000000000), x / y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(-1ul, 1), x / y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE), x / y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(-1ul, 0xc000000000000001), x / y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0xc000000000000001), x / y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(-1ul, 0xcccccccccccccccd), x / y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 0xd555555555555556), x / y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, IMAX), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, BANE), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, -1ul), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, BANE), x / y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(0xc000000000000000, BANE), x / y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(-1ul, 2), x / y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE1), x / y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(-1ul, 0xc000000000000001), x / y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0xc000000000000001), x / y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(-1ul, 0xccccccccccccccce), x / y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 0xd555555555555556), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, IMAX), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, BANE), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0xfffffffffffffffe), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, 1), x / y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(-1ul, BANE), x / y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x / y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x / y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 2), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(1, 0), x / y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(-1ul, BANE1), x / y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, -1ul), x / y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0xfffffffffffffffe), x / y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(-1ul, 0xc000000000000000), x / y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(-1ul, -1ul), x / y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, BANE), x / y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 1), x / y); +} + +void testDivu128(void) { + unsigned __int128 x, y; + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, IMAX), x / y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(1, 0), x / y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 4), x / y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x / y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(1, 1), x / y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 4), x / y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x / y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(1, 0x4000000000000000), x / y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 5), x / y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x / y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(1, IMAX), x / y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, 5), x / y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 3), x / y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(0x4000000000000000, 0), x / y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(1, 0), x / y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x / y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0x3fffffffffffffff), x / y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0x3333333333333333), x / y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x2aaaaaaaaaaaaaaa), x / y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(0x4000000000000000, 1), x / y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(1, 0), x / y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x / y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0x3fffffffffffffff), x / y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0x3333333333333333), x / y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x2aaaaaaaaaaaaaaa), x / y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(0x4000000000000000, 0x4000000000000000), x / y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(1, 1), x / y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE1), x / y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0x3333333333333333), x / y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x2aaaaaaaaaaaaaaa), x / y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(0x4000000000000000, IMAX), x / y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(1, 1), x / y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE1), x / y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 0x4000000000000000), x / y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, 0x3333333333333333), x / y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x2aaaaaaaaaaaaaab), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(IMAX, BANE), x / y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(1, 0xfffffffffffffffe), x / y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(1, 0), x / y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0x6666666666666666), x / y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x5555555555555555), x / y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(IMAX, BANE1), x / y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(1, 0xfffffffffffffffe), x / y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(1, 0), x / y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0x6666666666666666), x / y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x5555555555555555), x / y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(IMAX, 0xc000000000000000), x / y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(1, -1ul), x / y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(1, 0), x / y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0x6666666666666666), x / y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x5555555555555555), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x / y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(IMAX, -1ul), x / y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(1, -1ul), x / y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(1, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, IMAX), x / y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, 0x6666666666666666), x / y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x5555555555555555), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 1), x / y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 1), x / y); +} + +void testRem128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 1), x % y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 1), x % y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 4), x % y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 4), x % y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0x0000000000000006), x % y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE2), x % y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x % y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0x8000000000000004), x % y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 1), x % y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, IMAX2), x % y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 5), x % y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffe, 0x7ffffffffffffffe), x % y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, 0xd555555555555556), x % y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x % y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, 1), x % y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x % y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE2), x % y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE2), x % y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 2), x % y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffe, BANE), x % y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE2), x % y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, 0xd555555555555558), x % y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 2), x % y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE2), x % y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, 3), x % y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x % y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, BANE), x % y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(0xfffffffffffffffe, 0xfffffffffffffffe), x % y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0x5555555555555556), x % y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, BANE), x % y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, BANE), x % y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, BANE1), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0x7ffffffffffffffd), x % y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0xfffffffffffffffe, 0xd555555555555555), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE2), x % y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); +} + +void testRemu128(void) { + unsigned __int128 x, y; + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 1), x % y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, -1ul), x % y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, -1ul), x % y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 0), x % y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 4), x % y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(2, 2), x % y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 2), x % y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE2), x % y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x % y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, BANE), x % y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 1), x % y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, IMAX2), x % y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(2, -1ul), x % y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, -1ul), x % y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(1, BANE2), x % y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x % y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, 0x2aaaaaaaaaaaaaaa), x % y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0), x % y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x % y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 0), x % y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x % y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 0), x % y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, 0), x % y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE2), x % y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(1, 0x8000000000000004), x % y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(0, BANE2), x % y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, 0x2aaaaaaaaaaaaaac), x % y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 2), x % y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 2), x % y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 2), x % y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 2), x % y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, 2), x % y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, 2), x % y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, 1), x % y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(1, 0), x % y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, 0xaaaaaaaaaaaaaaaa), x % y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x % y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, BANE), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, BANE), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, BANE), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE), x % y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, BANE), x % y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 1), x % y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, IMAX), x % y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(1, IMAX), x % y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x2aaaaaaaaaaaaaaa), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, IMAX2), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, -1ul), x % y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, -1ul), x % y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(1, 0), x % y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(0, 2), x % y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x5555555555555555), x % y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 0), x % y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(0x7ffffffffffffffe, 0xfffffffffffffffe), x % y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0x7ffffffffffffffe, BANE), x % y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, 1), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 0), x % y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x % y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(1, 2), x % y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(0, 4), x % y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 2), x % y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 0x5555555555555557), x % y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 2), x % y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 0), x % y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0x7ffffffffffffffe, BANE2), x % y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, 3), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 2), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 2), x % y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(1, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(0, BANE2), x % y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, 0xd555555555555555), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 0x7ffffffffffffffe), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, 0), x % y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0x7ffffffffffffffe, BANE1), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, BANE), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0x7ffffffffffffffe), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, BANE), x % y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 1), x % y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x % y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(1, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(1, 1), x % y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(1, 0x5555555555555554), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, IMAX2), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, IMAX), x % y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 0), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, -1ul), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, IMAX2), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, IMAX), x % y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x % y); +} + +void testShr128(void) { + unsigned __int128 x; + x = I128(0, 0); + x >>= 0; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x >>= 1; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, 2); + x >>= 0; + ASSERT128(I128(0, 2), x); + x = I128(0, 2); + x >>= 1; + ASSERT128(I128(0, 1), x); + x = I128(0, 2); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, 2); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, BANE); + x >>= 0; + ASSERT128(I128(0, BANE), x); + x = I128(0, BANE); + x >>= 1; + ASSERT128(I128(0, 0x4000000000000000), x); + x = I128(0, BANE); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, BANE); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, -1ul); + x >>= 0; + ASSERT128(I128(0, -1ul), x); + x = I128(0, -1ul); + x >>= 1; + ASSERT128(I128(0, IMAX), x); + x = I128(0, -1ul); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, -1ul); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, 0); + x >>= 0; + ASSERT128(I128(2, 0), x); + x = I128(2, 0); + x >>= 1; + ASSERT128(I128(1, 0), x); + x = I128(2, 0); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, 0); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, 2); + x >>= 0; + ASSERT128(I128(2, 2), x); + x = I128(2, 2); + x >>= 1; + ASSERT128(I128(1, 1), x); + x = I128(2, 2); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, 2); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, BANE); + x >>= 0; + ASSERT128(I128(2, BANE), x); + x = I128(2, BANE); + x >>= 1; + ASSERT128(I128(1, 0x4000000000000000), x); + x = I128(2, BANE); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, BANE); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, -1ul); + x >>= 0; + ASSERT128(I128(2, -1ul), x); + x = I128(2, -1ul); + x >>= 1; + ASSERT128(I128(1, IMAX), x); + x = I128(2, -1ul); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, -1ul); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(BANE, 0); + x >>= 0; + ASSERT128(I128(BANE, 0), x); + x = I128(BANE, 0); + x >>= 1; + ASSERT128(I128(0x4000000000000000, 0), x); + x = I128(BANE, 0); + x >>= 126; + ASSERT128(I128(0, 2), x); + x = I128(BANE, 0); + x >>= 127; + ASSERT128(I128(0, 1), x); + x = I128(BANE, 2); + x >>= 0; + ASSERT128(I128(BANE, 2), x); + x = I128(BANE, 2); + x >>= 1; + ASSERT128(I128(0x4000000000000000, 1), x); + x = I128(BANE, 2); + x >>= 126; + ASSERT128(I128(0, 2), x); + x = I128(BANE, 2); + x >>= 127; + ASSERT128(I128(0, 1), x); + x = I128(BANE, BANE); + x >>= 0; + ASSERT128(I128(BANE, BANE), x); + x = I128(BANE, BANE); + x >>= 1; + ASSERT128(I128(0x4000000000000000, 0x4000000000000000), x); + x = I128(BANE, BANE); + x >>= 126; + ASSERT128(I128(0, 2), x); + x = I128(BANE, BANE); + x >>= 127; + ASSERT128(I128(0, 1), x); + x = I128(BANE, -1ul); + x >>= 0; + ASSERT128(I128(BANE, -1ul), x); + x = I128(BANE, -1ul); + x >>= 1; + ASSERT128(I128(0x4000000000000000, IMAX), x); + x = I128(BANE, -1ul); + x >>= 126; + ASSERT128(I128(0, 2), x); + x = I128(BANE, -1ul); + x >>= 127; + ASSERT128(I128(0, 1), x); + x = I128(-1ul, 0); + x >>= 0; + ASSERT128(I128(-1ul, 0), x); + x = I128(-1ul, 0); + x >>= 1; + ASSERT128(I128(IMAX, BANE), x); + x = I128(-1ul, 0); + x >>= 126; + ASSERT128(I128(0, 3), x); + x = I128(-1ul, 0); + x >>= 127; + ASSERT128(I128(0, 1), x); + x = I128(-1ul, 2); + x >>= 0; + ASSERT128(I128(-1ul, 2), x); + x = I128(-1ul, 2); + x >>= 1; + ASSERT128(I128(IMAX, BANE1), x); + x = I128(-1ul, 2); + x >>= 126; + ASSERT128(I128(0, 3), x); + x = I128(-1ul, 2); + x >>= 127; + ASSERT128(I128(0, 1), x); + x = I128(-1ul, BANE); + x >>= 0; + ASSERT128(I128(-1ul, BANE), x); + x = I128(-1ul, BANE); + x >>= 1; + ASSERT128(I128(IMAX, 0xc000000000000000), x); + x = I128(-1ul, BANE); + x >>= 126; + ASSERT128(I128(0, 3), x); + x = I128(-1ul, BANE); + x >>= 127; + ASSERT128(I128(0, 1), x); + x = I128(-1ul, -1ul); + x >>= 0; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, -1ul); + x >>= 1; + ASSERT128(I128(IMAX, -1ul), x); + x = I128(-1ul, -1ul); + x >>= 126; + ASSERT128(I128(0, 3), x); + x = I128(-1ul, -1ul); + x >>= 127; + ASSERT128(I128(0, 1), x); +} + +void testSar128(void) { + __int128 x; + x = I128(0, 0); + x >>= 0; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x >>= 1; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, 2); + x >>= 0; + ASSERT128(I128(0, 2), x); + x = I128(0, 2); + x >>= 1; + ASSERT128(I128(0, 1), x); + x = I128(0, 2); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, 2); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, BANE); + x >>= 0; + ASSERT128(I128(0, BANE), x); + x = I128(0, BANE); + x >>= 1; + ASSERT128(I128(0, 0x4000000000000000), x); + x = I128(0, BANE); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, BANE); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, -1ul); + x >>= 0; + ASSERT128(I128(0, -1ul), x); + x = I128(0, -1ul); + x >>= 1; + ASSERT128(I128(0, IMAX), x); + x = I128(0, -1ul); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, -1ul); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, 0); + x >>= 0; + ASSERT128(I128(2, 0), x); + x = I128(2, 0); + x >>= 1; + ASSERT128(I128(1, 0), x); + x = I128(2, 0); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, 0); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, 2); + x >>= 0; + ASSERT128(I128(2, 2), x); + x = I128(2, 2); + x >>= 1; + ASSERT128(I128(1, 1), x); + x = I128(2, 2); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, 2); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, BANE); + x >>= 0; + ASSERT128(I128(2, BANE), x); + x = I128(2, BANE); + x >>= 1; + ASSERT128(I128(1, 0x4000000000000000), x); + x = I128(2, BANE); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, BANE); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, -1ul); + x >>= 0; + ASSERT128(I128(2, -1ul), x); + x = I128(2, -1ul); + x >>= 1; + ASSERT128(I128(1, IMAX), x); + x = I128(2, -1ul); + x >>= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, -1ul); + x >>= 127; + ASSERT128(I128(0, 0), x); + x = I128(BANE, 0); + x >>= 0; + ASSERT128(I128(BANE, 0), x); + x = I128(BANE, 0); + x >>= 1; + ASSERT128(I128(0xc000000000000000, 0), x); + x = I128(BANE, 0); + x >>= 126; + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x); + x = I128(BANE, 0); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(BANE, 2); + x >>= 0; + ASSERT128(I128(BANE, 2), x); + x = I128(BANE, 2); + x >>= 1; + ASSERT128(I128(0xc000000000000000, 1), x); + x = I128(BANE, 2); + x >>= 126; + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x); + x = I128(BANE, 2); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(BANE, BANE); + x >>= 0; + ASSERT128(I128(BANE, BANE), x); + x = I128(BANE, BANE); + x >>= 1; + ASSERT128(I128(0xc000000000000000, 0x4000000000000000), x); + x = I128(BANE, BANE); + x >>= 126; + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x); + x = I128(BANE, BANE); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(BANE, -1ul); + x >>= 0; + ASSERT128(I128(BANE, -1ul), x); + x = I128(BANE, -1ul); + x >>= 1; + ASSERT128(I128(0xc000000000000000, IMAX), x); + x = I128(BANE, -1ul); + x >>= 126; + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x); + x = I128(BANE, -1ul); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, 0); + x >>= 0; + ASSERT128(I128(-1ul, 0), x); + x = I128(-1ul, 0); + x >>= 1; + ASSERT128(I128(-1ul, BANE), x); + x = I128(-1ul, 0); + x >>= 126; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, 0); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, 2); + x >>= 0; + ASSERT128(I128(-1ul, 2), x); + x = I128(-1ul, 2); + x >>= 1; + ASSERT128(I128(-1ul, BANE1), x); + x = I128(-1ul, 2); + x >>= 126; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, 2); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, BANE); + x >>= 0; + ASSERT128(I128(-1ul, BANE), x); + x = I128(-1ul, BANE); + x >>= 1; + ASSERT128(I128(-1ul, 0xc000000000000000), x); + x = I128(-1ul, BANE); + x >>= 126; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, BANE); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, -1ul); + x >>= 0; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, -1ul); + x >>= 1; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, -1ul); + x >>= 126; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, -1ul); + x >>= 127; + ASSERT128(I128(-1ul, -1ul), x); +} + +void testShl128(void) { + __int128 x; + x = I128(0, 0); + x <<= 0; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x <<= 1; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, 0); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, 2); + x <<= 0; + ASSERT128(I128(0, 2), x); + x = I128(0, 2); + x <<= 1; + ASSERT128(I128(0, 4), x); + x = I128(0, 2); + x <<= 126; + ASSERT128(I128(BANE, 0), x); + x = I128(0, 2); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, BANE); + x <<= 0; + ASSERT128(I128(0, BANE), x); + x = I128(0, BANE); + x <<= 1; + ASSERT128(I128(1, 0), x); + x = I128(0, BANE); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(0, BANE); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(0, -1ul); + x <<= 0; + ASSERT128(I128(0, -1ul), x); + x = I128(0, -1ul); + x <<= 1; + ASSERT128(I128(1, 0xfffffffffffffffe), x); + x = I128(0, -1ul); + x <<= 126; + ASSERT128(I128(0xc000000000000000, 0), x); + x = I128(0, -1ul); + x <<= 127; + ASSERT128(I128(BANE, 0), x); + x = I128(2, 0); + x <<= 0; + ASSERT128(I128(2, 0), x); + x = I128(2, 0); + x <<= 1; + ASSERT128(I128(4, 0), x); + x = I128(2, 0); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, 0); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, 2); + x <<= 0; + ASSERT128(I128(2, 2), x); + x = I128(2, 2); + x <<= 1; + ASSERT128(I128(4, 4), x); + x = I128(2, 2); + x <<= 126; + ASSERT128(I128(BANE, 0), x); + x = I128(2, 2); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, BANE); + x <<= 0; + ASSERT128(I128(2, BANE), x); + x = I128(2, BANE); + x <<= 1; + ASSERT128(I128(5, 0), x); + x = I128(2, BANE); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(2, BANE); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(2, -1ul); + x <<= 0; + ASSERT128(I128(2, -1ul), x); + x = I128(2, -1ul); + x <<= 1; + ASSERT128(I128(5, 0xfffffffffffffffe), x); + x = I128(2, -1ul); + x <<= 126; + ASSERT128(I128(0xc000000000000000, 0), x); + x = I128(2, -1ul); + x <<= 127; + ASSERT128(I128(BANE, 0), x); + x = I128(BANE, 0); + x <<= 0; + ASSERT128(I128(BANE, 0), x); + x = I128(BANE, 0); + x <<= 1; + ASSERT128(I128(0, 0), x); + x = I128(BANE, 0); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(BANE, 0); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(BANE, 2); + x <<= 0; + ASSERT128(I128(BANE, 2), x); + x = I128(BANE, 2); + x <<= 1; + ASSERT128(I128(0, 4), x); + x = I128(BANE, 2); + x <<= 126; + ASSERT128(I128(BANE, 0), x); + x = I128(BANE, 2); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(BANE, BANE); + x <<= 0; + ASSERT128(I128(BANE, BANE), x); + x = I128(BANE, BANE); + x <<= 1; + ASSERT128(I128(1, 0), x); + x = I128(BANE, BANE); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(BANE, BANE); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(BANE, -1ul); + x <<= 0; + ASSERT128(I128(BANE, -1ul), x); + x = I128(BANE, -1ul); + x <<= 1; + ASSERT128(I128(1, 0xfffffffffffffffe), x); + x = I128(BANE, -1ul); + x <<= 126; + ASSERT128(I128(0xc000000000000000, 0), x); + x = I128(BANE, -1ul); + x <<= 127; + ASSERT128(I128(BANE, 0), x); + x = I128(-1ul, 0); + x <<= 0; + ASSERT128(I128(-1ul, 0), x); + x = I128(-1ul, 0); + x <<= 1; + ASSERT128(I128(0xfffffffffffffffe, 0), x); + x = I128(-1ul, 0); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(-1ul, 0); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(-1ul, 2); + x <<= 0; + ASSERT128(I128(-1ul, 2), x); + x = I128(-1ul, 2); + x <<= 1; + ASSERT128(I128(0xfffffffffffffffe, 4), x); + x = I128(-1ul, 2); + x <<= 126; + ASSERT128(I128(BANE, 0), x); + x = I128(-1ul, 2); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(-1ul, BANE); + x <<= 0; + ASSERT128(I128(-1ul, BANE), x); + x = I128(-1ul, BANE); + x <<= 1; + ASSERT128(I128(-1ul, 0), x); + x = I128(-1ul, BANE); + x <<= 126; + ASSERT128(I128(0, 0), x); + x = I128(-1ul, BANE); + x <<= 127; + ASSERT128(I128(0, 0), x); + x = I128(-1ul, -1ul); + x <<= 0; + ASSERT128(I128(-1ul, -1ul), x); + x = I128(-1ul, -1ul); + x <<= 1; + ASSERT128(I128(-1ul, 0xfffffffffffffffe), x); + x = I128(-1ul, -1ul); + x <<= 126; + ASSERT128(I128(0xc000000000000000, 0), x); + x = I128(-1ul, -1ul); + x <<= 127; + ASSERT128(I128(BANE, 0), x); +} + +void testNeg128(void) { + __int128 x; + x = I128(0, 0); + ASSERT128(I128(0, 0), -x); + x = I128(0, 2); + ASSERT128(I128(-1ul, 0xfffffffffffffffe), -x); + x = I128(0, BANE); + ASSERT128(I128(-1ul, BANE), -x); + x = I128(0, -1ul); + ASSERT128(I128(-1ul, 1), -x); + x = I128(2, 0); + ASSERT128(I128(0xfffffffffffffffe, 0), -x); + x = I128(2, 2); + ASSERT128(I128(IMAX2, 0xfffffffffffffffe), -x); + x = I128(2, BANE); + ASSERT128(I128(IMAX2, BANE), -x); + x = I128(2, -1ul); + ASSERT128(I128(IMAX2, 1), -x); + x = I128(BANE, 0); + ASSERT128(I128(BANE, 0), -x); + x = I128(BANE, 2); + ASSERT128(I128(IMAX, 0xfffffffffffffffe), -x); + x = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE), -x); + x = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 1), -x); + x = I128(-1ul, 0); + ASSERT128(I128(1, 0), -x); + x = I128(-1ul, 2); + ASSERT128(I128(0, 0xfffffffffffffffe), -x); + x = I128(-1ul, BANE); + ASSERT128(I128(0, BANE), -x); + x = I128(-1ul, -1ul); + ASSERT128(I128(0, 1), -x); +} + +void testXor128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 2), x ^ y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x ^ y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x ^ y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(2, 0), x ^ y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(2, 2), x ^ y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x ^ y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x ^ y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x ^ y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x ^ y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x ^ y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x ^ y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x ^ y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x ^ y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x ^ y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x ^ y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 0), x ^ y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(2, 2), x ^ y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(2, 0), x ^ y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(2, BANE2), x ^ y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, IMAX2), x ^ y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 2), x ^ y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0), x ^ y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE2), x ^ y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, IMAX2), x ^ y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x ^ y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0), x ^ y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x ^ y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, IMAX2), x ^ y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x ^ y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(2, BANE), x ^ y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(2, BANE2), x ^ y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x ^ y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, IMAX), x ^ y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, BANE), x ^ y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, BANE2), x ^ y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x ^ y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, IMAX), x ^ y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x ^ y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE2), x ^ y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x ^ y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, IMAX), x ^ y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x ^ y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(2, -1ul), x ^ y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(2, IMAX2), x ^ y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(2, IMAX), x ^ y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(2, 0), x ^ y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, -1ul), x ^ y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, IMAX2), x ^ y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, IMAX), x ^ y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 0), x ^ y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x ^ y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, IMAX2), x ^ y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, IMAX), x ^ y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 0), x ^ y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(2, 2), x ^ y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(2, BANE), x ^ y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(2, -1ul), x ^ y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x ^ y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(0, 2), x ^ y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x ^ y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, -1ul), x ^ y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 2), x ^ y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, BANE), x ^ y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, -1ul), x ^ y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX2, 2), x ^ y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX2, BANE), x ^ y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, -1ul), x ^ y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(2, 0), x ^ y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(2, BANE2), x ^ y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(2, IMAX2), x ^ y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(0, 2), x ^ y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(0, 0), x ^ y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 2), x ^ y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, BANE2), x ^ y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, IMAX2), x ^ y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX2, 2), x ^ y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX2, BANE2), x ^ y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, IMAX2), x ^ y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(2, BANE2), x ^ y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(2, 0), x ^ y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(2, IMAX), x ^ y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(0, BANE), x ^ y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x ^ y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, BANE), x ^ y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, BANE2), x ^ y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, IMAX), x ^ y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX2, BANE), x ^ y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX2, BANE2), x ^ y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, IMAX), x ^ y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(2, IMAX2), x ^ y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(2, IMAX), x ^ y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(2, 0), x ^ y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, -1ul), x ^ y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x ^ y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, -1ul), x ^ y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, IMAX2), x ^ y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, IMAX), x ^ y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX2, -1ul), x ^ y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX2, IMAX2), x ^ y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX2, IMAX), x ^ y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(BANE, 2), x ^ y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(BANE, BANE), x ^ y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(BANE, -1ul), x ^ y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(BANE2, 2), x ^ y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(BANE2, BANE), x ^ y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, -1ul), x ^ y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x ^ y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x ^ y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x ^ y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, -1ul), x ^ y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, 2), x ^ y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX, BANE), x ^ y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(BANE, 0), x ^ y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(BANE, BANE2), x ^ y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(BANE, IMAX2), x ^ y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(BANE2, 2), x ^ y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(BANE2, BANE2), x ^ y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, IMAX2), x ^ y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 2), x ^ y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x ^ y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, 2), x ^ y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX, BANE2), x ^ y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, IMAX2), x ^ y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(BANE, BANE2), x ^ y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(BANE, 0), x ^ y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(BANE, IMAX), x ^ y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(BANE2, BANE), x ^ y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(BANE2, BANE2), x ^ y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, IMAX), x ^ y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, BANE), x ^ y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x ^ y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, BANE), x ^ y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, BANE2), x ^ y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, IMAX), x ^ y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(BANE, IMAX2), x ^ y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(BANE, IMAX), x ^ y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(BANE, 0), x ^ y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(BANE2, -1ul), x ^ y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(BANE2, IMAX2), x ^ y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(BANE2, IMAX), x ^ y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, 0), x ^ y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, -1ul), x ^ y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x ^ y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(IMAX, -1ul), x ^ y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(IMAX, IMAX2), x ^ y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(IMAX, IMAX), x ^ y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(-1ul, 2), x ^ y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE), x ^ y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x ^ y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(IMAX2, 2), x ^ y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, BANE), x ^ y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, -1ul), x ^ y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 2), x ^ y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE), x ^ y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, -1ul), x ^ y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x ^ y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 2), x ^ y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE), x ^ y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, -1ul), x ^ y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(-1ul, 0), x ^ y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE2), x ^ y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, IMAX2), x ^ y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(IMAX2, 2), x ^ y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, BANE2), x ^ y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, IMAX2), x ^ y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, 2), x ^ y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, BANE2), x ^ y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, IMAX2), x ^ y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 2), x ^ y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x ^ y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(-1ul, BANE2), x ^ y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(-1ul, 0), x ^ y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, IMAX), x ^ y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(IMAX2, BANE), x ^ y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(IMAX2, BANE2), x ^ y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, IMAX), x ^ y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, BANE), x ^ y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, BANE2), x ^ y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, IMAX), x ^ y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, BANE), x ^ y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, BANE2), x ^ y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x ^ y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(-1ul, IMAX2), x ^ y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(-1ul, IMAX), x ^ y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, 0), x ^ y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(IMAX2, -1ul), x ^ y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(IMAX2, IMAX2), x ^ y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(IMAX2, IMAX), x ^ y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(IMAX2, 0), x ^ y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(IMAX, -1ul), x ^ y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(IMAX, IMAX2), x ^ y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(IMAX, IMAX), x ^ y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 0), x ^ y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, -1ul), x ^ y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, IMAX2), x ^ y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, IMAX), x ^ y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x ^ y); +} + +void testAnd128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(2, 2), x & y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, 2), x & y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(2, 2), x & y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(2, 0), x & y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, 2), x & y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(2, 0), x & y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x & y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, BANE), x & y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(2, 0), x & y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(2, BANE), x & y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, BANE), x & y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(2, 2), x & y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x & y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x & y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(2, 2), x & y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(2, BANE), x & y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(2, -1ul), x & y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x & y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 2), x & y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 2), x & y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, 2), x & y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(0, 0), x & y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x & y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x & y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(BANE, 2), x & y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(BANE, -1ul), x & y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, 0), x & y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(0, 0), x & y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, 2), x & y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(2, 2), x & y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, 2), x & y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x & y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, 2), x & y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x & y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, 2), x & y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(0, 0), x & y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, BANE), x & y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x & y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, BANE), x & y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x & y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, BANE), x & y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, 2), x & y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x & y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x & y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(2, 0), x & y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(2, 2), x & y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x & y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x & y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x & y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x & y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x & y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x & y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x & y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x & y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x & y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x & y); +} + +void testOr128(void) { + __int128 x, y; + x = I128(0, 0); + y = I128(0, 2); + ASSERT128(I128(0, 2), x | y); + x = I128(0, 0); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x | y); + x = I128(0, 0); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x | y); + x = I128(0, 0); + y = I128(2, 0); + ASSERT128(I128(2, 0), x | y); + x = I128(0, 0); + y = I128(2, 2); + ASSERT128(I128(2, 2), x | y); + x = I128(0, 0); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x | y); + x = I128(0, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(0, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x | y); + x = I128(0, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x | y); + x = I128(0, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(0, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(0, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x | y); + x = I128(0, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(0, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(0, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(0, 2); + y = I128(0, 2); + ASSERT128(I128(0, 2), x | y); + x = I128(0, 2); + y = I128(0, BANE); + ASSERT128(I128(0, BANE2), x | y); + x = I128(0, 2); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x | y); + x = I128(0, 2); + y = I128(2, 0); + ASSERT128(I128(2, 2), x | y); + x = I128(0, 2); + y = I128(2, 2); + ASSERT128(I128(2, 2), x | y); + x = I128(0, 2); + y = I128(2, BANE); + ASSERT128(I128(2, BANE2), x | y); + x = I128(0, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(0, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 2), x | y); + x = I128(0, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x | y); + x = I128(0, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE2), x | y); + x = I128(0, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(0, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(0, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(0, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(0, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(0, BANE); + y = I128(0, 2); + ASSERT128(I128(0, BANE2), x | y); + x = I128(0, BANE); + y = I128(0, BANE); + ASSERT128(I128(0, BANE), x | y); + x = I128(0, BANE); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x | y); + x = I128(0, BANE); + y = I128(2, 0); + ASSERT128(I128(2, BANE), x | y); + x = I128(0, BANE); + y = I128(2, 2); + ASSERT128(I128(2, BANE2), x | y); + x = I128(0, BANE); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x | y); + x = I128(0, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(0, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(0, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, BANE2), x | y); + x = I128(0, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(0, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(0, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(0, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(0, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(0, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(0, -1ul); + y = I128(0, 2); + ASSERT128(I128(0, -1ul), x | y); + x = I128(0, -1ul); + y = I128(0, BANE); + ASSERT128(I128(0, -1ul), x | y); + x = I128(0, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(0, -1ul), x | y); + x = I128(0, -1ul); + y = I128(2, 0); + ASSERT128(I128(2, -1ul), x | y); + x = I128(0, -1ul); + y = I128(2, 2); + ASSERT128(I128(2, -1ul), x | y); + x = I128(0, -1ul); + y = I128(2, BANE); + ASSERT128(I128(2, -1ul), x | y); + x = I128(0, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(0, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(0, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(0, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(0, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(0, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(0, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(0, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(0, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(2, 0); + y = I128(0, 2); + ASSERT128(I128(2, 2), x | y); + x = I128(2, 0); + y = I128(0, BANE); + ASSERT128(I128(2, BANE), x | y); + x = I128(2, 0); + y = I128(0, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, 0); + y = I128(2, 0); + ASSERT128(I128(2, 0), x | y); + x = I128(2, 0); + y = I128(2, 2); + ASSERT128(I128(2, 2), x | y); + x = I128(2, 0); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x | y); + x = I128(2, 0); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 0), x | y); + x = I128(2, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 2), x | y); + x = I128(2, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, BANE), x | y); + x = I128(2, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(2, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x | y); + x = I128(2, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(2, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(2, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(2, 2); + y = I128(0, 2); + ASSERT128(I128(2, 2), x | y); + x = I128(2, 2); + y = I128(0, BANE); + ASSERT128(I128(2, BANE2), x | y); + x = I128(2, 2); + y = I128(0, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, 2); + y = I128(2, 0); + ASSERT128(I128(2, 2), x | y); + x = I128(2, 2); + y = I128(2, 2); + ASSERT128(I128(2, 2), x | y); + x = I128(2, 2); + y = I128(2, BANE); + ASSERT128(I128(2, BANE2), x | y); + x = I128(2, 2); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, 2), x | y); + x = I128(2, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, 2), x | y); + x = I128(2, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, BANE2), x | y); + x = I128(2, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(2, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(2, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(2, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(2, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(2, BANE); + y = I128(0, 2); + ASSERT128(I128(2, BANE2), x | y); + x = I128(2, BANE); + y = I128(0, BANE); + ASSERT128(I128(2, BANE), x | y); + x = I128(2, BANE); + y = I128(0, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, BANE); + y = I128(2, 0); + ASSERT128(I128(2, BANE), x | y); + x = I128(2, BANE); + y = I128(2, 2); + ASSERT128(I128(2, BANE2), x | y); + x = I128(2, BANE); + y = I128(2, BANE); + ASSERT128(I128(2, BANE), x | y); + x = I128(2, BANE); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, BANE), x | y); + x = I128(2, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, BANE2), x | y); + x = I128(2, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, BANE), x | y); + x = I128(2, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(2, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(2, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(2, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(2, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(2, -1ul); + y = I128(0, 2); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(0, BANE); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(2, 0); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(2, 2); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(2, BANE); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(2, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(2, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(2, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(2, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(BANE, 0); + y = I128(0, 2); + ASSERT128(I128(BANE, 2), x | y); + x = I128(BANE, 0); + y = I128(0, BANE); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(BANE, 0); + y = I128(0, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, 0); + y = I128(2, 0); + ASSERT128(I128(BANE2, 0), x | y); + x = I128(BANE, 0); + y = I128(2, 2); + ASSERT128(I128(BANE2, 2), x | y); + x = I128(BANE, 0); + y = I128(2, BANE); + ASSERT128(I128(BANE2, BANE), x | y); + x = I128(BANE, 0); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(BANE, 0); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 0), x | y); + x = I128(BANE, 0); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x | y); + x = I128(BANE, 0); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(BANE, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x | y); + x = I128(BANE, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(BANE, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(BANE, 2); + y = I128(0, 2); + ASSERT128(I128(BANE, 2), x | y); + x = I128(BANE, 2); + y = I128(0, BANE); + ASSERT128(I128(BANE, BANE2), x | y); + x = I128(BANE, 2); + y = I128(0, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, 2); + y = I128(2, 0); + ASSERT128(I128(BANE2, 2), x | y); + x = I128(BANE, 2); + y = I128(2, 2); + ASSERT128(I128(BANE2, 2), x | y); + x = I128(BANE, 2); + y = I128(2, BANE); + ASSERT128(I128(BANE2, BANE2), x | y); + x = I128(BANE, 2); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(BANE, 2); + y = I128(BANE, 0); + ASSERT128(I128(BANE, 2), x | y); + x = I128(BANE, 2); + y = I128(BANE, 2); + ASSERT128(I128(BANE, 2), x | y); + x = I128(BANE, 2); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE2), x | y); + x = I128(BANE, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(BANE, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(BANE, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(BANE, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(BANE, BANE); + y = I128(0, 2); + ASSERT128(I128(BANE, BANE2), x | y); + x = I128(BANE, BANE); + y = I128(0, BANE); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(BANE, BANE); + y = I128(0, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, BANE); + y = I128(2, 0); + ASSERT128(I128(BANE2, BANE), x | y); + x = I128(BANE, BANE); + y = I128(2, 2); + ASSERT128(I128(BANE2, BANE2), x | y); + x = I128(BANE, BANE); + y = I128(2, BANE); + ASSERT128(I128(BANE2, BANE), x | y); + x = I128(BANE, BANE); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(BANE, BANE); + y = I128(BANE, 0); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(BANE, BANE); + y = I128(BANE, 2); + ASSERT128(I128(BANE, BANE2), x | y); + x = I128(BANE, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, BANE), x | y); + x = I128(BANE, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(BANE, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(BANE, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(BANE, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(0, 2); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(0, BANE); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(2, 0); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(2, 2); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(2, BANE); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(BANE2, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(BANE, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(BANE, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 0); + y = I128(0, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 0); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, 0); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 0); + y = I128(2, 0); + ASSERT128(I128(-1ul, 0), x | y); + x = I128(-1ul, 0); + y = I128(2, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 0); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, 0); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 0); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, 0), x | y); + x = I128(-1ul, 0); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 0); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, 0); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 0); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 0), x | y); + x = I128(-1ul, 0); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 0); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, 0); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 2); + y = I128(0, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 2); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, 2); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 2); + y = I128(2, 0); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 2); + y = I128(2, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 2); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, 2); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 2); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 2); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 2); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, 2); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, 2); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 2); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, 2), x | y); + x = I128(-1ul, 2); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, 2); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, BANE); + y = I128(0, 2); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, BANE); + y = I128(0, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, BANE); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, BANE); + y = I128(2, 0); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, BANE); + y = I128(2, 2); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, BANE); + y = I128(2, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, BANE); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, BANE); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, BANE); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, BANE); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, BANE); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, BANE); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, BANE); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, BANE2), x | y); + x = I128(-1ul, BANE); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, BANE), x | y); + x = I128(-1ul, BANE); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(0, 2); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(0, BANE); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(0, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(2, 0); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(2, 2); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(2, BANE); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(2, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(BANE, 0); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(BANE, 2); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(BANE, BANE); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(BANE, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 0); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(-1ul, 2); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(-1ul, BANE); + ASSERT128(I128(-1ul, -1ul), x | y); + x = I128(-1ul, -1ul); + y = I128(-1ul, -1ul); + ASSERT128(I128(-1ul, -1ul), x | y); +} + +void testNot128(void) { + __int128 x; + x = I128(0, 0); + ASSERT128(I128(-1ul, -1ul), ~x); + x = I128(0, 2); + ASSERT128(I128(-1ul, IMAX2), ~x); + x = I128(0, BANE); + ASSERT128(I128(-1ul, IMAX), ~x); + x = I128(0, -1ul); + ASSERT128(I128(-1ul, 0), ~x); + x = I128(2, 0); + ASSERT128(I128(IMAX2, -1ul), ~x); + x = I128(2, 2); + ASSERT128(I128(IMAX2, IMAX2), ~x); + x = I128(2, BANE); + ASSERT128(I128(IMAX2, IMAX), ~x); + x = I128(2, -1ul); + ASSERT128(I128(IMAX2, 0), ~x); + x = I128(BANE, 0); + ASSERT128(I128(IMAX, -1ul), ~x); + x = I128(BANE, 2); + ASSERT128(I128(IMAX, IMAX2), ~x); + x = I128(BANE, BANE); + ASSERT128(I128(IMAX, IMAX), ~x); + x = I128(BANE, -1ul); + ASSERT128(I128(IMAX, 0), ~x); + x = I128(-1ul, 0); + ASSERT128(I128(0, -1ul), ~x); + x = I128(-1ul, 2); + ASSERT128(I128(0, IMAX2), ~x); + x = I128(-1ul, BANE); + ASSERT128(I128(0, IMAX), ~x); + x = I128(-1ul, -1ul); + ASSERT128(I128(0, 0), ~x); +} + +int main(void) { + testLang128(); + testCompare128(); + testAdd128(); + testSub128(); + testMul128(); + testDiv128(); + testDivu128(); + testRem128(); + testRemu128(); + testShr128(); + testSar128(); + testShl128(); + testNeg128(); + testXor128(); + testAnd128(); + testOr128(); + testNot128(); + testCastDblInt128(); + testCastDblUint128(); + testCastLdblInt128(); + testCastLdblUint128(); + return 0; +} diff --git a/third_party/chibicc/test/line_test.c b/third_party/chibicc/test/line_test.c new file mode 100644 index 00000000..78cbf8aa --- /dev/null +++ b/third_party/chibicc/test/line_test.c @@ -0,0 +1,20 @@ +#include "third_party/chibicc/test/test.h" + +int main() { +#line 500 "foo" + ASSERT(501, __LINE__); + ASSERT(0, strcmp(__FILE__, "foo")); + +#line 800 "bar" + ASSERT(801, __LINE__); + ASSERT(0, strcmp(__FILE__, "bar")); + +#line 1 + ASSERT(2, __LINE__); + +# 200 "xyz" 2 3 + ASSERT(201, __LINE__); + ASSERT(0, strcmp(__FILE__, "xyz")); + + return 0; +} diff --git a/third_party/chibicc/test/literal_test.c b/third_party/chibicc/test/literal_test.c new file mode 100644 index 00000000..47de3fe3 --- /dev/null +++ b/third_party/chibicc/test/literal_test.c @@ -0,0 +1,108 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(97, 'a'); + ASSERT(10, '\n'); + ASSERT(-128, '\x80'); + + ASSERT(511, 0777); + ASSERT(0, 0x0); + ASSERT(10, 0xa); + ASSERT(10, 0XA); + ASSERT(48879, 0xbeef); + ASSERT(48879, 0xBEEF); + ASSERT(48879, 0XBEEF); + ASSERT(0, 0b0); + ASSERT(1, 0b1); + ASSERT(47, 0b101111); + ASSERT(47, 0B101111); + + ASSERT(4, sizeof(0)); + ASSERT(8, sizeof(0L)); + ASSERT(8, sizeof(0LU)); + ASSERT(8, sizeof(0UL)); + ASSERT(8, sizeof(0LL)); + ASSERT(8, sizeof(0LLU)); + ASSERT(8, sizeof(0Ull)); + ASSERT(8, sizeof(0l)); + ASSERT(8, sizeof(0ll)); + ASSERT(8, sizeof(0x0L)); + ASSERT(8, sizeof(0b0L)); + ASSERT(4, sizeof(2147483647)); + ASSERT(8, sizeof(2147483648)); + ASSERT(-1, 0xffffffffffffffff); + ASSERT(8, sizeof(0xffffffffffffffff)); + ASSERT(4, sizeof(4294967295U)); + ASSERT(8, sizeof(4294967296U)); + + ASSERT(3, -1U >> 30); + ASSERT(3, -1Ul >> 62); + ASSERT(3, -1ull >> 62); + + ASSERT(1, 0xffffffffffffffffl >> 63); + ASSERT(1, 0xffffffffffffffffll >> 63); + + ASSERT(-1, 18446744073709551615); + ASSERT(8, sizeof(18446744073709551615)); + ASSERT(-1, 18446744073709551615 >> 63); + + ASSERT(-1, 0xffffffffffffffff); + ASSERT(8, sizeof(0xffffffffffffffff)); + ASSERT(1, 0xffffffffffffffff >> 63); + + ASSERT(-1, 01777777777777777777777); + ASSERT(8, sizeof(01777777777777777777777)); + ASSERT(1, 01777777777777777777777 >> 63); + + ASSERT(-1, + 0b1111111111111111111111111111111111111111111111111111111111111111); + ASSERT( + 8, + sizeof( + 0b1111111111111111111111111111111111111111111111111111111111111111)); + ASSERT( + 1, + 0b1111111111111111111111111111111111111111111111111111111111111111 >> 63); + + ASSERT(8, sizeof(2147483648)); + ASSERT(4, sizeof(2147483647)); + + ASSERT(8, sizeof(0x1ffffffff)); + ASSERT(4, sizeof(0xffffffff)); + ASSERT(1, 0xffffffff >> 31); + + ASSERT(8, sizeof(040000000000)); + ASSERT(4, sizeof(037777777777)); + ASSERT(1, 037777777777 >> 31); + + ASSERT(8, sizeof(0b111111111111111111111111111111111)); + ASSERT(4, sizeof(0b11111111111111111111111111111111)); + ASSERT(1, 0b11111111111111111111111111111111 >> 31); + + ASSERT(-1, 1 << 31 >> 31); + ASSERT(-1, 01 << 31 >> 31); + ASSERT(-1, 0x1 << 31 >> 31); + ASSERT(-1, 0b1 << 31 >> 31); + + 0.0; + 1.0; + 3e+8; + 0x10.1p0; + .1E4f; + + ASSERT(4, sizeof(8f)); + ASSERT(4, sizeof(0.3F)); + ASSERT(8, sizeof(0.)); + ASSERT(8, sizeof(.0)); + ASSERT(16, sizeof(5.l)); + ASSERT(16, sizeof(2.0L)); + + Assert(1, size\ +of(char), + "sizeof(char)"); + + ASSERT(4, sizeof(L'\0')); + ASSERT(97, L'a'); + + return 0; +} diff --git a/third_party/chibicc/test/macro_test.c b/third_party/chibicc/test/macro_test.c new file mode 100644 index 00000000..d2bfb664 --- /dev/null +++ b/third_party/chibicc/test/macro_test.c @@ -0,0 +1,413 @@ +#include "third_party/chibicc/test/include1.h" +#include "third_party/chibicc/test/test.h" +/* clang-format off */ +char *main_filename1 = __FILE__; +int main_line1 = __LINE__; +#define LINE() __LINE__ +int main_line2 = LINE(); + +# + +/* */ # + +int ret3(void) { return 3; } +int dbl(int x) { return x*x; } + +int add2(int x, int y) { + return x + y; +} + +int add6(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} + +int main() { + ASSERT(5, include1); + ASSERT(7, include2); + +#if 0 +#include "/no/such/file" + ASSERT(0, 1); +#if nested +#endif +#endif + + int m = 0; + +#if 1 + m = 5; +#endif + ASSERT(5, m); + +#if 1 +# if 0 +# if 1 + foo bar +# endif +# endif + m = 3; +#endif + ASSERT(3, m); + +#if 1-1 +# if 1 +# endif +# if 1 +# else +# endif +# if 0 +# else +# endif + m = 2; +#else +# if 1 + m = 3; +# endif +#endif + ASSERT(3, m); + +#if 1 + m = 2; +#else + m = 3; +#endif + ASSERT(2, m); + +#if 1 + m = 2; +#else + m = 3; +#endif + ASSERT(2, m); + +#if 0 + m = 1; +#elif 0 + m = 2; +#elif 3+5 + m = 3; +#elif 1*5 + m = 4; +#endif + ASSERT(3, m); + +#if 1+5 + m = 1; +#elif 1 + m = 2; +#elif 3 + m = 2; +#endif + ASSERT(1, m); + +#if 0 + m = 1; +#elif 1 +# if 1 + m = 2; +# else + m = 3; +# endif +#else + m = 5; +#endif + ASSERT(2, m); + + int M1 = 5; + +#define M1 3 + ASSERT(3, M1); +#define M1 4 + ASSERT(4, M1); + +#define M1 3+4+ + ASSERT(12, M1 5); + +#define M1 3+4 + ASSERT(23, M1*5); + +#define ASSERT_ Assert( +#define if 5 +#define five "5" +#define END ) + ASSERT_ 5, if, five END; + +#undef ASSERT_ +#undef if +#undef five +#undef END + + if (0); + +#define M 5 +#if M + m = 5; +#else + m = 6; +#endif + ASSERT(5, m); + +#define M 5 +#if M-5 + m = 6; +#elif M + m = 5; +#endif + ASSERT(5, m); + + int M2 = 6; +#define M2 M2 + 3 + ASSERT(9, M2); + +#define M3 M2 + 3 + ASSERT(12, M3); + + int M4 = 3; +#define M4 M5 * 5 +#define M5 M4 + 2 + ASSERT(13, M4); + +#ifdef M6 + m = 5; +#else + m = 3; +#endif + ASSERT(3, m); + +#define M6 +#ifdef M6 + m = 5; +#else + m = 3; +#endif + ASSERT(5, m); + +#ifndef M7 + m = 3; +#else + m = 5; +#endif + ASSERT(3, m); + +#define M7 +#ifndef M7 + m = 3; +#else + m = 5; +#endif + ASSERT(5, m); + +#if 0 +#ifdef NO_SUCH_MACRO +#endif +#ifndef NO_SUCH_MACRO +#endif +#else +#endif + +#define M7() 1 + int M7 = 5; + ASSERT(1, M7()); + ASSERT(5, M7); + +#define M7 () + ASSERT(3, ret3 M7); + +#define M8(x,y) x+y + ASSERT(7, M8(3, 4)); + +#define M8(x,y) x*y + ASSERT(24, M8(3+4, 4+5)); + +#define M8(x,y) (x)*(y) + ASSERT(63, M8(3+4, 4+5)); + +#define M8(x,y) x y + ASSERT(9, M8(, 4+5)); + +#define M8(x,y) x*y + ASSERT(20, M8((2+3), 4)); + +#define M8(x,y) x*y + ASSERT(12, M8((2,3), 4)); + +#define dbl(x) M10(x) * x +#define M10(x) dbl(x) + 3 + ASSERT(10, dbl(2)); + +#define M11(x) #x + ASSERT('a', M11( a!b `""c)[0]); + ASSERT('!', M11( a!b `""c)[1]); + ASSERT('b', M11( a!b `""c)[2]); + ASSERT(' ', M11( a!b `""c)[3]); + ASSERT('`', M11( a!b `""c)[4]); + ASSERT('"', M11( a!b `""c)[5]); + ASSERT('"', M11( a!b `""c)[6]); + ASSERT('c', M11( a!b `""c)[7]); + ASSERT(0, M11( a!b `""c)[8]); + +#define paste(x,y) x##y + ASSERT(15, paste(1,5)); + ASSERT(255, paste(0,xff)); + ASSERT(3, ({ int foobar=3; paste(foo,bar); })); + ASSERT(5, paste(5,)); + ASSERT(5, paste(,5)); + +#define i 5 + ASSERT(101, ({ int i3=100; paste(1+i,3); })); +#undef i + +#define paste2(x) x##5 + ASSERT(26, paste2(1+2)); + +#define paste3(x) 2##x + ASSERT(23, paste3(1+2)); + +#define paste4(x, y, z) x##y##z + ASSERT(123, paste4(1,2,3)); + +#define M12 +#if defined(M12) + m = 3; +#else + m = 4; +#endif + ASSERT(3, m); + +#define M12 +#if defined M12 + m = 3; +#else + m = 4; +#endif + ASSERT(3, m); + +#if defined(M12) - 1 + m = 3; +#else + m = 4; +#endif + ASSERT(4, m); + +#if defined(NO_SUCH_MACRO) + m = 3; +#else + m = 4; +#endif + ASSERT(4, m); + +#if no_such_symbol == 0 + m = 5; +#else + m = 6; +#endif + ASSERT(5, m); + +#define STR(x) #x +#define M12(x) STR(x) +#define M13(x) M12(foo.x) + ASSERT(0, strcmp(M13(bar), "foo.bar")); + +#define M13(x) M12(foo. x) + ASSERT(0, strcmp(M13(bar), "foo. bar")); + +#define M12 foo +#define M13(x) STR(x) +#define M14(x) M13(x.M12) + ASSERT(0, strcmp(M14(bar), "bar.foo")); + +#define M14(x) M13(x. M12) + ASSERT(0, strcmp(M14(bar), "bar. foo")); + +#include "third_party/chibicc/test/include3.h" + ASSERT(3, foo); + +#include "third_party/chibicc/test/include4.h" + ASSERT(4, foo); + +#define M13 "third_party/chibicc/test/include3.h" +#include M13 + ASSERT(3, foo); + +#define M13 < third_party/chibicc/test/include4.h +#include M13 > + ASSERT(4, foo); + +#undef foo + + ASSERT(1, __STDC__); + + ASSERT(0, strcmp(main_filename1, "third_party/chibicc/test/macro_test.c")); + ASSERT(5, main_line1); + ASSERT(7, main_line2); + ASSERT(0, strcmp(include1_filename, "third_party/chibicc/test/include1.h")); + ASSERT(4, include1_line); + +#define M14(...) 3 + ASSERT(3, M14()); + +#define M14(...) __VA_ARGS__ + ASSERT(2, M14() 2); + ASSERT(5, M14(5)); + +#define M14(...) add2(__VA_ARGS__) + ASSERT(8, M14(2, 6)); + +#define M14(...) add6(1,2,__VA_ARGS__,6) + ASSERT(21, M14(3,4,5)); + +#define M14(x, ...) add6(1,2,x,__VA_ARGS__,6) + ASSERT(21, M14(3,4,5)); + +#define M14(args...) 3 + ASSERT(3, M14()); + +#define M14(x, ...) x + ASSERT(5, M14(5)); + +#define M14(args...) args + ASSERT(2, M14() 2); + ASSERT(5, M14(5)); + +#define M14(args...) add2(args) + ASSERT(8, M14(2, 6)); + +#define M14(args...) add6(1,2,args,6) + ASSERT(21, M14(3,4,5)); + +#define M14(x, args...) add6(1,2,x,args,6) + ASSERT(21, M14(3,4,5)); + +#define M14(x, args...) x + ASSERT(5, M14(5)); + +#define CONCAT(x,y) x##y + ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); })); + ASSERT(5, ({ CONCAT(4,.57) + 0.5; })); + + ASSERT(11, strlen(__DATE__)); + ASSERT(8, strlen(__TIME__)); + + ASSERT(0, __COUNTER__); + ASSERT(1, __COUNTER__); + ASSERT(2, __COUNTER__); + + ASSERT(24, strlen(__TIMESTAMP__)); + + ASSERT(0, strcmp(__BASE_FILE__, "third_party/chibicc/test/macro_test.c")); + +#define M30(buf, fmt, ...) sprintf(buf, fmt __VA_OPT__(,) __VA_ARGS__) + ASSERT(0, ({ char buf[100]; M30(buf, "foo"); strcmp(buf, "foo"); })); + ASSERT(0, ({ char buf[100]; M30(buf, "foo%d", 3); strcmp(buf, "foo3"); })); + ASSERT(0, ({ char buf[100]; M30(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); })); + +#define M31(buf, fmt, ...) sprintf(buf, fmt, ## __VA_ARGS__) + ASSERT(0, ({ char buf[100]; M31(buf, "foo"); strcmp(buf, "foo"); })); + ASSERT(0, ({ char buf[100]; M31(buf, "foo%d", 3); strcmp(buf, "foo3"); })); + ASSERT(0, ({ char buf[100]; M31(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); })); + +#define M31(x, y) (1, ##x y) + ASSERT(3, M31(, 3)); + + return 0; +} diff --git a/third_party/chibicc/test/offsetof_test.c b/third_party/chibicc/test/offsetof_test.c new file mode 100644 index 00000000..418ac127 --- /dev/null +++ b/third_party/chibicc/test/offsetof_test.c @@ -0,0 +1,17 @@ +#include "third_party/chibicc/test/test.h" + +typedef struct { + int a; + char b; + int c; + double d; +} T; + +int main() { + ASSERT(0, offsetof(T, a)); + ASSERT(4, offsetof(T, b)); + ASSERT(8, offsetof(T, c)); + ASSERT(16, offsetof(T, d)); + + return 0; +} diff --git a/third_party/chibicc/test/pointer_test.c b/third_party/chibicc/test/pointer_test.c new file mode 100644 index 00000000..e1953760 --- /dev/null +++ b/third_party/chibicc/test/pointer_test.c @@ -0,0 +1,202 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(3, ({ + int x = 3; + *&x; + })); + ASSERT(3, ({ + int x = 3; + int *y = &x; + int **z = &y; + **z; + })); + ASSERT(5, ({ + int x = 3; + int y = 5; + *(&x + 1); + })); + ASSERT(3, ({ + int x = 3; + int y = 5; + *(&y - 1); + })); + ASSERT(5, ({ + int x = 3; + int y = 5; + *(&x - (-1)); + })); + ASSERT(5, ({ + int x = 3; + int *y = &x; + *y = 5; + x; + })); + ASSERT(7, ({ + int x = 3; + int y = 5; + *(&x + 1) = 7; + y; + })); + ASSERT(7, ({ + int x = 3; + int y = 5; + *(&y - 2 + 1) = 7; + x; + })); + ASSERT(5, ({ + int x = 3; + (&x + 2) - &x + 3; + })); + ASSERT(8, ({ + int x, y; + x = 3; + y = 5; + x + y; + })); + ASSERT(8, ({ + int x = 3, y = 5; + x + y; + })); + + ASSERT(3, ({ + int x[2]; + int *y = &x; + *y = 3; + *x; + })); + + ASSERT(3, ({ + int x[3]; + *x = 3; + *(x + 1) = 4; + *(x + 2) = 5; + *x; + })); + ASSERT(4, ({ + int x[3]; + *x = 3; + *(x + 1) = 4; + *(x + 2) = 5; + *(x + 1); + })); + ASSERT(5, ({ + int x[3]; + *x = 3; + *(x + 1) = 4; + *(x + 2) = 5; + *(x + 2); + })); + + ASSERT(0, ({ + int x[2][3]; + int *y = x; + *y = 0; + **x; + })); + ASSERT(1, ({ + int x[2][3]; + int *y = x; + *(y + 1) = 1; + *(*x + 1); + })); + ASSERT(2, ({ + int x[2][3]; + int *y = x; + *(y + 2) = 2; + *(*x + 2); + })); + ASSERT(3, ({ + int x[2][3]; + int *y = x; + *(y + 3) = 3; + **(x + 1); + })); + ASSERT(4, ({ + int x[2][3]; + int *y = x; + *(y + 4) = 4; + *(*(x + 1) + 1); + })); + ASSERT(5, ({ + int x[2][3]; + int *y = x; + *(y + 5) = 5; + *(*(x + 1) + 2); + })); + + ASSERT(3, ({ + int x[3]; + *x = 3; + x[1] = 4; + x[2] = 5; + *x; + })); + ASSERT(4, ({ + int x[3]; + *x = 3; + x[1] = 4; + x[2] = 5; + *(x + 1); + })); + ASSERT(5, ({ + int x[3]; + *x = 3; + x[1] = 4; + x[2] = 5; + *(x + 2); + })); + ASSERT(5, ({ + int x[3]; + *x = 3; + x[1] = 4; + x[2] = 5; + *(x + 2); + })); + ASSERT(5, ({ + int x[3]; + *x = 3; + x[1] = 4; + 2 [x] = 5; + *(x + 2); + })); + + ASSERT(0, ({ + int x[2][3]; + int *y = x; + y[0] = 0; + x[0][0]; + })); + ASSERT(1, ({ + int x[2][3]; + int *y = x; + y[1] = 1; + x[0][1]; + })); + ASSERT(2, ({ + int x[2][3]; + int *y = x; + y[2] = 2; + x[0][2]; + })); + ASSERT(3, ({ + int x[2][3]; + int *y = x; + y[3] = 3; + x[1][0]; + })); + ASSERT(4, ({ + int x[2][3]; + int *y = x; + y[4] = 4; + x[1][1]; + })); + ASSERT(5, ({ + int x[2][3]; + int *y = x; + y[5] = 5; + x[1][2]; + })); + + return 0; +} diff --git a/third_party/chibicc/test/pragma-once_test.c b/third_party/chibicc/test/pragma-once_test.c new file mode 100644 index 00000000..ffafb7aa --- /dev/null +++ b/third_party/chibicc/test/pragma-once_test.c @@ -0,0 +1,9 @@ +#include "third_party/chibicc/test/test.h" + +#pragma once + +#include "third_party/chibicc/test/pragma-once_test.c" + +int main() { + return 0; +} diff --git a/third_party/chibicc/test/sizeof_test.c b/third_party/chibicc/test/sizeof_test.c new file mode 100644 index 00000000..71468111 --- /dev/null +++ b/third_party/chibicc/test/sizeof_test.c @@ -0,0 +1,113 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(1, sizeof(char)); + ASSERT(2, sizeof(short)); + ASSERT(2, sizeof(short int)); + ASSERT(2, sizeof(int short)); + ASSERT(4, sizeof(int)); + ASSERT(8, sizeof(long)); + ASSERT(8, sizeof(long int)); + ASSERT(8, sizeof(long int)); + ASSERT(8, sizeof(char *)); + ASSERT(8, sizeof(int *)); + ASSERT(8, sizeof(long *)); + ASSERT(8, sizeof(int **)); + ASSERT(8, sizeof(int(*)[4])); + ASSERT(32, sizeof(int *[4])); + ASSERT(16, sizeof(int[4])); + ASSERT(48, sizeof(int[3][4])); + ASSERT(8, sizeof(struct { + int a; + int b; + })); + + ASSERT(8, sizeof(-10 + (long)5)); + ASSERT(8, sizeof(-10 - (long)5)); + ASSERT(8, sizeof(-10 * (long)5)); + ASSERT(8, sizeof(-10 / (long)5)); + ASSERT(8, sizeof((long)-10 + 5)); + ASSERT(8, sizeof((long)-10 - 5)); + ASSERT(8, sizeof((long)-10 * 5)); + ASSERT(8, sizeof((long)-10 / 5)); + + ASSERT(1, ({ + char i; + sizeof(++i); + })); + ASSERT(1, ({ + char i; + sizeof(i++); + })); + + ASSERT(8, sizeof(int(*)[10])); + ASSERT(8, sizeof(int(*)[][10])); + + ASSERT(4, sizeof(struct { int x, y[]; })); + + ASSERT(1, sizeof(char)); + ASSERT(1, sizeof(signed char)); + ASSERT(1, sizeof(signed char signed)); + ASSERT(1, sizeof(unsigned char)); + ASSERT(1, sizeof(unsigned char unsigned)); + + ASSERT(2, sizeof(short)); + ASSERT(2, sizeof(int short)); + ASSERT(2, sizeof(short int)); + ASSERT(2, sizeof(signed short)); + ASSERT(2, sizeof(int short signed)); + ASSERT(2, sizeof(unsigned short)); + ASSERT(2, sizeof(int short unsigned)); + + ASSERT(4, sizeof(int)); + ASSERT(4, sizeof(signed int)); + ASSERT(4, sizeof(signed)); + ASSERT(4, sizeof(signed signed)); + ASSERT(4, sizeof(unsigned int)); + ASSERT(4, sizeof(unsigned)); + ASSERT(4, sizeof(unsigned unsigned)); + + ASSERT(8, sizeof(long)); + ASSERT(8, sizeof(signed long)); + ASSERT(8, sizeof(signed long int)); + ASSERT(8, sizeof(unsigned long)); + ASSERT(8, sizeof(unsigned long int)); + + ASSERT(8, sizeof(long long)); + ASSERT(8, sizeof(signed long long)); + ASSERT(8, sizeof(signed long long int)); + ASSERT(8, sizeof(unsigned long long)); + ASSERT(8, sizeof(unsigned long long int)); + + ASSERT(1, sizeof((char)1)); + ASSERT(2, sizeof((short)1)); + ASSERT(4, sizeof((int)1)); + ASSERT(8, sizeof((long)1)); + + ASSERT(4, sizeof((char)1 + (char)1)); + ASSERT(4, sizeof((short)1 + (short)1)); + ASSERT(4, sizeof(1 ? 2 : 3)); + ASSERT(4, sizeof(1 ? (short)2 : (char)3)); + ASSERT(8, sizeof(1 ? (long)2 : (char)3)); + + ASSERT(1, sizeof(char) << 31 >> 31); + ASSERT(1, sizeof(char) << 63 >> 63); + + ASSERT(4, sizeof(float)); + ASSERT(8, sizeof(double)); + + ASSERT(4, sizeof(1f + 2)); + ASSERT(8, sizeof(1.0 + 2)); + ASSERT(4, sizeof(1f - 2)); + ASSERT(8, sizeof(1.0 - 2)); + ASSERT(4, sizeof(1f * 2)); + ASSERT(8, sizeof(1.0 * 2)); + ASSERT(4, sizeof(1f / 2)); + ASSERT(8, sizeof(1.0 / 2)); + + ASSERT(16, sizeof(long double)); + + ASSERT(1, sizeof(main)); + + return 0; +} diff --git a/third_party/chibicc/test/string_test.c b/third_party/chibicc/test/string_test.c new file mode 100644 index 00000000..96260d84 --- /dev/null +++ b/third_party/chibicc/test/string_test.c @@ -0,0 +1,105 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(0, ""[0]); + ASSERT(1, sizeof("")); + + ASSERT(97, "abc"[0]); + ASSERT(98, "abc"[1]); + ASSERT(99, "abc"[2]); + ASSERT(0, "abc"[3]); + ASSERT(4, sizeof("abc")); + + ASSERT(7, "\a"[0]); + ASSERT(8, "\b"[0]); + ASSERT(9, "\t"[0]); + ASSERT(10, "\n"[0]); + ASSERT(11, "\v"[0]); + ASSERT(12, "\f"[0]); + ASSERT(13, "\r"[0]); + ASSERT(27, "\e"[0]); + + ASSERT(106, "\j"[0]); + ASSERT(107, "\k"[0]); + ASSERT(108, "\l"[0]); + + ASSERT(7, "\ax\ny"[0]); + ASSERT(120, "\ax\ny"[1]); + ASSERT(10, "\ax\ny"[2]); + ASSERT(121, "\ax\ny"[3]); + + ASSERT(0, "\0"[0]); + ASSERT(16, "\20"[0]); + ASSERT(65, "\101"[0]); + ASSERT(104, "\1500"[0]); + ASSERT(0, "\x00"[0]); + ASSERT(119, "\x77"[0]); + + ASSERT(7, sizeof("abc" + "def")); + ASSERT(9, sizeof("abc" + "d" + "efgh")); + ASSERT(0, strcmp("abc" + "d" + "\nefgh", + "abcd\nefgh")); + ASSERT(0, !strcmp("abc" + "d", + "abcd\nefgh")); + ASSERT(0, strcmp("\x9" + "0", + "\t0")); + + ASSERT(16, sizeof(L"abc" + "")); + + ASSERT(28, sizeof(L"abc" + "def")); + ASSERT(28, sizeof(L"abc" + L"def")); + ASSERT(14, sizeof(u"abc" + "def")); + ASSERT(14, sizeof(u"abc" + u"def")); + + ASSERT(L'a', (L"abc" + "def")[0]); + ASSERT(L'd', (L"abc" + "def")[3]); + ASSERT(L'\0', (L"abc" + "def")[6]); + + ASSERT(u'a', (u"abc" + "def")[0]); + ASSERT(u'd', (u"abc" + "def")[3]); + ASSERT(u'\0', (u"abc" + "def")[6]); + + ASSERT(L'あ', ("あ" + L"")[0]); + ASSERT(0343, ("\343\201\202" + L"")[0]); + ASSERT(0201, ("\343\201\202" + L"")[1]); + ASSERT(0202, ("\343\201\202" + L"")[2]); + ASSERT(0, ("\343\201\202" + L"")[3]); + + ASSERT(L'a', ("a" + "b" + L"c")[0]); + ASSERT(L'b', ("a" + "b" + L"c")[1]); + ASSERT(L'c', ("a" + "b" + L"c")[2]); + ASSERT(0, ("a" + "b" + L"c")[3]); + + return 0; +} diff --git a/third_party/chibicc/test/struct_test.c b/third_party/chibicc/test/struct_test.c new file mode 100644 index 00000000..c008c01a --- /dev/null +++ b/third_party/chibicc/test/struct_test.c @@ -0,0 +1,379 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(1, ({ + struct { + int a; + int b; + } x; + x.a = 1; + x.b = 2; + x.a; + })); + ASSERT(2, ({ + struct { + int a; + int b; + } x; + x.a = 1; + x.b = 2; + x.b; + })); + ASSERT(1, ({ + struct { + char a; + int b; + char c; + } x; + x.a = 1; + x.b = 2; + x.c = 3; + x.a; + })); + ASSERT(2, ({ + struct { + char a; + int b; + char c; + } x; + x.b = 1; + x.b = 2; + x.c = 3; + x.b; + })); + ASSERT(3, ({ + struct { + char a; + int b; + char c; + } x; + x.a = 1; + x.b = 2; + x.c = 3; + x.c; + })); + + ASSERT(0, ({ + struct { + char a; + char b; + } x[3]; + char *p = x; + p[0] = 0; + x[0].a; + })); + ASSERT(1, ({ + struct { + char a; + char b; + } x[3]; + char *p = x; + p[1] = 1; + x[0].b; + })); + ASSERT(2, ({ + struct { + char a; + char b; + } x[3]; + char *p = x; + p[2] = 2; + x[1].a; + })); + ASSERT(3, ({ + struct { + char a; + char b; + } x[3]; + char *p = x; + p[3] = 3; + x[1].b; + })); + + ASSERT(6, ({ + struct { + char a[3]; + char b[5]; + } x; + char *p = &x; + x.a[0] = 6; + p[0]; + })); + ASSERT(7, ({ + struct { + char a[3]; + char b[5]; + } x; + char *p = &x; + x.b[0] = 7; + p[3]; + })); + + ASSERT(6, ({ + struct { + struct { + char b; + } a; + } x; + x.a.b = 6; + x.a.b; + })); + + ASSERT(4, ({ + struct { + int a; + } x; + sizeof(x); + })); + ASSERT(8, ({ + struct { + int a; + int b; + } x; + sizeof(x); + })); + ASSERT(8, ({ + struct { + int a, b; + } x; + sizeof(x); + })); + ASSERT(12, ({ + struct { + int a[3]; + } x; + sizeof(x); + })); + ASSERT(16, ({ + struct { + int a; + } x[4]; + sizeof(x); + })); + ASSERT(24, ({ + struct { + int a[3]; + } x[2]; + sizeof(x); + })); + ASSERT(2, ({ + struct { + char a; + char b; + } x; + sizeof(x); + })); + ASSERT(0, ({ + struct { + } x; + sizeof(x); + })); + ASSERT(8, ({ + struct { + char a; + int b; + } x; + sizeof(x); + })); + ASSERT(8, ({ + struct { + int a; + char b; + } x; + sizeof(x); + })); + + ASSERT(8, ({ + struct t { + int a; + int b; + } x; + struct t y; + sizeof(y); + })); + ASSERT(8, ({ + struct t { + int a; + int b; + }; + struct t y; + sizeof(y); + })); + ASSERT(2, ({ + struct t { + char a[2]; + }; + { + struct t { + char a[4]; + }; + } + struct t y; + sizeof(y); + })); + ASSERT(3, ({ + struct t { + int x; + }; + int t = 1; + struct t y; + y.x = 2; + t + y.x; + })); + + ASSERT(3, ({ + struct t { + char a; + } x; + struct t *y = &x; + x.a = 3; + y->a; + })); + ASSERT(3, ({ + struct t { + char a; + } x; + struct t *y = &x; + y->a = 3; + x.a; + })); + + ASSERT(3, ({ + struct { + int a, b; + } x, y; + x.a = 3; + y = x; + y.a; + })); + ASSERT(7, ({ + struct t { + int a, b; + }; + struct t x; + x.a = 7; + struct t y; + struct t *z = &y; + *z = x; + y.a; + })); + ASSERT(7, ({ + struct t { + int a, b; + }; + struct t x; + x.a = 7; + struct t y, *p = &x, *q = &y; + *q = *p; + y.a; + })); + ASSERT(5, ({ + struct t { + char a, b; + } x, y; + x.a = 5; + y = x; + y.a; + })); + + ASSERT(3, ({ + struct { + int a, b; + } x, y; + x.a = 3; + y = x; + y.a; + })); + ASSERT(7, ({ + struct t { + int a, b; + }; + struct t x; + x.a = 7; + struct t y; + struct t *z = &y; + *z = x; + y.a; + })); + ASSERT(7, ({ + struct t { + int a, b; + }; + struct t x; + x.a = 7; + struct t y, *p = &x, *q = &y; + *q = *p; + y.a; + })); + ASSERT(5, ({ + struct t { + char a, b; + } x, y; + x.a = 5; + y = x; + y.a; + })); + + ASSERT(8, ({ + struct t { + int a; + int b; + } x; + struct t y; + sizeof(y); + })); + ASSERT(8, ({ + struct t { + int a; + int b; + }; + struct t y; + sizeof(y); + })); + + ASSERT(16, ({ + struct { + char a; + long b; + } x; + sizeof(x); + })); + ASSERT(4, ({ + struct { + char a; + short b; + } x; + sizeof(x); + })); + + ASSERT(8, ({ + struct foo *bar; + sizeof(bar); + })); + ASSERT(4, ({ + struct T *foo; + struct T { + int x; + }; + sizeof(struct T); + })); + ASSERT(1, ({ + struct T { + struct T *next; + int x; + } a; + struct T b; + b.x = 1; + a.next = &b; + a.next->x; + })); + ASSERT(4, ({ + typedef struct T T; + struct T { + int x; + }; + sizeof(T); + })); + + return 0; +} diff --git a/third_party/chibicc/test/test.h b/third_party/chibicc/test/test.h new file mode 100644 index 00000000..201b2e90 --- /dev/null +++ b/third_party/chibicc/test/test.h @@ -0,0 +1,11 @@ +#include "libc/fmt/fmt.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" + +#define ASSERT(x, y) Assert2(x, y, #y, __FILE__, __LINE__) +#define ASSERT128(x, y) Assert128(x, y, #y, __FILE__, __LINE__) + +void Assert(long, long, char *); +void Assert2(long, long, char *, char *, int); +void Assert128(__int128, __int128, char *, char *, int); diff --git a/third_party/chibicc/test/test.mk b/third_party/chibicc/test/test.mk new file mode 100644 index 00000000..555cc8f2 --- /dev/null +++ b/third_party/chibicc/test/test.mk @@ -0,0 +1,100 @@ +#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ +#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ +# +# SYNOPSIS +# +# C Compiler Unit Tests +# +# OVERVIEW +# +# This makefile compiles and runs each test twice. The first with +# GCC-built chibicc, and a second time with chibicc-built chibicc + +PKGS += THIRD_PARTY_CHIBICC_TEST + +THIRD_PARTY_CHIBICC_TEST_A = o/$(MODE)/third_party/chibicc/test/test.a +THIRD_PARTY_CHIBICC_TEST2_A = o/$(MODE)/third_party/chibicc/test/test2.a +THIRD_PARTY_CHIBICC_TEST_FILES := $(wildcard third_party/chibicc/test/*) +THIRD_PARTY_CHIBICC_TEST_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_TEST_FILES)) +THIRD_PARTY_CHIBICC_TEST_SRCS_TEST = $(filter %_test.c,$(THIRD_PARTY_CHIBICC_TEST_SRCS)) +THIRD_PARTY_CHIBICC_TEST_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_TEST_FILES)) +THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok) + +THIRD_PARTY_CHIBICC_TEST_COMS = \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%.com) \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%2.com) + +THIRD_PARTY_CHIBICC_TEST_OBJS = \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS:%=o/$(MODE)/%.zip.o) \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.o) + +THIRD_PARTY_CHIBICC_TEST2_OBJS = \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS:%=o/$(MODE)/%.zip.o) \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc2.o) + +THIRD_PARTY_CHIBICC_TEST_BINS = \ + $(THIRD_PARTY_CHIBICC_TEST_COMS) \ + $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.dbg) + +THIRD_PARTY_CHIBICC_TEST_CHECKS = \ + $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.runs) \ + $(THIRD_PARTY_CHIBICC_TEST_HDRS:%=o/$(MODE)/%.ok) + +THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS = \ + LIBC_RUNTIME \ + LIBC_FMT \ + LIBC_STR \ + LIBC_STDIO \ + LIBC_STUBS \ + LIBC_NEXGEN32E \ + LIBC_UNICODE \ + LIBC_MEM \ + THIRD_PARTY_COMPILER_RT + +THIRD_PARTY_CHIBICC_TEST_DEPS := \ + $(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)))) + +$(THIRD_PARTY_CHIBICC_TEST_A): \ + third_party/chibicc/test/ \ + $(THIRD_PARTY_CHIBICC_TEST_A).pkg \ + $(THIRD_PARTY_CHIBICC_TEST_OBJS) + +$(THIRD_PARTY_CHIBICC_TEST2_A): \ + third_party/chibicc/test/ \ + $(THIRD_PARTY_CHIBICC_TEST2_A).pkg \ + $(THIRD_PARTY_CHIBICC_TEST2_OBJS) + +$(THIRD_PARTY_CHIBICC_TEST_A).pkg: \ + $(THIRD_PARTY_CHIBICC_TEST_OBJS) \ + $(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg) + +$(THIRD_PARTY_CHIBICC_TEST2_A).pkg: \ + $(THIRD_PARTY_CHIBICC_TEST2_OBJS) \ + $(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg) + +o/$(MODE)/third_party/chibicc/test/%.com.dbg: \ + $(THIRD_PARTY_CHIBICC_TEST_DEPS) \ + $(THIRD_PARTY_CHIBICC_TEST_A) \ + o/$(MODE)/third_party/chibicc/test/%.chibicc.o \ + $(THIRD_PARTY_CHIBICC_TEST_A).pkg \ + $(LIBC_TESTMAIN) \ + $(CRT) \ + $(APE) + @$(APELINK) + +o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \ + $(THIRD_PARTY_CHIBICC_TEST_DEPS) \ + $(THIRD_PARTY_CHIBICC_TEST2_A) \ + o/$(MODE)/third_party/chibicc/test/%.chibicc2.o \ + $(THIRD_PARTY_CHIBICC_TEST2_A).pkg \ + $(LIBC_TESTMAIN) \ + $(CRT) \ + $(APE) + @$(APELINK) + +.PHONY: o/$(MODE)/third_party/chibicc/test +o/$(MODE)/third_party/chibicc/test: \ + $(THIRD_PARTY_CHIBICC_TEST_BINS) \ + $(THIRD_PARTY_CHIBICC_TEST_CHECKS) \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.s) \ + $(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc2.s) diff --git a/third_party/chibicc/test/tls_test.c.todo b/third_party/chibicc/test/tls_test.c.todo new file mode 100644 index 00000000..e5a73e83 --- /dev/null +++ b/third_party/chibicc/test/tls_test.c.todo @@ -0,0 +1,18 @@ +#include "third_party/chibicc/test/test.h" + +_Thread_local int x; + +void add(void) { + x += 3; +} + +_Noreturn int test(void) { + x = 7; + add(); + ASSERT(10, x); + exit(0); +} + +int main(void) { + test(); +} diff --git a/third_party/chibicc/test/typedef_test.c b/third_party/chibicc/test/typedef_test.c new file mode 100644 index 00000000..188b98a4 --- /dev/null +++ b/third_party/chibicc/test/typedef_test.c @@ -0,0 +1,49 @@ +#include "third_party/chibicc/test/test.h" + +typedef int MyInt, MyInt2[4]; +typedef int; + +int main() { + ASSERT(1, ({ + typedef int t; + t x = 1; + x; + })); + ASSERT(1, ({ + typedef struct { + int a; + } t; + t x; + x.a = 1; + x.a; + })); + ASSERT(1, ({ + typedef int t; + t t = 1; + t; + })); + ASSERT(2, ({ + typedef struct { + int a; + } t; + { typedef int t; } + t x; + x.a = 2; + x.a; + })); + ASSERT(4, ({ + typedef t; + t x; + sizeof(x); + })); + ASSERT(3, ({ + MyInt x = 3; + x; + })); + ASSERT(16, ({ + MyInt2 x; + sizeof(x); + })); + + return 0; +} diff --git a/third_party/chibicc/test/typeof_test.c b/third_party/chibicc/test/typeof_test.c new file mode 100644 index 00000000..4e5bded1 --- /dev/null +++ b/third_party/chibicc/test/typeof_test.c @@ -0,0 +1,29 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(3, ({ + typeof(int) x = 3; + x; + })); + ASSERT(3, ({ + typeof(1) x = 3; + x; + })); + ASSERT(4, ({ + int x; + typeof(x) y; + sizeof(y); + })); + ASSERT(8, ({ + int x; + typeof(&x) y; + sizeof(y); + })); + ASSERT(4, ({ + typeof("foo") x; + sizeof(x); + })); + ASSERT(12, sizeof(typeof(struct { int a, b, c; }))); + + return 0; +} diff --git a/third_party/chibicc/test/unicode_test.c b/third_party/chibicc/test/unicode_test.c new file mode 100644 index 00000000..6da17d9f --- /dev/null +++ b/third_party/chibicc/test/unicode_test.c @@ -0,0 +1,138 @@ +#include "third_party/chibicc/test/test.h" + +/* TODO(jart): shl overflow in read_escaped_char */ + +#define STR(x) #x + +typedef unsigned short char16_t; +typedef unsigned int char32_t; +typedef int wchar_t; + +int π = 3; + +int main() { + ASSERT(4, sizeof(L'\0')); + ASSERT(97, L'a'); + + ASSERT(0, strcmp("αβγ", "\u03B1\u03B2\u03B3")); + ASSERT(0, strcmp("日本語", "\u65E5\u672C\u8A9E")); + ASSERT(0, strcmp("日本語", "\U000065E5\U0000672C\U00008A9E")); + ASSERT(0, strcmp("🌮", "\U0001F32E")); + + ASSERT(-1, L'\xffffffff' >> 31); + ASSERT(946, L'β'); + ASSERT(12354, L'あ'); + ASSERT(127843, L'🍣'); + + ASSERT(2, sizeof(u'\0')); + ASSERT(1, u'\xffff' >> 15); + ASSERT(97, u'a'); + ASSERT(946, u'β'); + ASSERT(12354, u'あ'); + ASSERT(62307, u'🍣'); + + ASSERT(0, strcmp(STR(u'a'), "u'a'")); + + ASSERT(4, sizeof(U'\0')); + ASSERT(1, U'\xffffffff' >> 31); + ASSERT(97, U'a'); + ASSERT(946, U'β'); + ASSERT(12354, U'あ'); + ASSERT(127843, U'🍣'); + + ASSERT(0, strcmp(STR(U'a'), "U'a'")); + + ASSERT(4, sizeof(u8"abc")); + ASSERT(0, strcmp(u8"abc", "abc")); + + ASSERT(0, strcmp(STR(u8"a"), "u8\"a\"")); + + ASSERT(2, sizeof(u"")); + ASSERT(10, sizeof(u"\xffzzz")); + ASSERT(0, memcmp(u"", "\0\0", 2)); + ASSERT(0, memcmp(u"abc", "a\0b\0c\0\0\0", 8)); + ASSERT(0, memcmp(u"日本語", "\345e,g\236\212\0\0", 8)); + ASSERT(0, memcmp(u"🍣", "<\330c\337\0\0", 6)); + ASSERT(u'β', u"βb"[0]); + ASSERT(u'b', u"βb"[1]); + ASSERT(0, u"βb"[2]); + + ASSERT(0, strcmp(STR(u"a"), "u\"a\"")); + + ASSERT(4, sizeof(U"")); + ASSERT(20, sizeof(U"\xffzzz")); + ASSERT(0, memcmp(U"", "\0\0\0\0", 4)); + ASSERT(0, memcmp(U"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16)); + ASSERT(0, memcmp(U"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16)); + ASSERT(0, memcmp(U"🍣", "c\363\001\0\0\0\0\0", 8)); + ASSERT(u'β', U"βb"[0]); + ASSERT(u'b', U"βb"[1]); + ASSERT(0, U"βb"[2]); + ASSERT(1, U"\xffffffff"[0] >> 31); + + ASSERT(0, strcmp(STR(U"a"), "U\"a\"")); + + ASSERT(4, sizeof(L"")); + ASSERT(20, sizeof(L"\xffzzz")); + ASSERT(0, memcmp(L"", "\0\0\0\0", 4)); + ASSERT(0, memcmp(L"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16)); + ASSERT(0, memcmp(L"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16)); + ASSERT(0, memcmp(L"🍣", "c\363\001\0\0\0\0\0", 8)); + ASSERT(u'β', L"βb"[0]); + ASSERT(u'b', L"βb"[1]); + ASSERT(0, L"βb"[2]); + ASSERT(-1, L"\xffffffff"[0] >> 31); + + ASSERT(0, strcmp(STR(L"a"), "L\"a\"")); + + ASSERT(u'α', ({ + char16_t x[] = u"αβ"; + x[0]; + })); + ASSERT(u'β', ({ + char16_t x[] = u"αβ"; + x[1]; + })); + ASSERT(6, ({ + char16_t x[] = u"αβ"; + sizeof(x); + })); + + ASSERT(U'🤔', ({ + char32_t x[] = U"🤔x"; + x[0]; + })); + ASSERT(U'x', ({ + char32_t x[] = U"🤔x"; + x[1]; + })); + ASSERT(12, ({ + char32_t x[] = U"🤔x"; + sizeof(x); + })); + + ASSERT(L'🤔', ({ + wchar_t x[] = L"🤔x"; + x[0]; + })); + ASSERT(L'x', ({ + wchar_t x[] = L"🤔x"; + x[1]; + })); + ASSERT(12, ({ + wchar_t x[] = L"🤔x"; + sizeof(x); + })); + + ASSERT(3, π); + ASSERT(3, ({ + int あβ0¾ = 3; + あβ0¾; + })); + ASSERT(5, ({ + int $$$ = 5; + $$$; + })); + + return 0; +} diff --git a/third_party/chibicc/test/union_test.c b/third_party/chibicc/test/union_test.c new file mode 100644 index 00000000..8f91f778 --- /dev/null +++ b/third_party/chibicc/test/union_test.c @@ -0,0 +1,132 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(8, ({ + union { + int a; + char b[6]; + } x; + sizeof(x); + })); + ASSERT(3, ({ + union { + int a; + char b[4]; + } x; + x.a = 515; + x.b[0]; + })); + ASSERT(2, ({ + union { + int a; + char b[4]; + } x; + x.a = 515; + x.b[1]; + })); + ASSERT(0, ({ + union { + int a; + char b[4]; + } x; + x.a = 515; + x.b[2]; + })); + ASSERT(0, ({ + union { + int a; + char b[4]; + } x; + x.a = 515; + x.b[3]; + })); + + ASSERT(3, ({ + union { + int a, b; + } x, y; + x.a = 3; + y.a = 5; + y = x; + y.a; + })); + ASSERT(3, ({ + union { + struct { + int a, b; + } c; + } x, y; + x.c.b = 3; + y.c.b = 5; + y = x; + y.c.b; + })); + + ASSERT(0xef, ({ + union { + struct { + unsigned char a, b, c, d; + }; + long e; + } x; + x.e = 0xdeadbeef; + x.a; + })); + ASSERT(0xbe, ({ + union { + struct { + unsigned char a, b, c, d; + }; + long e; + } x; + x.e = 0xdeadbeef; + x.b; + })); + ASSERT(0xad, ({ + union { + struct { + unsigned char a, b, c, d; + }; + long e; + } x; + x.e = 0xdeadbeef; + x.c; + })); + ASSERT(0xde, ({ + union { + struct { + unsigned char a, b, c, d; + }; + long e; + } x; + x.e = 0xdeadbeef; + x.d; + })); + + ASSERT(3, ({ + struct { + union { + int a, b; + }; + union { + int c, d; + }; + } x; + x.a = 3; + x.b; + })); + ASSERT(5, ({ + struct { + union { + int a, b; + }; + union { + int c, d; + }; + } x; + x.d = 5; + x.c; + })); + + return 0; +} diff --git a/third_party/chibicc/test/usualconv_test.c b/third_party/chibicc/test/usualconv_test.c new file mode 100644 index 00000000..a9185bd2 --- /dev/null +++ b/third_party/chibicc/test/usualconv_test.c @@ -0,0 +1,58 @@ +#include "third_party/chibicc/test/test.h" + +static int ret10(void) { + return 10; +} + +int main() { + ASSERT((long)-5, -10 + (long)5); + ASSERT((long)-15, -10 - (long)5); + ASSERT((long)-50, -10 * (long)5); + ASSERT((long)-2, -10 / (long)5); + + ASSERT(1, -2 < (long)-1); + ASSERT(1, -2 <= (long)-1); + ASSERT(0, -2 > (long)-1); + ASSERT(0, -2 >= (long)-1); + + ASSERT(1, (long)-2 < -1); + ASSERT(1, (long)-2 <= -1); + ASSERT(0, (long)-2 > -1); + ASSERT(0, (long)-2 >= -1); + + ASSERT(0, 2147483647 + 2147483647 + 2); + ASSERT((long)-1, ({ + long x; + x = -1; + x; + })); + + ASSERT(1, ({ + char x[3]; + x[0] = 0; + x[1] = 1; + x[2] = 2; + char *y = x + 1; + y[0]; + })); + ASSERT(0, ({ + char x[3]; + x[0] = 0; + x[1] = 1; + x[2] = 2; + char *y = x + 1; + y[-1]; + })); + ASSERT(5, ({ + struct t { + char a; + } x, y; + x.a = 5; + y = x; + y.a; + })); + + ASSERT(10, (1 ? ret10 : (void *)0)()); + + return 0; +} diff --git a/third_party/chibicc/test/varargs_test.c b/third_party/chibicc/test/varargs_test.c new file mode 100644 index 00000000..1007c5bc --- /dev/null +++ b/third_party/chibicc/test/varargs_test.c @@ -0,0 +1,52 @@ +#include "third_party/chibicc/test/test.h" + +int sum1(int x, ...) { + va_list ap; + va_start(ap, x); + + for (;;) { + int y = va_arg(ap, int); + if (y == 0) return x; + x += y; + } +} + +int sum2(int x, ...) { + va_list ap; + va_start(ap, x); + + for (;;) { + double y = va_arg(ap, double); + x += y; + + int z = va_arg(ap, int); + if (z == 0) return x; + x += z; + } +} + +void fmt(char *buf, char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + + va_list ap2; + va_copy(ap2, ap); + vsprintf(buf, fmt, ap2); + va_end(buf); +} + +int main() { + ASSERT(6, sum1(1, 2, 3, 0)); + ASSERT(55, sum1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0)); + ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0)); + ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0)); + ASSERT(210, sum2(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, + 15, 16.0, 17, 18.0, 19, 20.0, 0)); + ASSERT(0, ({ + char buf[100]; + fmt(buf, "%d %d", 2, 3); + strcmp(buf, "2 3"); + })); + + return 0; +} diff --git a/third_party/chibicc/test/variable_test.c b/third_party/chibicc/test/variable_test.c new file mode 100644 index 00000000..b5081f03 --- /dev/null +++ b/third_party/chibicc/test/variable_test.c @@ -0,0 +1,244 @@ +#include "third_party/chibicc/test/test.h" + +int g1, g2[4]; +static int g3 = 3; + +int main() { + ASSERT(3, ({ + int a; + a = 3; + a; + })); + ASSERT(3, ({ + int a = 3; + a; + })); + ASSERT(8, ({ + int a = 3; + int z = 5; + a + z; + })); + + ASSERT(3, ({ + int a = 3; + a; + })); + ASSERT(8, ({ + int a = 3; + int z = 5; + a + z; + })); + ASSERT(6, ({ + int a; + int b; + a = b = 3; + a + b; + })); + ASSERT(3, ({ + int foo = 3; + foo; + })); + ASSERT(8, ({ + int foo123 = 3; + int bar = 5; + foo123 + bar; + })); + + ASSERT(4, ({ + int x; + sizeof(x); + })); + ASSERT(4, ({ + int x; + sizeof x; + })); + ASSERT(8, ({ + int *x; + sizeof(x); + })); + ASSERT(16, ({ + int x[4]; + sizeof(x); + })); + ASSERT(48, ({ + int x[3][4]; + sizeof(x); + })); + ASSERT(16, ({ + int x[3][4]; + sizeof(*x); + })); + ASSERT(4, ({ + int x[3][4]; + sizeof(**x); + })); + ASSERT(5, ({ + int x[3][4]; + sizeof(**x) + 1; + })); + ASSERT(5, ({ + int x[3][4]; + sizeof **x + 1; + })); + ASSERT(4, ({ + int x[3][4]; + sizeof(**x + 1); + })); + ASSERT(4, ({ + int x = 1; + sizeof(x = 2); + })); + ASSERT(1, ({ + int x = 1; + sizeof(x = 2); + x; + })); + + ASSERT(0, g1); + ASSERT(3, ({ + g1 = 3; + g1; + })); + ASSERT(0, ({ + g2[0] = 0; + g2[1] = 1; + g2[2] = 2; + g2[3] = 3; + g2[0]; + })); + ASSERT(1, ({ + g2[0] = 0; + g2[1] = 1; + g2[2] = 2; + g2[3] = 3; + g2[1]; + })); + ASSERT(2, ({ + g2[0] = 0; + g2[1] = 1; + g2[2] = 2; + g2[3] = 3; + g2[2]; + })); + ASSERT(3, ({ + g2[0] = 0; + g2[1] = 1; + g2[2] = 2; + g2[3] = 3; + g2[3]; + })); + + ASSERT(4, sizeof(g1)); + ASSERT(16, sizeof(g2)); + + ASSERT(1, ({ + char x = 1; + x; + })); + ASSERT(1, ({ + char x = 1; + char y = 2; + x; + })); + ASSERT(2, ({ + char x = 1; + char y = 2; + y; + })); + + ASSERT(1, ({ + char x; + sizeof(x); + })); + ASSERT(10, ({ + char x[10]; + sizeof(x); + })); + + ASSERT(2, ({ + int x = 2; + { int x = 3; } + x; + })); + ASSERT(2, ({ + int x = 2; + { int x = 3; } + int y = 4; + x; + })); + ASSERT(3, ({ + int x = 2; + { x = 3; } + x; + })); + + ASSERT(7, ({ + int x; + int y; + char z; + char *a = &y; + char *b = &z; + b - a; + })); + ASSERT(1, ({ + int x; + char y; + int z; + char *a = &y; + char *b = &z; + b - a; + })); + + ASSERT(8, ({ + long x; + sizeof(x); + })); + ASSERT(2, ({ + short x; + sizeof(x); + })); + + ASSERT(24, ({ + char *x[3]; + sizeof(x); + })); + ASSERT(8, ({ + char(*x)[3]; + sizeof(x); + })); + ASSERT(1, ({ + char(x); + sizeof(x); + })); + ASSERT(3, ({ + char(x)[3]; + sizeof(x); + })); + ASSERT(12, ({ + char(x[3])[4]; + sizeof(x); + })); + ASSERT(4, ({ + char(x[3])[4]; + sizeof(x[0]); + })); + ASSERT(3, ({ + char *x[3]; + char y; + x[0] = &y; + y = 3; + x[0][0]; + })); + ASSERT(4, ({ + char x[3]; + char(*y)[3] = x; + y[0][0] = 4; + y[0][0]; + })); + + { void *x; } + + ASSERT(3, g3); + + return 0; +} diff --git a/third_party/chibicc/test/vector_test.c b/third_party/chibicc/test/vector_test.c new file mode 100644 index 00000000..a09b88cd --- /dev/null +++ b/third_party/chibicc/test/vector_test.c @@ -0,0 +1,56 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or 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. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/chibicc/test/test.h" + +typedef float float4 __attribute__((__vector_size__(16))); +typedef float float4a1 __attribute__((__vector_size__(16), __aligned__(1))); +typedef float float4a16 __attribute__((__vector_size__(16), __aligned__(16))); +typedef double double2 __attribute__((__vector_size__(16))); +typedef double double2a1 __attribute__((__vector_size__(16), __aligned__(1))); +typedef double double2a16 __attribute__((__vector_size__(16), __aligned__(16))); + +int main(void) { + ASSERT(16, sizeof(float4)); + ASSERT(16, sizeof(float4a1)); + ASSERT(16, sizeof(float4a16)); + ASSERT(16, sizeof(double2)); + ASSERT(16, sizeof(double2a1)); + ASSERT(16, sizeof(double2a16)); + ASSERT(16, _Alignof(float4)); + ASSERT(1, _Alignof(float4a1)); + ASSERT(16, _Alignof(float4a16)); + ASSERT(16, _Alignof(double2)); + ASSERT(1, _Alignof(double2a1)); + ASSERT(16, _Alignof(double2a16)); + + float4 v1; + float4 v2; + float x[4] = {1, 2, 3, 4}; + float y[4] = {1, 1, 1, 1}; + memcpy(&v1, x, 16); + memcpy(&v2, y, 16); + v1 = v1 + v2; + memcpy(x, &v1, 16); + ASSERT(2, x[0]); + /* ASSERT(3, x[1]); */ + /* ASSERT(4, x[2]); */ + /* ASSERT(5, x[3]); */ + + return 0; +} diff --git a/third_party/chibicc/test/vla_test.c b/third_party/chibicc/test/vla_test.c new file mode 100644 index 00000000..7f98e1ca --- /dev/null +++ b/third_party/chibicc/test/vla_test.c @@ -0,0 +1,86 @@ +#include "third_party/chibicc/test/test.h" + +int main() { + ASSERT(20, ({ + int n = 5; + int x[n]; + sizeof(x); + })); + ASSERT((5 + 1) * (8 * 2) * 4, ({ + int m = 5, n = 8; + int x[m + 1][n * 2]; + sizeof(x); + })); + + ASSERT(8, ({ + char n = 10; + int(*x)[n][n + 2]; + sizeof(x); + })); + ASSERT(480, ({ + char n = 10; + int(*x)[n][n + 2]; + sizeof(*x); + })); + ASSERT(48, ({ + char n = 10; + int(*x)[n][n + 2]; + sizeof(**x); + })); + ASSERT(4, ({ + char n = 10; + int(*x)[n][n + 2]; + sizeof(***x); + })); + + ASSERT(60, ({ + char n = 3; + int x[5][n]; + sizeof(x); + })); + ASSERT(12, ({ + char n = 3; + int x[5][n]; + sizeof(*x); + })); + + ASSERT(60, ({ + char n = 3; + int x[n][5]; + sizeof(x); + })); + ASSERT(20, ({ + char n = 3; + int x[n][5]; + sizeof(*x); + })); + + ASSERT(0, ({ + int n = 10; + int x[n + 1][n + 6]; + int *p = x; + for (int i = 0; i < sizeof(x) / 4; i++) p[i] = i; + x[0][0]; + })); + ASSERT(5, ({ + int n = 10; + int x[n + 1][n + 6]; + int *p = x; + for (int i = 0; i < sizeof(x) / 4; i++) p[i] = i; + x[0][5]; + })); + ASSERT(5 * 16 + 2, ({ + int n = 10; + int x[n + 1][n + 6]; + int *p = x; + for (int i = 0; i < sizeof(x) / 4; i++) p[i] = i; + x[5][2]; + })); + + ASSERT(10, ({ + int n = 5; + sizeof(char[2][n]); + })); + + return 0; +} diff --git a/third_party/chibicc/tokenize.c b/third_party/chibicc/tokenize.c index bfb3f4ea..eb673630 100644 --- a/third_party/chibicc/tokenize.c +++ b/third_party/chibicc/tokenize.c @@ -1,5 +1,7 @@ #include "third_party/chibicc/chibicc.h" +#define LOOKINGAT(TOK, OP) lookingat(TOK, OP, strlen(OP)) + // Input file static File *current_file; @@ -30,17 +32,13 @@ static void verror_at(char *filename, char *input, int line_no, char *loc, // Find a line containing `loc`. char *line = loc; while (input < line && line[-1] != '\n') line--; - char *end = loc; while (*end && *end != '\n') end++; - // Print out the line. int indent = fprintf(stderr, "%s:%d: ", filename, line_no); fprintf(stderr, "%.*s\n", (int)(end - line), line); - // Show the error message. int pos = str_width(line, loc - line) + indent; - fprintf(stderr, "%*s", pos, ""); // print pos spaces. fprintf(stderr, "^ "); vfprintf(stderr, fmt, ap); @@ -49,9 +47,9 @@ static void verror_at(char *filename, char *input, int line_no, char *loc, void error_at(char *loc, char *fmt, ...) { int line_no = 1; - for (char *p = current_file->contents; p < loc; p++) + for (char *p = current_file->contents; p < loc; p++) { if (*p == '\n') line_no++; - + } va_list ap; va_start(ap, fmt); verror_at(current_file->name, current_file->contents, line_no, loc, fmt, ap); @@ -59,10 +57,14 @@ void error_at(char *loc, char *fmt, ...) { } void error_tok(Token *tok, char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, - ap); + va_list ap, va; + va_start(va, fmt); + for (Token *t = tok; t; t = t->origin) { + va_copy(ap, va); + verror_at(t->file->name, t->file->contents, t->line_no, t->loc, fmt, ap); + va_end(ap); + } + va_end(va); exit(1); } @@ -73,19 +75,29 @@ void warn_tok(Token *tok, char *fmt, ...) { ap); } +forceinline int compare_strings(const char *a, const char *b, size_t n) { + size_t i = 0; + if (!n-- || a == b) return 0; + while (a[i] == b[i] && b[i] && i < n) ++i; + return (a[i] & 0xff) - (b[i] & 0xff); +} + +static int is_space(int c) { + return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || + c == '\v'; +} + +static bool lookingat(const char *a, const char *b, size_t n) { + return !compare_strings(a, b, n); +} + // Consumes the current token if it matches `op`. -bool equal(Token *tok, char *op) { - return strlen(op) == tok->len && !strncmp(tok->loc, op, tok->len); +bool equal(Token *tok, char *op, size_t n) { + return n == tok->len && !compare_strings(tok->loc, op, tok->len); } -// Ensure that the current token is `op`. -Token *skip(Token *tok, char *op) { - if (!equal(tok, op)) error_tok(tok, "expected '%s'", op); - return tok->next; -} - -bool consume(Token **rest, Token *tok, char *str) { - if (equal(tok, str)) { +bool consume(Token **rest, Token *tok, char *str, size_t n) { + if (n == tok->len && !compare_strings(tok->loc, str, n)) { *rest = tok->next; return true; } @@ -93,6 +105,12 @@ bool consume(Token **rest, Token *tok, char *str) { return false; } +// Ensure that the current token is `op`. +Token *skip(Token *tok, char *op) { + if (!EQUAL(tok, op)) error_tok(tok, "expected '%s'", op); + return tok->next; +} + // Create a new token and add it as the next token of `cur`. static Token *new_token(TokenKind kind, char *start, char *end) { Token *tok = calloc(1, sizeof(Token)); @@ -103,15 +121,10 @@ static Token *new_token(TokenKind kind, char *start, char *end) { tok->filename = current_file->display_name; tok->at_bol = at_bol; tok->has_space = has_space; - at_bol = has_space = false; return tok; } -static bool starts_with(char *p, char *q) { - return strncmp(p, q, strlen(q)) == 0; -} - // Read an identifier and returns a pointer pointing to the end // of an identifier. // @@ -119,11 +132,12 @@ static bool starts_with(char *p, char *q) { static char *read_ident(char *p) { uint32_t c = decode_utf8(&p, p); if (!is_ident1(c)) return NULL; - for (;;) { char *q; c = decode_utf8(&q, p); - if (!is_ident2(c)) return p; + if (!('a' <= c && c <= 'f') && !is_ident2(c)) { + return p; + } p = q; } } @@ -136,7 +150,6 @@ static int from_hex(char c) { static bool is_keyword(Token *tok) { static HashMap map; - if (map.capacity == 0) { static char *kw[] = { "return", "if", "else", @@ -155,18 +168,17 @@ static bool is_keyword(Token *tok) { "typeof", "asm", "_Thread_local", "__thread", "_Atomic", "__attribute__", }; - - for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) + for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { hashmap_put(&map, kw[i], (void *)1); + } } - return hashmap_get2(&map, tok->loc, tok->len); } static int read_escaped_char(char **new_pos, char *p) { if ('0' <= *p && *p <= '7') { // Read an octal number. - int c = *p++ - '0'; + unsigned c = *p++ - '0'; if ('0' <= *p && *p <= '7') { c = (c << 3) + (*p++ - '0'); if ('0' <= *p && *p <= '7') c = (c << 3) + (*p++ - '0'); @@ -174,20 +186,18 @@ static int read_escaped_char(char **new_pos, char *p) { *new_pos = p; return c; } - if (*p == 'x') { // Read a hexadecimal number. p++; if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence"); - - int c = 0; - for (; isxdigit(*p); p++) c = (c << 4) + from_hex(*p); + unsigned c = 0; + for (; isxdigit(*p); p++) { + c = (c << 4) + from_hex(*p); /* TODO(jart): overflow here unicode_test */ + } *new_pos = p; return c; } - *new_pos = p + 1; - switch (*p) { case 'a': return '\a'; @@ -225,14 +235,12 @@ static Token *read_string_literal(char *start, char *quote) { char *end = string_literal_end(quote + 1); char *buf = calloc(1, end - quote); int len = 0; - for (char *p = quote + 1; p < end;) { if (*p == '\\') buf[len++] = read_escaped_char(&p, p + 1); else buf[len++] = *p++; } - Token *tok = new_token(TK_STR, start, end + 1); tok->ty = array_of(ty_char, len + 1); tok->str = buf; @@ -250,13 +258,11 @@ static Token *read_utf16_string_literal(char *start, char *quote) { char *end = string_literal_end(quote + 1); uint16_t *buf = calloc(2, end - start - 1); int len = 0; - for (char *p = quote + 1; p < end;) { if (*p == '\\') { buf[len++] = read_escaped_char(&p, p + 1); continue; } - uint32_t c = decode_utf8(&p, p); if (c < 0x10000) { // Encode a code point in 2 bytes. @@ -268,7 +274,6 @@ static Token *read_utf16_string_literal(char *start, char *quote) { buf[len++] = 0xdc00 + (c & 0x3ff); } } - Token *tok = new_token(TK_STR, start, end + 1); tok->ty = array_of(ty_ushort, len + 1); tok->str = (char *)buf; @@ -283,14 +288,12 @@ static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) { char *end = string_literal_end(quote + 1); uint32_t *buf = calloc(4, end - quote); int len = 0; - for (char *p = quote + 1; p < end;) { if (*p == '\\') buf[len++] = read_escaped_char(&p, p + 1); else buf[len++] = decode_utf8(&p, p); } - Token *tok = new_token(TK_STR, start, end + 1); tok->ty = array_of(ty, len + 1); tok->str = (char *)buf; @@ -300,16 +303,13 @@ static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) { static Token *read_char_literal(char *start, char *quote, Type *ty) { char *p = quote + 1; if (*p == '\0') error_at(start, "unclosed char literal"); - int c; if (*p == '\\') c = read_escaped_char(&p, p + 1); else c = decode_utf8(&p, p); - char *end = strchr(p, '\''); if (!end) error_at(p, "unclosed char literal"); - Token *tok = new_token(TK_NUM, start, end + 1); tok->val = c; tok->ty = ty; @@ -318,7 +318,6 @@ static Token *read_char_literal(char *start, char *quote, Type *ty) { static bool convert_pp_int(Token *tok) { char *p = tok->loc; - // Read a binary, octal, decimal or hexadecimal number. int base = 10; if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) { @@ -330,22 +329,19 @@ static bool convert_pp_int(Token *tok) { } else if (*p == '0') { base = 8; } - int64_t val = strtoul(p, &p, base); - // Read U, L or LL suffixes. bool l = false; bool u = false; - - if (starts_with(p, "LLU") || starts_with(p, "LLu") || starts_with(p, "llU") || - starts_with(p, "llu") || starts_with(p, "ULL") || starts_with(p, "Ull") || - starts_with(p, "uLL") || starts_with(p, "ull")) { + if (LOOKINGAT(p, "LLU") || LOOKINGAT(p, "LLu") || LOOKINGAT(p, "llU") || + LOOKINGAT(p, "llu") || LOOKINGAT(p, "ULL") || LOOKINGAT(p, "Ull") || + LOOKINGAT(p, "uLL") || LOOKINGAT(p, "ull")) { p += 3; l = u = true; } else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) { p += 2; l = u = true; - } else if (starts_with(p, "LL") || starts_with(p, "ll")) { + } else if (LOOKINGAT(p, "LL") || LOOKINGAT(p, "ll")) { p += 2; l = true; } else if (*p == 'L' || *p == 'l') { @@ -355,9 +351,7 @@ static bool convert_pp_int(Token *tok) { p++; u = true; } - if (p != tok->loc + tok->len) return false; - // Infer a type. Type *ty; if (base == 10) { @@ -385,7 +379,6 @@ static bool convert_pp_int(Token *tok) { else ty = ty_int; } - tok->kind = TK_NUM; tok->val = val; tok->ty = ty; @@ -402,11 +395,9 @@ static bool convert_pp_int(Token *tok) { static void convert_pp_number(Token *tok) { // Try to parse as an integer constant. if (convert_pp_int(tok)) return; - // If it's not an integer, it must be a floating point constant. char *end; long double val = strtold(tok->loc, &end); - Type *ty; if (*end == 'f' || *end == 'F') { ty = ty_float; @@ -417,9 +408,7 @@ static void convert_pp_number(Token *tok) { } else { ty = ty_double; } - if (tok->loc + tok->len != end) error_tok(tok, "invalid numeric constant"); - tok->kind = TK_NUM; tok->fval = val; tok->ty = ty; @@ -438,7 +427,6 @@ void convert_pp_tokens(Token *tok) { static void add_line_numbers(Token *tok) { char *p = current_file->contents; int n = 1; - do { if (p == tok->loc) { tok->line_no = n; @@ -461,32 +449,27 @@ Token *tokenize_string_literal(Token *tok, Type *basety) { // Tokenize a given string and returns new tokens. Token *tokenize(File *file) { current_file = file; - char *p = file->contents; Token head = {}; Token *cur = &head; - at_bol = true; has_space = false; - while (*p) { // Skip line comments. - if (starts_with(p, "//")) { + if (LOOKINGAT(p, "//")) { p += 2; while (*p != '\n') p++; has_space = true; continue; } - // Skip block comments. - if (starts_with(p, "/*")) { + if (LOOKINGAT(p, "/*")) { char *q = strstr(p + 2, "*/"); if (!q) error_at(p, "unclosed block comment"); p = q + 2; has_space = true; continue; } - // Skip newline. if (*p == '\n') { p++; @@ -494,14 +477,12 @@ Token *tokenize(File *file) { has_space = false; continue; } - // Skip whitespace characters. - if (isspace(*p)) { + if (is_space(*p)) { p++; has_space = true; continue; } - // Numeric literal if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) { char *q = p++; @@ -516,42 +497,36 @@ Token *tokenize(File *file) { cur = cur->next = new_token(TK_PP_NUM, q, p); continue; } - // String literal if (*p == '"') { cur = cur->next = read_string_literal(p, p); p += cur->len; continue; } - // UTF-8 string literal - if (starts_with(p, "u8\"")) { + if (LOOKINGAT(p, "u8\"")) { cur = cur->next = read_string_literal(p, p + 2); p += cur->len; continue; } - // UTF-16 string literal - if (starts_with(p, "u\"")) { + if (LOOKINGAT(p, "u\"")) { cur = cur->next = read_utf16_string_literal(p, p + 1); p += cur->len; continue; } - // Wide string literal - if (starts_with(p, "L\"")) { + if (LOOKINGAT(p, "L\"")) { cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int); p += cur->len; continue; } - // UTF-32 string literal - if (starts_with(p, "U\"")) { + if (LOOKINGAT(p, "U\"")) { cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint); p += cur->len; continue; } - // Character literal if (*p == '\'') { cur = cur->next = read_char_literal(p, p, ty_int); @@ -559,29 +534,25 @@ Token *tokenize(File *file) { p += cur->len; continue; } - // UTF-16 character literal - if (starts_with(p, "u'")) { + if (LOOKINGAT(p, "u'")) { cur = cur->next = read_char_literal(p, p + 1, ty_ushort); cur->val &= 0xffff; p += cur->len; continue; } - // Wide character literal - if (starts_with(p, "L'")) { + if (LOOKINGAT(p, "L'")) { cur = cur->next = read_char_literal(p, p + 1, ty_int); p += cur->len; continue; } - // UTF-32 character literal - if (starts_with(p, "U'")) { + if (LOOKINGAT(p, "U'")) { cur = cur->next = read_char_literal(p, p + 1, ty_uint); p += cur->len; continue; } - // Identifier or keyword char *q; if ((q = read_ident(p)) != NULL) { @@ -589,38 +560,32 @@ Token *tokenize(File *file) { p = q; continue; } - // Three-letter punctuators - if (starts_with(p, "<<=") || starts_with(p, ">>=") || - starts_with(p, "...")) { + if (LOOKINGAT(p, "<<=") || LOOKINGAT(p, ">>=") || LOOKINGAT(p, "...")) { cur = cur->next = new_token(TK_RESERVED, p, p + 3); p += 3; continue; } - // Two-letter punctuators - if (starts_with(p, "==") || starts_with(p, "!=") || starts_with(p, "<=") || - starts_with(p, ">=") || starts_with(p, "->") || starts_with(p, "+=") || - starts_with(p, "-=") || starts_with(p, "*=") || starts_with(p, "/=") || - starts_with(p, "++") || starts_with(p, "--") || starts_with(p, "%=") || - starts_with(p, "&=") || starts_with(p, "|=") || starts_with(p, "^=") || - starts_with(p, "&&") || starts_with(p, "||") || starts_with(p, "<<") || - starts_with(p, ">>") || starts_with(p, "##")) { + if (LOOKINGAT(p, "==") || LOOKINGAT(p, "!=") || LOOKINGAT(p, "<=") || + LOOKINGAT(p, ">=") || LOOKINGAT(p, "->") || LOOKINGAT(p, "+=") || + LOOKINGAT(p, "-=") || LOOKINGAT(p, "*=") || LOOKINGAT(p, "/=") || + LOOKINGAT(p, "++") || LOOKINGAT(p, "--") || LOOKINGAT(p, "%=") || + LOOKINGAT(p, "&=") || LOOKINGAT(p, "|=") || LOOKINGAT(p, "^=") || + LOOKINGAT(p, "&&") || LOOKINGAT(p, "||") || LOOKINGAT(p, "<<") || + LOOKINGAT(p, ">>") || LOOKINGAT(p, "##")) { cur = cur->next = new_token(TK_RESERVED, p, p + 2); p += 2; continue; } - // Single-letter punctuators if (ispunct(*p)) { cur = cur->next = new_token(TK_RESERVED, p, p + 1); p++; continue; } - error_at(p, "invalid token"); } - cur = cur->next = new_token(TK_EOF, p, p); add_line_numbers(head.next); return head.next; @@ -629,7 +594,6 @@ Token *tokenize(File *file) { // Returns the contents of a given file. static char *read_file(char *path) { FILE *fp; - if (strcmp(path, "-") == 0) { // By convention, read from stdin if a given filename is "-". fp = stdin; @@ -637,11 +601,9 @@ static char *read_file(char *path) { fp = fopen(path, "r"); if (!fp) return NULL; } - int buflen = 4096; int nread = 0; char *buf = calloc(1, buflen); - // Read the entire file. for (;;) { int end = buflen - 2; // extra 2 bytes for the trailing "\n\0" @@ -653,15 +615,12 @@ static char *read_file(char *path) { buf = realloc(buf, buflen); } } - if (fp != stdin) fclose(fp); - // Make sure that the last logical line is properly terminated with '\n'. if (nread > 0 && buf[nread - 1] == '\\') buf[nread - 1] = '\n'; else if (nread == 0 || buf[nread - 1] != '\n') buf[nread++] = '\n'; - buf[nread] = '\0'; return buf; } @@ -682,7 +641,6 @@ File *new_file(char *name, int file_no, char *contents) { // Replaces \r or \r\n with \n. static void canonicalize_newline(char *p) { int i = 0, j = 0; - while (p[i]) { if (p[i] == '\r' && p[i + 1] == '\n') { i += 2; @@ -694,19 +652,16 @@ static void canonicalize_newline(char *p) { p[j++] = p[i++]; } } - p[j] = '\0'; } // Removes backslashes followed by a newline. static void remove_backslash_newline(char *p) { int i = 0, j = 0; - // We want to keep the number of newline characters so that // the logical line number matches the physical one. // This counter maintain the number of newlines we have removed. int n = 0; - while (p[i]) { if (p[i] == '\\' && p[i + 1] == '\n') { i += 2; @@ -718,7 +673,6 @@ static void remove_backslash_newline(char *p) { p[j++] = p[i++]; } } - p[j] = '\0'; } @@ -734,9 +688,8 @@ static uint32_t read_universal_char(char *p, int len) { // Replace \u or \U escape sequences with corresponding UTF-8 bytes. static void convert_universal_chars(char *p) { char *q = p; - while (*p) { - if (starts_with(p, "\\u")) { + if (LOOKINGAT(p, "\\u")) { uint32_t c = read_universal_char(p + 2, 4); if (c) { p += 6; @@ -744,7 +697,7 @@ static void convert_universal_chars(char *p) { } else { *q++ = *p++; } - } else if (starts_with(p, "\\U")) { + } else if (LOOKINGAT(p, "\\U")) { uint32_t c = read_universal_char(p + 2, 8); if (c) { p += 10; @@ -759,27 +712,22 @@ static void convert_universal_chars(char *p) { *q++ = *p++; } } - *q = '\0'; } Token *tokenize_file(char *path) { char *p = read_file(path); if (!p) return NULL; - canonicalize_newline(p); remove_backslash_newline(p); convert_universal_chars(p); - // Save the filename for assembler .file directive. static int file_no; File *file = new_file(path, file_no + 1, p); - // Save the filename for assembler .file directive. input_files = realloc(input_files, sizeof(char *) * (file_no + 2)); input_files[file_no] = file; input_files[file_no + 1] = NULL; file_no++; - return tokenize(file); } diff --git a/third_party/chibicc/type.c b/third_party/chibicc/type.c index df8e3497..fa119e4e 100644 --- a/third_party/chibicc/type.c +++ b/third_party/chibicc/type.c @@ -1,21 +1,21 @@ #include "third_party/chibicc/chibicc.h" -Type *ty_void = &(Type){TY_VOID, 1, 1}; -Type *ty_bool = &(Type){TY_BOOL, 1, 1}; - -Type *ty_char = &(Type){TY_CHAR, 1, 1}; -Type *ty_short = &(Type){TY_SHORT, 2, 2}; -Type *ty_int = &(Type){TY_INT, 4, 4}; -Type *ty_long = &(Type){TY_LONG, 8, 8}; - -Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true}; -Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true}; -Type *ty_uint = &(Type){TY_INT, 4, 4, true}; -Type *ty_ulong = &(Type){TY_LONG, 8, 8, true}; - -Type *ty_float = &(Type){TY_FLOAT, 4, 4}; -Type *ty_double = &(Type){TY_DOUBLE, 8, 8}; -Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16}; +/* TODO(jart): Why can't these be const? */ +Type ty_void[1] = {{TY_VOID, 1, 1}}; +Type ty_bool[1] = {{TY_BOOL, 1, 1}}; +Type ty_char[1] = {{TY_CHAR, 1, 1}}; +Type ty_short[1] = {{TY_SHORT, 2, 2}}; +Type ty_int[1] = {{TY_INT, 4, 4}}; +Type ty_long[1] = {{TY_LONG, 8, 8}}; +Type ty_int128[1] = {{TY_INT128, 16, 16}}; +Type ty_uchar[1] = {{TY_CHAR, 1, 1, true}}; +Type ty_ushort[1] = {{TY_SHORT, 2, 2, true}}; +Type ty_uint[1] = {{TY_INT, 4, 4, true}}; +Type ty_ulong[1] = {{TY_LONG, 8, 8, true}}; +Type ty_uint128[1] = {{TY_INT128, 16, 16, true}}; +Type ty_float[1] = {{TY_FLOAT, 4, 4}}; +Type ty_double[1] = {{TY_DOUBLE, 8, 8}}; +Type ty_ldouble[1] = {{TY_LDOUBLE, 16, 16}}; static Type *new_type(TypeKind kind, int size, int align) { Type *ty = calloc(1, sizeof(Type)); @@ -28,7 +28,7 @@ static Type *new_type(TypeKind kind, int size, int align) { bool is_integer(Type *ty) { TypeKind k = ty->kind; return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT || k == TY_INT || - k == TY_LONG || k == TY_ENUM; + k == TY_LONG || k == TY_INT128 || k == TY_ENUM; } bool is_flonum(Type *ty) { @@ -42,18 +42,15 @@ bool is_numeric(Type *ty) { bool is_compatible(Type *t1, Type *t2) { if (t1 == t2) return true; - if (t1->origin) return is_compatible(t1->origin, t2); - if (t2->origin) return is_compatible(t1, t2->origin); - if (t1->kind != t2->kind) return false; - switch (t1->kind) { case TY_CHAR: case TY_SHORT: case TY_INT: case TY_LONG: + case TY_INT128: return t1->is_unsigned == t2->is_unsigned; case TY_FLOAT: case TY_DOUBLE: @@ -64,11 +61,11 @@ bool is_compatible(Type *t1, Type *t2) { case TY_FUNC: { if (!is_compatible(t1->return_ty, t2->return_ty)) return false; if (t1->is_variadic != t2->is_variadic) return false; - Type *p1 = t1->params; Type *p2 = t2->params; - for (; p1 && p2; p1 = p1->next, p2 = p2->next) + for (; p1 && p2; p1 = p1->next, p2 = p2->next) { if (!is_compatible(p1, p2)) return false; + } return p1 == NULL && p2 == NULL; } case TY_ARRAY: @@ -125,19 +122,14 @@ Type *struct_type(void) { static Type *get_common_type(Type *ty1, Type *ty2) { if (ty1->base) return pointer_to(ty1->base); - if (ty1->kind == TY_FUNC) return pointer_to(ty1); if (ty2->kind == TY_FUNC) return pointer_to(ty2); - if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE) return ty_ldouble; if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE) return ty_double; if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT) return ty_float; - if (ty1->size < 4) ty1 = ty_int; if (ty2->size < 4) ty2 = ty_int; - if (ty1->size != ty2->size) return (ty1->size < ty2->size) ? ty2 : ty1; - if (ty2->is_unsigned) return ty2; return ty1; } @@ -157,7 +149,6 @@ static void usual_arith_conv(Node **lhs, Node **rhs) { void add_type(Node *node) { if (!node || node->ty) return; - add_type(node->lhs); add_type(node->rhs); add_type(node->cond); @@ -165,10 +156,8 @@ void add_type(Node *node) { add_type(node->els); add_type(node->init); add_type(node->inc); - for (Node *n = node->body; n; n = n->next) add_type(n); for (Node *n = node->args; n; n = n->next) add_type(n); - switch (node->kind) { case ND_NUM: node->ty = ty_int; @@ -192,7 +181,7 @@ void add_type(Node *node) { } case ND_ASSIGN: if (node->lhs->ty->kind == TY_ARRAY) - error_tok(node->lhs->tok, "not an lvalue"); + error_tok(node->lhs->tok, "not an lvalue!"); if (node->lhs->ty->kind != TY_STRUCT) node->rhs = new_cast(node->rhs, node->lhs->ty); node->ty = node->lhs->ty; @@ -244,12 +233,20 @@ void add_type(Node *node) { return; } case ND_DEREF: +#if 0 + if (node->lhs->ty->size == 16 && (node->lhs->ty->kind == TY_FLOAT || + node->lhs->ty->kind == TY_DOUBLE)) { + node->ty = node->lhs->ty; + } else { +#endif if (!node->lhs->ty->base) error_tok(node->tok, "invalid pointer dereference"); if (node->lhs->ty->base->kind == TY_VOID) error_tok(node->tok, "dereferencing a void pointer"); - node->ty = node->lhs->ty->base; +#if 0 + } +#endif return; case ND_STMT_EXPR: if (node->body) { @@ -271,7 +268,6 @@ void add_type(Node *node) { add_type(node->cas_old); add_type(node->cas_new); node->ty = ty_bool; - if (node->cas_addr->ty->kind != TY_PTR) error_tok(node->cas_addr->tok, "pointer expected"); if (node->cas_old->ty->kind != TY_PTR) diff --git a/third_party/chibicc/unicode.c b/third_party/chibicc/unicode.c index da87caf7..64d1dcab 100644 --- a/third_party/chibicc/unicode.c +++ b/third_party/chibicc/unicode.c @@ -6,20 +6,17 @@ int encode_utf8(char *buf, uint32_t c) { buf[0] = c; return 1; } - if (c <= 0x7FF) { buf[0] = 0b11000000 | (c >> 6); buf[1] = 0b10000000 | (c & 0b00111111); return 2; } - if (c <= 0xFFFF) { buf[0] = 0b11100000 | (c >> 12); buf[1] = 0b10000000 | ((c >> 6) & 0b00111111); buf[2] = 0b10000000 | (c & 0b00111111); return 3; } - buf[0] = 0b11110000 | (c >> 18); buf[1] = 0b10000000 | ((c >> 12) & 0b00111111); buf[2] = 0b10000000 | ((c >> 6) & 0b00111111); @@ -39,11 +36,9 @@ uint32_t decode_utf8(char **new_pos, char *p) { *new_pos = p + 1; return *p; } - char *start = p; int len; uint32_t c; - if ((unsigned char)*p >= 0b11110000) { len = 4; c = *p & 0b111; @@ -56,13 +51,11 @@ uint32_t decode_utf8(char **new_pos, char *p) { } else { error_at(start, "invalid UTF-8 sequence"); } - for (int i = 1; i < len; i++) { if ((unsigned char)p[i] >> 6 != 0b10) error_at(start, "invalid UTF-8 sequence"); c = (c << 6) | (p[i] & 0b111111); } - *new_pos = p + len; return c; } @@ -85,7 +78,7 @@ static bool in_range(uint32_t *range, uint32_t c) { // (U+3000, full-width space) are allowed because they are out of range. bool is_ident1(uint32_t c) { static uint32_t range[] = { - '_', '_', 'a', 'z', 'A', 'Z', '$', '$', + 'a', 'z', 'A', 'Z', '_', '_', '$', '$', 0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF, 0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6, 0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F, @@ -100,7 +93,6 @@ bool is_ident1(uint32_t c) { 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD, -1, }; - return in_range(range, c); } @@ -111,68 +103,9 @@ bool is_ident2(uint32_t c) { '0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0, 0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F, -1, }; - return is_ident1(c) || in_range(range, c); } -// Returns the number of columns needed to display a given -// character in a fixed-width font. -// -// Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c -static int char_width(uint32_t c) { - static uint32_t range1[] = { - 0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486, - 0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2, - 0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615, - 0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8, - 0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A, - 0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C, - 0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963, - 0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD, - 0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42, - 0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82, - 0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD, - 0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F, - 0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82, - 0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48, - 0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF, - 0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43, - 0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6, - 0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1, - 0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19, - 0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E, - 0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC, - 0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037, - 0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F, - 0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773, - 0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3, - 0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922, - 0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18, - 0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C, - 0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF, - 0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F, - 0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806, - 0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F, - 0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03, - 0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F, - 0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD, - 0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF, - -1, - }; - - if (in_range(range1, c)) return 0; - - static uint32_t range2[] = { - 0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E, - 0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19, - 0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644, - 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1, - }; - - if (in_range(range2, c)) return 2; - return 1; -} - // Returns the number of columns needed to display a given // string in a fixed-width font. int str_width(char *p, int len) { @@ -180,7 +113,7 @@ int str_width(char *p, int len) { int w = 0; while (p - start < len) { uint32_t c = decode_utf8(&p, p); - w += char_width(c); + w += wcwidth(c); } return w; } diff --git a/third_party/compiler_rt/int_util.h b/third_party/compiler_rt/int_util.h index 73e99dac..69d301a1 100644 --- a/third_party/compiler_rt/int_util.h +++ b/third_party/compiler_rt/int_util.h @@ -26,7 +26,7 @@ /* #define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__) */ -noreturn void __compilerrt_abort_impl(const char *file, int line, +wontreturn void __compilerrt_abort_impl(const char *file, int line, const char *function); #define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__) diff --git a/third_party/dlmalloc/dlmalloc.c b/third_party/dlmalloc/dlmalloc.c index db428e4a..d5aa10d9 100644 --- a/third_party/dlmalloc/dlmalloc.c +++ b/third_party/dlmalloc/dlmalloc.c @@ -34,7 +34,7 @@ struct MallocParams g_mparams; * Note that contiguous allocations are what Doug Lea recommends. */ static void *dlmalloc_requires_more_vespene_gas(size_t size) { - if (0 && !IsTrustworthy()) { + if (0) { size_t need = mallinfo().arena + size; if (need > 8 * 1024 * 1024) { struct sysinfo info; diff --git a/third_party/dtoa/dtoa.c b/third_party/dtoa/dtoa.c deleted file mode 100644 index 8d72df56..00000000 --- a/third_party/dtoa/dtoa.c +++ /dev/null @@ -1,5848 +0,0 @@ -#include "libc/bits/pushpop.h" -#include "libc/calls/calls.h" -#include "libc/limits.h" -#include "libc/math.h" -#include "libc/runtime/runtime.h" -#include "libc/str/str.h" -#include "third_party/dtoa/dtoa.h" - -#define Omit_Private_Memory - -#define IEEE_8087 1 -/* #define SET_INEXACT 1 */ - -#if __NO_MATH_ERRNO__ + 0 -#define NO_ERRNO 1 -#endif - -#if __FINITE_MATH_ONLY__ + 0 -#define NO_INFNAN_CHECK 1 -#endif - -asm(".ident\t\"\\n\\n\ -dtoa (MIT License)\\n\ -The author of this software is David M. Gay.\\n\ -Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\""); -asm(".include \"libc/disclaimer.inc\""); - -/**************************************************************** - * - * The author of this software is David M. Gay. - * - * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - * - ***************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -/* On a machine with IEEE extended-precision registers, it is - * necessary to specify double-precision (53-bit) rounding precision - * before invoking strtod or dtoa. If the machine uses (the equivalent - * of) Intel 80x87 arithmetic, the call - * _control87(PC_53, MCW_PC); - * does this with many compilers. Whether this or another call is - * appropriate depends on the compiler; for this to work, it may be - * necessary to #include "float.h" or another system-dependent header - * file. - */ - -/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. - * (Note that IEEE arithmetic is disabled by gcc's -ffast-math flag.) - * - * This strtod returns a nearest machine number to the input decimal - * string (or sets errno to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). - * - * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * - * 1. We only require IEEE, IBM, or VAX double-precision - * arithmetic (not IEEE double-extended). - * 2. We get by with floating-point arithmetic in a case that - * Clinger missed -- when we're computing d * 10^n - * for a small integer d and the integer n is not too - * much larger than 22 (the maximum integer k for which - * we can represent 10^k exactly), we may be able to - * compute (d*10^k) * 10^(e-k) with just one roundoff. - * 3. Rather than a bit-at-a-time adjustment of the binary - * result in the hard case, we use floating-point - * arithmetic to determine the adjustment to within - * one bit; only in really hard cases do we need to - * compute a second residual. - * 4. Because of 3., we don't need a large table of powers of 10 - * for ten-to-e (just some small tables, e.g. of 10^k - * for 0 <= k <= 22). - */ - -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define Long int on machines with 32-bit ints and 64-bit longs. - * #define IBM for IBM mainframe-style floating-point arithmetic. - * #define VAX for VAX-style floating-point arithmetic (D_floating). - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. This will cause dtoa modes 4 and 5 to be - * treated the same as modes 2 and 3 for some inputs. - * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS - * is also #defined, fegetround() will be queried for the rounding mode. - * Note that both FLT_ROUNDS and fegetround() are specified by the C99 - * standard (and are specified to be consistent, with fesetround() - * affecting the value of FLT_ROUNDS), but that some (Linux) systems - * do not work correctly in this regard, so using fegetround() is more - * portable than using FLT_ROUNDS directly. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and Honor_FLT_ROUNDS is not #defined. - * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines - * that use extended-precision instructions to compute rounded - * products and quotients) with IBM. - * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic - * that rounds toward +Infinity. - * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased - * rounding when the underlying floating-point arithmetic uses - * unbiased rounding. This prevent using ordinary floating-point - * arithmetic when the result could be computed with one rounding error. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define NO_LONG_LONG on machines that do not have a "long long" - * integer type (of >= 64 bits). On such machines, you can - * #define Just_16 to store 16 bits per 32-bit Long when doing - * high-precision integer arithmetic. Whether this speeds things - * up or slows things down depends on the machine and the number - * being converted. If long long is available and the name is - * something other than "long long", #define Llong to be the name, - * and if "unsigned Llong" does not work as an unsigned version of - * Llong, #define #ULLong to be the corresponding unsigned type. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) - * if memory is available and otherwise does something you deem - * appropriate. If MALLOC is undefined, malloc will be invoked - * directly -- and assumed always to succeed. Similarly, if you - * want something other than the system's free() to be called to - * recycle memory acquired from MALLOC, #define FREE to be the - * name of the alternate routine. (FREE or free is only called in - * pathological cases, e.g., in a dtoa call after a dtoa return in - * mode 3 with thousands of digits requested.) - * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making - * memory allocations from a private pool of memory when possible. - * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, - * unless #defined to be a different length. This default length - * suffices to get rid of MALLOC calls except for unusual cases, - * such as decimal-to-binary conversion of a very long string of - * digits. The longest string dtoa can return is about 751 bytes - * long. For conversions by strtod of strings of 800 digits and - * all dtoa conversions in single-threaded executions with 8-byte - * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte - * pointers, PRIVATE_MEM >= 7112 appears adequate. - * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK - * #defined automatically on IEEE systems. On such systems, - * when INFNAN_CHECK is #defined, strtod checks - * for Infinity and NaN (case insensitively). On some systems - * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 - * appropriately -- to the most significant word of a quiet NaN. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) - * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, - * strtod also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits and spaces; - * if there is only one string of hexadecimal digits, it is taken - * for the 52 fraction bits of the resulting NaN; if there are two - * or more strings of hex digits, the first is for the high 20 bits, - * the second and subsequent for the low 32 bits, with intervening - * white space ignored; but if this results in none of the 52 - * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 - * and NAN_WORD1 are used instead. - * #define MULTIPLE_THREADS if the system offers preemptively scheduled - * multiple threads. In this case, you must provide (or suitably - * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed - * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed - * in dtoa_pow5mult, ensures lazy evaluation of only one copy of high - * powers of 5; omitting this lock would introduce a small - * probability of wasting memory, but would otherwise be harmless.) - * You must also invoke freedtoa(s) to free the value s returned by - * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. - - * When MULTIPLE_THREADS is #defined, this source file provides - * void set_max_dtoa_threads(unsigned int n); - * and expects - * unsigned int dtoa_get_threadno(void); - * to be available (possibly provided by - * #define dtoa_get_threadno omp_get_thread_num - * if OpenMP is in use or by - * #define dtoa_get_threadno pthread_self - * if Pthreads is in use), to return the current thread number. - * If set_max_dtoa_threads(n) was called and the current thread - * number is k with k < n, then calls on ACQUIRE_DTOA_LOCK(...) and - * FREE_DTOA_LOCK(...) are avoided; instead each thread with thread - * number < n has a separate copy of relevant data structures. - * After set_max_dtoa_threads(n), a call set_max_dtoa_threads(m) - * with m <= n has has no effect, but a call with m > n is honored. - * Such a call invokes REALLOC (assumed to be "realloc" if REALLOC - * is not #defined) to extend the size of the relevant array. - - * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that - * avoids underflows on inputs whose result does not underflow. - * If you #define NO_IEEE_Scale on a machine that uses IEEE-format - * floating-point numbers and flushes underflows to zero rather - * than implementing gradual underflow, then you must also #define - * Sudden_Underflow. - * #define USE_LOCALE to use the current locale's decimal_point value. - * #define SET_INEXACT if IEEE arithmetic is being used and extra - * computation should be done to set the inexact flag when the - * result is inexact and avoid setting inexact when the result - * is exact. In this case, dtoa.c must be compiled in - * an environment, perhaps provided by #include "dtoa.c" in a - * suitable wrapper, that defines two functions, - * int get_inexact(void); - * void clear_inexact(void); - * such that get_inexact() returns a nonzero value if the - * inexact bit is already set, and clear_inexact() sets the - * inexact bit to 0. When SET_INEXACT is #defined, strtod - * also does extra computations to set the underflow and overflow - * flags when appropriate (i.e., when the result is tiny and - * inexact or when it is a numeric value rounded to +-infinity). - * #define NO_ERRNO if strtod should not assign errno = ERANGE when - * the result overflows to +-Infinity or underflows to 0. - * When errno should be assigned, under seemingly rare conditions - * it may be necessary to define Set_errno(x) suitably, e.g., in - * a local errno.h, such as - * #include - * #define Set_errno(x) _set_errno(x) - * #define NO_HEX_FP to omit recognition of hexadecimal floating-point - * values by strtod. - * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now) - * to disable logic for "fast" testing of very long input strings - * to strtod. This testing proceeds by initially truncating the - * input string, then if necessary comparing the whole string with - * a decimal expansion to decide close cases. This logic is only - * used for input more than STRTOD_DIGLIM digits long (default 40). - */ - -#ifndef Long -#define Long int -#endif -#ifndef ULong -typedef unsigned Long ULong; -#endif - -#ifdef DEBUG -#include "libc/assert.h" -#define Bug(x) \ - { \ - dprintf(STDERR_FILENO, "%s\n", x); \ - exit(1); \ - } -#define Debug(x) x -int dtoa_stats - [7]; /* strtod_{64,96,dtoa_bigcomp},dtoa_{exact,64,96,dtoa_bigcomp} - */ -#else -#define assert(x) /*nothing*/ -#define Debug(x) /*nothing*/ -#endif - -#include "libc/mem/mem.h" -#include "libc/str/str.h" -#include "libc/sysv/errfuns.h" - -#ifdef Honor_FLT_ROUNDS -#ifndef Trust_FLT_ROUNDS -#include "libc/math.h" -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif -#ifdef MALLOC -extern void *MALLOC(size_t); -#else -#define MALLOC malloc -#endif - -#ifdef REALLOC -extern void *REALLOC(void *, size_t); -#else -#define REALLOC realloc -#endif - -#ifndef FREE -#define FREE free -#endif - -#ifdef __cplusplus -} -#endif - -#ifndef Omit_Private_Memory -#ifndef PRIVATE_MEM -#define PRIVATE_MEM 2304 -#endif -#define PRIVATE_mem ((PRIVATE_MEM + sizeof(double) - 1) / sizeof(double)) -static double private_mem[PRIVATE_mem], *pmem_next = private_mem; -#endif - -#undef IEEE_Arith -#undef Avoid_Underflow -#ifdef IEEE_MC68k -#define IEEE_Arith -#endif -#ifdef IEEE_8087 -#define IEEE_Arith -#endif - -#ifdef IEEE_Arith -#ifndef NO_INFNAN_CHECK -#undef INFNAN_CHECK -#define INFNAN_CHECK -#endif -#else -#undef INFNAN_CHECK -#define NO_STRTOD_BIGCOMP -#endif - -#include "libc/errno.h" - -#ifdef NO_ERRNO /*{*/ -#undef Set_errno -#define Set_errno(x) -#else -#ifndef Set_errno -#define Set_errno(x) x() -#endif -#endif /*}*/ - -#ifdef Bad_float_h - -#ifdef IEEE_Arith -#define DBL_DIG 15 -#define DBL_MAX_10_EXP 308 -#define DBL_MAX_EXP 1024 -#define FLT_RADIX 2 -#endif /*IEEE_Arith*/ - -#ifdef IBM -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 75 -#define DBL_MAX_EXP 63 -#define FLT_RADIX 16 -#define DBL_MAX 7.2370055773322621e+75 -#endif - -#ifdef VAX -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 38 -#define DBL_MAX_EXP 127 -#define FLT_RADIX 2 -#define DBL_MAX 1.7014118346046923e+38 -#endif - -#ifndef LONG_MAX -#define LONG_MAX 2147483647 -#endif - -#else /* ifndef Bad_float_h */ -#include "libc/math.h" -#endif /* Bad_float_h */ - -#ifndef __MATH_H__ -#include "libc/math.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 -Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. -#endif - -#undef USE_BF96 - -#ifdef NO_LONG_LONG /*{{*/ -#undef ULLong -#ifdef Just_16 -#undef Pack_32 -/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per Long. - */ -#endif -#else /*}{ long long available */ -#ifndef Llong -#define Llong long long -#endif -#ifndef ULLong -#define ULLong unsigned Llong -#endif -#ifndef NO_BF96 /*{*/ -#define USE_BF96 - -#ifdef SET_INEXACT -#define dtoa_divmax 27 -#else -/* Permit experimenting: on some systems, 64-bit integer */ -/* division is slow enough that we may sometimes want to */ -/* avoid using it. We assume (but do not check) that */ -/* dtoa_divmax <= 27.*/ -extern int dtoa_divmax; -#endif - -typedef struct BF96 { /* Normalized 96-bit software floating point numbers */ - unsigned int b0, b1, - b2; /* b0 = most significant, binary point just to its left */ - int e; /* number represented = b * 2^e, with .5 <= b < 1 */ -} BF96; - -static const BF96 kDtoaPten[667] = {{0xeef453d6, 0x923bd65a, 0x113faa29, -1136}, - {0x9558b466, 0x1b6565f8, 0x4ac7ca59, -1132}, - {0xbaaee17f, 0xa23ebf76, 0x5d79bcf0, -1129}, - {0xe95a99df, 0x8ace6f53, 0xf4d82c2c, -1126}, - {0x91d8a02b, 0xb6c10594, 0x79071b9b, -1122}, - {0xb64ec836, 0xa47146f9, 0x9748e282, -1119}, - {0xe3e27a44, 0x4d8d98b7, 0xfd1b1b23, -1116}, - {0x8e6d8c6a, 0xb0787f72, 0xfe30f0f5, -1112}, - {0xb208ef85, 0x5c969f4f, 0xbdbd2d33, -1109}, - {0xde8b2b66, 0xb3bc4723, 0xad2c7880, -1106}, - {0x8b16fb20, 0x3055ac76, 0x4c3bcb50, -1102}, - {0xaddcb9e8, 0x3c6b1793, 0xdf4abe24, -1099}, - {0xd953e862, 0x4b85dd78, 0xd71d6dad, -1096}, - {0x87d4713d, 0x6f33aa6b, 0x8672648c, -1092}, - {0xa9c98d8c, 0xcb009506, 0x680efdaf, -1089}, - {0xd43bf0ef, 0xfdc0ba48, 0x0212bd1b, -1086}, - {0x84a57695, 0xfe98746d, 0x014bb630, -1082}, - {0xa5ced43b, 0x7e3e9188, 0x419ea3bd, -1079}, - {0xcf42894a, 0x5dce35ea, 0x52064cac, -1076}, - {0x818995ce, 0x7aa0e1b2, 0x7343efeb, -1072}, - {0xa1ebfb42, 0x19491a1f, 0x1014ebe6, -1069}, - {0xca66fa12, 0x9f9b60a6, 0xd41a26e0, -1066}, - {0xfd00b897, 0x478238d0, 0x8920b098, -1063}, - {0x9e20735e, 0x8cb16382, 0x55b46e5f, -1059}, - {0xc5a89036, 0x2fddbc62, 0xeb2189f7, -1056}, - {0xf712b443, 0xbbd52b7b, 0xa5e9ec75, -1053}, - {0x9a6bb0aa, 0x55653b2d, 0x47b233c9, -1049}, - {0xc1069cd4, 0xeabe89f8, 0x999ec0bb, -1046}, - {0xf148440a, 0x256e2c76, 0xc00670ea, -1043}, - {0x96cd2a86, 0x5764dbca, 0x38040692, -1039}, - {0xbc807527, 0xed3e12bc, 0xc6050837, -1036}, - {0xeba09271, 0xe88d976b, 0xf7864a44, -1033}, - {0x93445b87, 0x31587ea3, 0x7ab3ee6a, -1029}, - {0xb8157268, 0xfdae9e4c, 0x5960ea05, -1026}, - {0xe61acf03, 0x3d1a45df, 0x6fb92487, -1023}, - {0x8fd0c162, 0x06306bab, 0xa5d3b6d4, -1019}, - {0xb3c4f1ba, 0x87bc8696, 0x8f48a489, -1016}, - {0xe0b62e29, 0x29aba83c, 0x331acdab, -1013}, - {0x8c71dcd9, 0xba0b4925, 0x9ff0c08b, -1009}, - {0xaf8e5410, 0x288e1b6f, 0x07ecf0ae, -1006}, - {0xdb71e914, 0x32b1a24a, 0xc9e82cd9, -1003}, - {0x892731ac, 0x9faf056e, 0xbe311c08, -999}, - {0xab70fe17, 0xc79ac6ca, 0x6dbd630a, -996}, - {0xd64d3d9d, 0xb981787d, 0x092cbbcc, -993}, - {0x85f04682, 0x93f0eb4e, 0x25bbf560, -989}, - {0xa76c5823, 0x38ed2621, 0xaf2af2b8, -986}, - {0xd1476e2c, 0x07286faa, 0x1af5af66, -983}, - {0x82cca4db, 0x847945ca, 0x50d98d9f, -979}, - {0xa37fce12, 0x6597973c, 0xe50ff107, -976}, - {0xcc5fc196, 0xfefd7d0c, 0x1e53ed49, -973}, - {0xff77b1fc, 0xbebcdc4f, 0x25e8e89c, -970}, - {0x9faacf3d, 0xf73609b1, 0x77b19161, -966}, - {0xc795830d, 0x75038c1d, 0xd59df5b9, -963}, - {0xf97ae3d0, 0xd2446f25, 0x4b057328, -960}, - {0x9becce62, 0x836ac577, 0x4ee367f9, -956}, - {0xc2e801fb, 0x244576d5, 0x229c41f7, -953}, - {0xf3a20279, 0xed56d48a, 0x6b435275, -950}, - {0x9845418c, 0x345644d6, 0x830a1389, -946}, - {0xbe5691ef, 0x416bd60c, 0x23cc986b, -943}, - {0xedec366b, 0x11c6cb8f, 0x2cbfbe86, -940}, - {0x94b3a202, 0xeb1c3f39, 0x7bf7d714, -936}, - {0xb9e08a83, 0xa5e34f07, 0xdaf5ccd9, -933}, - {0xe858ad24, 0x8f5c22c9, 0xd1b3400f, -930}, - {0x91376c36, 0xd99995be, 0x23100809, -926}, - {0xb5854744, 0x8ffffb2d, 0xabd40a0c, -923}, - {0xe2e69915, 0xb3fff9f9, 0x16c90c8f, -920}, - {0x8dd01fad, 0x907ffc3b, 0xae3da7d9, -916}, - {0xb1442798, 0xf49ffb4a, 0x99cd11cf, -913}, - {0xdd95317f, 0x31c7fa1d, 0x40405643, -910}, - {0x8a7d3eef, 0x7f1cfc52, 0x482835ea, -906}, - {0xad1c8eab, 0x5ee43b66, 0xda324365, -903}, - {0xd863b256, 0x369d4a40, 0x90bed43e, -900}, - {0x873e4f75, 0xe2224e68, 0x5a7744a6, -896}, - {0xa90de353, 0x5aaae202, 0x711515d0, -893}, - {0xd3515c28, 0x31559a83, 0x0d5a5b44, -890}, - {0x8412d999, 0x1ed58091, 0xe858790a, -886}, - {0xa5178fff, 0x668ae0b6, 0x626e974d, -883}, - {0xce5d73ff, 0x402d98e3, 0xfb0a3d21, -880}, - {0x80fa687f, 0x881c7f8e, 0x7ce66634, -876}, - {0xa139029f, 0x6a239f72, 0x1c1fffc1, -873}, - {0xc9874347, 0x44ac874e, 0xa327ffb2, -870}, - {0xfbe91419, 0x15d7a922, 0x4bf1ff9f, -867}, - {0x9d71ac8f, 0xada6c9b5, 0x6f773fc3, -863}, - {0xc4ce17b3, 0x99107c22, 0xcb550fb4, -860}, - {0xf6019da0, 0x7f549b2b, 0x7e2a53a1, -857}, - {0x99c10284, 0x4f94e0fb, 0x2eda7444, -853}, - {0xc0314325, 0x637a1939, 0xfa911155, -850}, - {0xf03d93ee, 0xbc589f88, 0x793555ab, -847}, - {0x96267c75, 0x35b763b5, 0x4bc1558b, -843}, - {0xbbb01b92, 0x83253ca2, 0x9eb1aaed, -840}, - {0xea9c2277, 0x23ee8bcb, 0x465e15a9, -837}, - {0x92a1958a, 0x7675175f, 0x0bfacd89, -833}, - {0xb749faed, 0x14125d36, 0xcef980ec, -830}, - {0xe51c79a8, 0x5916f484, 0x82b7e127, -827}, - {0x8f31cc09, 0x37ae58d2, 0xd1b2ecb8, -823}, - {0xb2fe3f0b, 0x8599ef07, 0x861fa7e6, -820}, - {0xdfbdcece, 0x67006ac9, 0x67a791e0, -817}, - {0x8bd6a141, 0x006042bd, 0xe0c8bb2c, -813}, - {0xaecc4991, 0x4078536d, 0x58fae9f7, -810}, - {0xda7f5bf5, 0x90966848, 0xaf39a475, -807}, - {0x888f9979, 0x7a5e012d, 0x6d8406c9, -803}, - {0xaab37fd7, 0xd8f58178, 0xc8e5087b, -800}, - {0xd5605fcd, 0xcf32e1d6, 0xfb1e4a9a, -797}, - {0x855c3be0, 0xa17fcd26, 0x5cf2eea0, -793}, - {0xa6b34ad8, 0xc9dfc06f, 0xf42faa48, -790}, - {0xd0601d8e, 0xfc57b08b, 0xf13b94da, -787}, - {0x823c1279, 0x5db6ce57, 0x76c53d08, -783}, - {0xa2cb1717, 0xb52481ed, 0x54768c4b, -780}, - {0xcb7ddcdd, 0xa26da268, 0xa9942f5d, -777}, - {0xfe5d5415, 0x0b090b02, 0xd3f93b35, -774}, - {0x9efa548d, 0x26e5a6e1, 0xc47bc501, -770}, - {0xc6b8e9b0, 0x709f109a, 0x359ab641, -767}, - {0xf867241c, 0x8cc6d4c0, 0xc30163d2, -764}, - {0x9b407691, 0xd7fc44f8, 0x79e0de63, -760}, - {0xc2109436, 0x4dfb5636, 0x985915fc, -757}, - {0xf294b943, 0xe17a2bc4, 0x3e6f5b7b, -754}, - {0x979cf3ca, 0x6cec5b5a, 0xa705992c, -750}, - {0xbd8430bd, 0x08277231, 0x50c6ff78, -747}, - {0xece53cec, 0x4a314ebd, 0xa4f8bf56, -744}, - {0x940f4613, 0xae5ed136, 0x871b7795, -740}, - {0xb9131798, 0x99f68584, 0x28e2557b, -737}, - {0xe757dd7e, 0xc07426e5, 0x331aeada, -734}, - {0x9096ea6f, 0x3848984f, 0x3ff0d2c8, -730}, - {0xb4bca50b, 0x065abe63, 0x0fed077a, -727}, - {0xe1ebce4d, 0xc7f16dfb, 0xd3e84959, -724}, - {0x8d3360f0, 0x9cf6e4bd, 0x64712dd7, -720}, - {0xb080392c, 0xc4349dec, 0xbd8d794d, -717}, - {0xdca04777, 0xf541c567, 0xecf0d7a0, -714}, - {0x89e42caa, 0xf9491b60, 0xf41686c4, -710}, - {0xac5d37d5, 0xb79b6239, 0x311c2875, -707}, - {0xd77485cb, 0x25823ac7, 0x7d633293, -704}, - {0x86a8d39e, 0xf77164bc, 0xae5dff9c, -700}, - {0xa8530886, 0xb54dbdeb, 0xd9f57f83, -697}, - {0xd267caa8, 0x62a12d66, 0xd072df63, -694}, - {0x8380dea9, 0x3da4bc60, 0x4247cb9e, -690}, - {0xa4611653, 0x8d0deb78, 0x52d9be85, -687}, - {0xcd795be8, 0x70516656, 0x67902e27, -684}, - {0x806bd971, 0x4632dff6, 0x00ba1cd8, -680}, - {0xa086cfcd, 0x97bf97f3, 0x80e8a40e, -677}, - {0xc8a883c0, 0xfdaf7df0, 0x6122cd12, -674}, - {0xfad2a4b1, 0x3d1b5d6c, 0x796b8057, -671}, - {0x9cc3a6ee, 0xc6311a63, 0xcbe33036, -667}, - {0xc3f490aa, 0x77bd60fc, 0xbedbfc44, -664}, - {0xf4f1b4d5, 0x15acb93b, 0xee92fb55, -661}, - {0x99171105, 0x2d8bf3c5, 0x751bdd15, -657}, - {0xbf5cd546, 0x78eef0b6, 0xd262d45a, -654}, - {0xef340a98, 0x172aace4, 0x86fb8971, -651}, - {0x9580869f, 0x0e7aac0e, 0xd45d35e6, -647}, - {0xbae0a846, 0xd2195712, 0x89748360, -644}, - {0xe998d258, 0x869facd7, 0x2bd1a438, -641}, - {0x91ff8377, 0x5423cc06, 0x7b6306a3, -637}, - {0xb67f6455, 0x292cbf08, 0x1a3bc84c, -634}, - {0xe41f3d6a, 0x7377eeca, 0x20caba5f, -631}, - {0x8e938662, 0x882af53e, 0x547eb47b, -627}, - {0xb23867fb, 0x2a35b28d, 0xe99e619a, -624}, - {0xdec681f9, 0xf4c31f31, 0x6405fa00, -621}, - {0x8b3c113c, 0x38f9f37e, 0xde83bc40, -617}, - {0xae0b158b, 0x4738705e, 0x9624ab50, -614}, - {0xd98ddaee, 0x19068c76, 0x3badd624, -611}, - {0x87f8a8d4, 0xcfa417c9, 0xe54ca5d7, -607}, - {0xa9f6d30a, 0x038d1dbc, 0x5e9fcf4c, -604}, - {0xd47487cc, 0x8470652b, 0x7647c320, -601}, - {0x84c8d4df, 0xd2c63f3b, 0x29ecd9f4, -597}, - {0xa5fb0a17, 0xc777cf09, 0xf4681071, -594}, - {0xcf79cc9d, 0xb955c2cc, 0x7182148d, -591}, - {0x81ac1fe2, 0x93d599bf, 0xc6f14cd8, -587}, - {0xa21727db, 0x38cb002f, 0xb8ada00e, -584}, - {0xca9cf1d2, 0x06fdc03b, 0xa6d90811, -581}, - {0xfd442e46, 0x88bd304a, 0x908f4a16, -578}, - {0x9e4a9cec, 0x15763e2e, 0x9a598e4e, -574}, - {0xc5dd4427, 0x1ad3cdba, 0x40eff1e1, -571}, - {0xf7549530, 0xe188c128, 0xd12bee59, -568}, - {0x9a94dd3e, 0x8cf578b9, 0x82bb74f8, -564}, - {0xc13a148e, 0x3032d6e7, 0xe36a5236, -561}, - {0xf18899b1, 0xbc3f8ca1, 0xdc44e6c3, -558}, - {0x96f5600f, 0x15a7b7e5, 0x29ab103a, -554}, - {0xbcb2b812, 0xdb11a5de, 0x7415d448, -551}, - {0xebdf6617, 0x91d60f56, 0x111b495b, -548}, - {0x936b9fce, 0xbb25c995, 0xcab10dd9, -544}, - {0xb84687c2, 0x69ef3bfb, 0x3d5d514f, -541}, - {0xe65829b3, 0x046b0afa, 0x0cb4a5a3, -538}, - {0x8ff71a0f, 0xe2c2e6dc, 0x47f0e785, -534}, - {0xb3f4e093, 0xdb73a093, 0x59ed2167, -531}, - {0xe0f218b8, 0xd25088b8, 0x306869c1, -528}, - {0x8c974f73, 0x83725573, 0x1e414218, -524}, - {0xafbd2350, 0x644eeacf, 0xe5d1929e, -521}, - {0xdbac6c24, 0x7d62a583, 0xdf45f746, -518}, - {0x894bc396, 0xce5da772, 0x6b8bba8c, -514}, - {0xab9eb47c, 0x81f5114f, 0x066ea92f, -511}, - {0xd686619b, 0xa27255a2, 0xc80a537b, -508}, - {0x8613fd01, 0x45877585, 0xbd06742c, -504}, - {0xa798fc41, 0x96e952e7, 0x2c481138, -501}, - {0xd17f3b51, 0xfca3a7a0, 0xf75a1586, -498}, - {0x82ef8513, 0x3de648c4, 0x9a984d73, -494}, - {0xa3ab6658, 0x0d5fdaf5, 0xc13e60d0, -491}, - {0xcc963fee, 0x10b7d1b3, 0x318df905, -488}, - {0xffbbcfe9, 0x94e5c61f, 0xfdf17746, -485}, - {0x9fd561f1, 0xfd0f9bd3, 0xfeb6ea8b, -481}, - {0xc7caba6e, 0x7c5382c8, 0xfe64a52e, -478}, - {0xf9bd690a, 0x1b68637b, 0x3dfdce7a, -475}, - {0x9c1661a6, 0x51213e2d, 0x06bea10c, -471}, - {0xc31bfa0f, 0xe5698db8, 0x486e494f, -468}, - {0xf3e2f893, 0xdec3f126, 0x5a89dba3, -465}, - {0x986ddb5c, 0x6b3a76b7, 0xf8962946, -461}, - {0xbe895233, 0x86091465, 0xf6bbb397, -458}, - {0xee2ba6c0, 0x678b597f, 0x746aa07d, -455}, - {0x94db4838, 0x40b717ef, 0xa8c2a44e, -451}, - {0xba121a46, 0x50e4ddeb, 0x92f34d62, -448}, - {0xe896a0d7, 0xe51e1566, 0x77b020ba, -445}, - {0x915e2486, 0xef32cd60, 0x0ace1474, -441}, - {0xb5b5ada8, 0xaaff80b8, 0x0d819992, -438}, - {0xe3231912, 0xd5bf60e6, 0x10e1fff6, -435}, - {0x8df5efab, 0xc5979c8f, 0xca8d3ffa, -431}, - {0xb1736b96, 0xb6fd83b3, 0xbd308ff8, -428}, - {0xddd0467c, 0x64bce4a0, 0xac7cb3f6, -425}, - {0x8aa22c0d, 0xbef60ee4, 0x6bcdf07a, -421}, - {0xad4ab711, 0x2eb3929d, 0x86c16c98, -418}, - {0xd89d64d5, 0x7a607744, 0xe871c7bf, -415}, - {0x87625f05, 0x6c7c4a8b, 0x11471cd7, -411}, - {0xa93af6c6, 0xc79b5d2d, 0xd598e40d, -408}, - {0xd389b478, 0x79823479, 0x4aff1d10, -405}, - {0x843610cb, 0x4bf160cb, 0xcedf722a, -401}, - {0xa54394fe, 0x1eedb8fe, 0xc2974eb4, -398}, - {0xce947a3d, 0xa6a9273e, 0x733d2262, -395}, - {0x811ccc66, 0x8829b887, 0x0806357d, -391}, - {0xa163ff80, 0x2a3426a8, 0xca07c2dc, -388}, - {0xc9bcff60, 0x34c13052, 0xfc89b393, -385}, - {0xfc2c3f38, 0x41f17c67, 0xbbac2078, -382}, - {0x9d9ba783, 0x2936edc0, 0xd54b944b, -378}, - {0xc5029163, 0xf384a931, 0x0a9e795e, -375}, - {0xf64335bc, 0xf065d37d, 0x4d4617b5, -372}, - {0x99ea0196, 0x163fa42e, 0x504bced1, -368}, - {0xc06481fb, 0x9bcf8d39, 0xe45ec286, -365}, - {0xf07da27a, 0x82c37088, 0x5d767327, -362}, - {0x964e858c, 0x91ba2655, 0x3a6a07f8, -358}, - {0xbbe226ef, 0xb628afea, 0x890489f7, -355}, - {0xeadab0ab, 0xa3b2dbe5, 0x2b45ac74, -352}, - {0x92c8ae6b, 0x464fc96f, 0x3b0b8bc9, -348}, - {0xb77ada06, 0x17e3bbcb, 0x09ce6ebb, -345}, - {0xe5599087, 0x9ddcaabd, 0xcc420a6a, -342}, - {0x8f57fa54, 0xc2a9eab6, 0x9fa94682, -338}, - {0xb32df8e9, 0xf3546564, 0x47939822, -335}, - {0xdff97724, 0x70297ebd, 0x59787e2b, -332}, - {0x8bfbea76, 0xc619ef36, 0x57eb4edb, -328}, - {0xaefae514, 0x77a06b03, 0xede62292, -325}, - {0xdab99e59, 0x958885c4, 0xe95fab36, -322}, - {0x88b402f7, 0xfd75539b, 0x11dbcb02, -318}, - {0xaae103b5, 0xfcd2a881, 0xd652bdc2, -315}, - {0xd59944a3, 0x7c0752a2, 0x4be76d33, -312}, - {0x857fcae6, 0x2d8493a5, 0x6f70a440, -308}, - {0xa6dfbd9f, 0xb8e5b88e, 0xcb4ccd50, -305}, - {0xd097ad07, 0xa71f26b2, 0x7e2000a4, -302}, - {0x825ecc24, 0xc873782f, 0x8ed40066, -298}, - {0xa2f67f2d, 0xfa90563b, 0x72890080, -295}, - {0xcbb41ef9, 0x79346bca, 0x4f2b40a0, -292}, - {0xfea126b7, 0xd78186bc, 0xe2f610c8, -289}, - {0x9f24b832, 0xe6b0f436, 0x0dd9ca7d, -285}, - {0xc6ede63f, 0xa05d3143, 0x91503d1c, -282}, - {0xf8a95fcf, 0x88747d94, 0x75a44c63, -279}, - {0x9b69dbe1, 0xb548ce7c, 0xc986afbe, -275}, - {0xc24452da, 0x229b021b, 0xfbe85bad, -272}, - {0xf2d56790, 0xab41c2a2, 0xfae27299, -269}, - {0x97c560ba, 0x6b0919a5, 0xdccd879f, -265}, - {0xbdb6b8e9, 0x05cb600f, 0x5400e987, -262}, - {0xed246723, 0x473e3813, 0x290123e9, -259}, - {0x9436c076, 0x0c86e30b, 0xf9a0b672, -255}, - {0xb9447093, 0x8fa89bce, 0xf808e40e, -252}, - {0xe7958cb8, 0x7392c2c2, 0xb60b1d12, -249}, - {0x90bd77f3, 0x483bb9b9, 0xb1c6f22b, -245}, - {0xb4ecd5f0, 0x1a4aa828, 0x1e38aeb6, -242}, - {0xe2280b6c, 0x20dd5232, 0x25c6da63, -239}, - {0x8d590723, 0x948a535f, 0x579c487e, -235}, - {0xb0af48ec, 0x79ace837, 0x2d835a9d, -232}, - {0xdcdb1b27, 0x98182244, 0xf8e43145, -229}, - {0x8a08f0f8, 0xbf0f156b, 0x1b8e9ecb, -225}, - {0xac8b2d36, 0xeed2dac5, 0xe272467e, -222}, - {0xd7adf884, 0xaa879177, 0x5b0ed81d, -219}, - {0x86ccbb52, 0xea94baea, 0x98e94712, -215}, - {0xa87fea27, 0xa539e9a5, 0x3f2398d7, -212}, - {0xd29fe4b1, 0x8e88640e, 0x8eec7f0d, -209}, - {0x83a3eeee, 0xf9153e89, 0x1953cf68, -205}, - {0xa48ceaaa, 0xb75a8e2b, 0x5fa8c342, -202}, - {0xcdb02555, 0x653131b6, 0x3792f412, -199}, - {0x808e1755, 0x5f3ebf11, 0xe2bbd88b, -195}, - {0xa0b19d2a, 0xb70e6ed6, 0x5b6aceae, -192}, - {0xc8de0475, 0x64d20a8b, 0xf245825a, -189}, - {0xfb158592, 0xbe068d2e, 0xeed6e2f0, -186}, - {0x9ced737b, 0xb6c4183d, 0x55464dd6, -182}, - {0xc428d05a, 0xa4751e4c, 0xaa97e14c, -179}, - {0xf5330471, 0x4d9265df, 0xd53dd99f, -176}, - {0x993fe2c6, 0xd07b7fab, 0xe546a803, -172}, - {0xbf8fdb78, 0x849a5f96, 0xde985204, -169}, - {0xef73d256, 0xa5c0f77c, 0x963e6685, -166}, - {0x95a86376, 0x27989aad, 0xdde70013, -162}, - {0xbb127c53, 0xb17ec159, 0x5560c018, -159}, - {0xe9d71b68, 0x9dde71af, 0xaab8f01e, -156}, - {0x92267121, 0x62ab070d, 0xcab39613, -152}, - {0xb6b00d69, 0xbb55c8d1, 0x3d607b97, -149}, - {0xe45c10c4, 0x2a2b3b05, 0x8cb89a7d, -146}, - {0x8eb98a7a, 0x9a5b04e3, 0x77f3608e, -142}, - {0xb267ed19, 0x40f1c61c, 0x55f038b2, -139}, - {0xdf01e85f, 0x912e37a3, 0x6b6c46de, -136}, - {0x8b61313b, 0xbabce2c6, 0x2323ac4b, -132}, - {0xae397d8a, 0xa96c1b77, 0xabec975e, -129}, - {0xd9c7dced, 0x53c72255, 0x96e7bd35, -126}, - {0x881cea14, 0x545c7575, 0x7e50d641, -122}, - {0xaa242499, 0x697392d2, 0xdde50bd1, -119}, - {0xd4ad2dbf, 0xc3d07787, 0x955e4ec6, -116}, - {0x84ec3c97, 0xda624ab4, 0xbd5af13b, -112}, - {0xa6274bbd, 0xd0fadd61, 0xecb1ad8a, -109}, - {0xcfb11ead, 0x453994ba, 0x67de18ed, -106}, - {0x81ceb32c, 0x4b43fcf4, 0x80eacf94, -102}, - {0xa2425ff7, 0x5e14fc31, 0xa1258379, -99}, - {0xcad2f7f5, 0x359a3b3e, 0x096ee458, -96}, - {0xfd87b5f2, 0x8300ca0d, 0x8bca9d6e, -93}, - {0x9e74d1b7, 0x91e07e48, 0x775ea264, -89}, - {0xc6120625, 0x76589dda, 0x95364afe, -86}, - {0xf79687ae, 0xd3eec551, 0x3a83ddbd, -83}, - {0x9abe14cd, 0x44753b52, 0xc4926a96, -79}, - {0xc16d9a00, 0x95928a27, 0x75b7053c, -76}, - {0xf1c90080, 0xbaf72cb1, 0x5324c68b, -73}, - {0x971da050, 0x74da7bee, 0xd3f6fc16, -69}, - {0xbce50864, 0x92111aea, 0x88f4bb1c, -66}, - {0xec1e4a7d, 0xb69561a5, 0x2b31e9e3, -63}, - {0x9392ee8e, 0x921d5d07, 0x3aff322e, -59}, - {0xb877aa32, 0x36a4b449, 0x09befeb9, -56}, - {0xe69594be, 0xc44de15b, 0x4c2ebe68, -53}, - {0x901d7cf7, 0x3ab0acd9, 0x0f9d3701, -49}, - {0xb424dc35, 0x095cd80f, 0x538484c1, -46}, - {0xe12e1342, 0x4bb40e13, 0x2865a5f2, -43}, - {0x8cbccc09, 0x6f5088cb, 0xf93f87b7, -39}, - {0xafebff0b, 0xcb24aafe, 0xf78f69a5, -36}, - {0xdbe6fece, 0xbdedd5be, 0xb573440e, -33}, - {0x89705f41, 0x36b4a597, 0x31680a88, -29}, - {0xabcc7711, 0x8461cefc, 0xfdc20d2b, -26}, - {0xd6bf94d5, 0xe57a42bc, 0x3d329076, -23}, - {0x8637bd05, 0xaf6c69b5, 0xa63f9a49, -19}, - {0xa7c5ac47, 0x1b478423, 0x0fcf80dc, -16}, - {0xd1b71758, 0xe219652b, 0xd3c36113, -13}, - {0x83126e97, 0x8d4fdf3b, 0x645a1cac, -9}, - {0xa3d70a3d, 0x70a3d70a, 0x3d70a3d7, -6}, - {0xcccccccc, 0xcccccccc, 0xcccccccc, -3}, - {0x80000000, 0x00000000, 0x00000000, 1}, - {0xa0000000, 0x00000000, 0x00000000, 4}, - {0xc8000000, 0x00000000, 0x00000000, 7}, - {0xfa000000, 0x00000000, 0x00000000, 10}, - {0x9c400000, 0x00000000, 0x00000000, 14}, - {0xc3500000, 0x00000000, 0x00000000, 17}, - {0xf4240000, 0x00000000, 0x00000000, 20}, - {0x98968000, 0x00000000, 0x00000000, 24}, - {0xbebc2000, 0x00000000, 0x00000000, 27}, - {0xee6b2800, 0x00000000, 0x00000000, 30}, - {0x9502f900, 0x00000000, 0x00000000, 34}, - {0xba43b740, 0x00000000, 0x00000000, 37}, - {0xe8d4a510, 0x00000000, 0x00000000, 40}, - {0x9184e72a, 0x00000000, 0x00000000, 44}, - {0xb5e620f4, 0x80000000, 0x00000000, 47}, - {0xe35fa931, 0xa0000000, 0x00000000, 50}, - {0x8e1bc9bf, 0x04000000, 0x00000000, 54}, - {0xb1a2bc2e, 0xc5000000, 0x00000000, 57}, - {0xde0b6b3a, 0x76400000, 0x00000000, 60}, - {0x8ac72304, 0x89e80000, 0x00000000, 64}, - {0xad78ebc5, 0xac620000, 0x00000000, 67}, - {0xd8d726b7, 0x177a8000, 0x00000000, 70}, - {0x87867832, 0x6eac9000, 0x00000000, 74}, - {0xa968163f, 0x0a57b400, 0x00000000, 77}, - {0xd3c21bce, 0xcceda100, 0x00000000, 80}, - {0x84595161, 0x401484a0, 0x00000000, 84}, - {0xa56fa5b9, 0x9019a5c8, 0x00000000, 87}, - {0xcecb8f27, 0xf4200f3a, 0x00000000, 90}, - {0x813f3978, 0xf8940984, 0x40000000, 94}, - {0xa18f07d7, 0x36b90be5, 0x50000000, 97}, - {0xc9f2c9cd, 0x04674ede, 0xa4000000, 100}, - {0xfc6f7c40, 0x45812296, 0x4d000000, 103}, - {0x9dc5ada8, 0x2b70b59d, 0xf0200000, 107}, - {0xc5371912, 0x364ce305, 0x6c280000, 110}, - {0xf684df56, 0xc3e01bc6, 0xc7320000, 113}, - {0x9a130b96, 0x3a6c115c, 0x3c7f4000, 117}, - {0xc097ce7b, 0xc90715b3, 0x4b9f1000, 120}, - {0xf0bdc21a, 0xbb48db20, 0x1e86d400, 123}, - {0x96769950, 0xb50d88f4, 0x13144480, 127}, - {0xbc143fa4, 0xe250eb31, 0x17d955a0, 130}, - {0xeb194f8e, 0x1ae525fd, 0x5dcfab08, 133}, - {0x92efd1b8, 0xd0cf37be, 0x5aa1cae5, 137}, - {0xb7abc627, 0x050305ad, 0xf14a3d9e, 140}, - {0xe596b7b0, 0xc643c719, 0x6d9ccd05, 143}, - {0x8f7e32ce, 0x7bea5c6f, 0xe4820023, 147}, - {0xb35dbf82, 0x1ae4f38b, 0xdda2802c, 150}, - {0xe0352f62, 0xa19e306e, 0xd50b2037, 153}, - {0x8c213d9d, 0xa502de45, 0x4526f422, 157}, - {0xaf298d05, 0x0e4395d6, 0x9670b12b, 160}, - {0xdaf3f046, 0x51d47b4c, 0x3c0cdd76, 163}, - {0x88d8762b, 0xf324cd0f, 0xa5880a69, 167}, - {0xab0e93b6, 0xefee0053, 0x8eea0d04, 170}, - {0xd5d238a4, 0xabe98068, 0x72a49045, 173}, - {0x85a36366, 0xeb71f041, 0x47a6da2b, 177}, - {0xa70c3c40, 0xa64e6c51, 0x999090b6, 180}, - {0xd0cf4b50, 0xcfe20765, 0xfff4b4e3, 183}, - {0x82818f12, 0x81ed449f, 0xbff8f10e, 187}, - {0xa321f2d7, 0x226895c7, 0xaff72d52, 190}, - {0xcbea6f8c, 0xeb02bb39, 0x9bf4f8a6, 193}, - {0xfee50b70, 0x25c36a08, 0x02f236d0, 196}, - {0x9f4f2726, 0x179a2245, 0x01d76242, 200}, - {0xc722f0ef, 0x9d80aad6, 0x424d3ad2, 203}, - {0xf8ebad2b, 0x84e0d58b, 0xd2e08987, 206}, - {0x9b934c3b, 0x330c8577, 0x63cc55f4, 210}, - {0xc2781f49, 0xffcfa6d5, 0x3cbf6b71, 213}, - {0xf316271c, 0x7fc3908a, 0x8bef464e, 216}, - {0x97edd871, 0xcfda3a56, 0x97758bf0, 220}, - {0xbde94e8e, 0x43d0c8ec, 0x3d52eeed, 223}, - {0xed63a231, 0xd4c4fb27, 0x4ca7aaa8, 226}, - {0x945e455f, 0x24fb1cf8, 0x8fe8caa9, 230}, - {0xb975d6b6, 0xee39e436, 0xb3e2fd53, 233}, - {0xe7d34c64, 0xa9c85d44, 0x60dbbca8, 236}, - {0x90e40fbe, 0xea1d3a4a, 0xbc8955e9, 240}, - {0xb51d13ae, 0xa4a488dd, 0x6babab63, 243}, - {0xe264589a, 0x4dcdab14, 0xc696963c, 246}, - {0x8d7eb760, 0x70a08aec, 0xfc1e1de5, 250}, - {0xb0de6538, 0x8cc8ada8, 0x3b25a55f, 253}, - {0xdd15fe86, 0xaffad912, 0x49ef0eb7, 256}, - {0x8a2dbf14, 0x2dfcc7ab, 0x6e356932, 260}, - {0xacb92ed9, 0x397bf996, 0x49c2c37f, 263}, - {0xd7e77a8f, 0x87daf7fb, 0xdc33745e, 266}, - {0x86f0ac99, 0xb4e8dafd, 0x69a028bb, 270}, - {0xa8acd7c0, 0x222311bc, 0xc40832ea, 273}, - {0xd2d80db0, 0x2aabd62b, 0xf50a3fa4, 276}, - {0x83c7088e, 0x1aab65db, 0x792667c6, 280}, - {0xa4b8cab1, 0xa1563f52, 0x577001b8, 283}, - {0xcde6fd5e, 0x09abcf26, 0xed4c0226, 286}, - {0x80b05e5a, 0xc60b6178, 0x544f8158, 290}, - {0xa0dc75f1, 0x778e39d6, 0x696361ae, 293}, - {0xc913936d, 0xd571c84c, 0x03bc3a19, 296}, - {0xfb587849, 0x4ace3a5f, 0x04ab48a0, 299}, - {0x9d174b2d, 0xcec0e47b, 0x62eb0d64, 303}, - {0xc45d1df9, 0x42711d9a, 0x3ba5d0bd, 306}, - {0xf5746577, 0x930d6500, 0xca8f44ec, 309}, - {0x9968bf6a, 0xbbe85f20, 0x7e998b13, 313}, - {0xbfc2ef45, 0x6ae276e8, 0x9e3fedd8, 316}, - {0xefb3ab16, 0xc59b14a2, 0xc5cfe94e, 319}, - {0x95d04aee, 0x3b80ece5, 0xbba1f1d1, 323}, - {0xbb445da9, 0xca61281f, 0x2a8a6e45, 326}, - {0xea157514, 0x3cf97226, 0xf52d09d7, 329}, - {0x924d692c, 0xa61be758, 0x593c2626, 333}, - {0xb6e0c377, 0xcfa2e12e, 0x6f8b2fb0, 336}, - {0xe498f455, 0xc38b997a, 0x0b6dfb9c, 339}, - {0x8edf98b5, 0x9a373fec, 0x4724bd41, 343}, - {0xb2977ee3, 0x00c50fe7, 0x58edec91, 346}, - {0xdf3d5e9b, 0xc0f653e1, 0x2f2967b6, 349}, - {0x8b865b21, 0x5899f46c, 0xbd79e0d2, 353}, - {0xae67f1e9, 0xaec07187, 0xecd85906, 356}, - {0xda01ee64, 0x1a708de9, 0xe80e6f48, 359}, - {0x884134fe, 0x908658b2, 0x3109058d, 363}, - {0xaa51823e, 0x34a7eede, 0xbd4b46f0, 366}, - {0xd4e5e2cd, 0xc1d1ea96, 0x6c9e18ac, 369}, - {0x850fadc0, 0x9923329e, 0x03e2cf6b, 373}, - {0xa6539930, 0xbf6bff45, 0x84db8346, 376}, - {0xcfe87f7c, 0xef46ff16, 0xe6126418, 379}, - {0x81f14fae, 0x158c5f6e, 0x4fcb7e8f, 383}, - {0xa26da399, 0x9aef7749, 0xe3be5e33, 386}, - {0xcb090c80, 0x01ab551c, 0x5cadf5bf, 389}, - {0xfdcb4fa0, 0x02162a63, 0x73d9732f, 392}, - {0x9e9f11c4, 0x014dda7e, 0x2867e7fd, 396}, - {0xc646d635, 0x01a1511d, 0xb281e1fd, 399}, - {0xf7d88bc2, 0x4209a565, 0x1f225a7c, 402}, - {0x9ae75759, 0x6946075f, 0x3375788d, 406}, - {0xc1a12d2f, 0xc3978937, 0x0052d6b1, 409}, - {0xf209787b, 0xb47d6b84, 0xc0678c5d, 412}, - {0x9745eb4d, 0x50ce6332, 0xf840b7ba, 416}, - {0xbd176620, 0xa501fbff, 0xb650e5a9, 419}, - {0xec5d3fa8, 0xce427aff, 0xa3e51f13, 422}, - {0x93ba47c9, 0x80e98cdf, 0xc66f336c, 426}, - {0xb8a8d9bb, 0xe123f017, 0xb80b0047, 429}, - {0xe6d3102a, 0xd96cec1d, 0xa60dc059, 432}, - {0x9043ea1a, 0xc7e41392, 0x87c89837, 436}, - {0xb454e4a1, 0x79dd1877, 0x29babe45, 439}, - {0xe16a1dc9, 0xd8545e94, 0xf4296dd6, 442}, - {0x8ce2529e, 0x2734bb1d, 0x1899e4a6, 446}, - {0xb01ae745, 0xb101e9e4, 0x5ec05dcf, 449}, - {0xdc21a117, 0x1d42645d, 0x76707543, 452}, - {0x899504ae, 0x72497eba, 0x6a06494a, 456}, - {0xabfa45da, 0x0edbde69, 0x0487db9d, 459}, - {0xd6f8d750, 0x9292d603, 0x45a9d284, 462}, - {0x865b8692, 0x5b9bc5c2, 0x0b8a2392, 466}, - {0xa7f26836, 0xf282b732, 0x8e6cac77, 469}, - {0xd1ef0244, 0xaf2364ff, 0x3207d795, 472}, - {0x8335616a, 0xed761f1f, 0x7f44e6bd, 476}, - {0xa402b9c5, 0xa8d3a6e7, 0x5f16206c, 479}, - {0xcd036837, 0x130890a1, 0x36dba887, 482}, - {0x80222122, 0x6be55a64, 0xc2494954, 486}, - {0xa02aa96b, 0x06deb0fd, 0xf2db9baa, 489}, - {0xc83553c5, 0xc8965d3d, 0x6f928294, 492}, - {0xfa42a8b7, 0x3abbf48c, 0xcb772339, 495}, - {0x9c69a972, 0x84b578d7, 0xff2a7604, 499}, - {0xc38413cf, 0x25e2d70d, 0xfef51385, 502}, - {0xf46518c2, 0xef5b8cd1, 0x7eb25866, 505}, - {0x98bf2f79, 0xd5993802, 0xef2f773f, 509}, - {0xbeeefb58, 0x4aff8603, 0xaafb550f, 512}, - {0xeeaaba2e, 0x5dbf6784, 0x95ba2a53, 515}, - {0x952ab45c, 0xfa97a0b2, 0xdd945a74, 519}, - {0xba756174, 0x393d88df, 0x94f97111, 522}, - {0xe912b9d1, 0x478ceb17, 0x7a37cd56, 525}, - {0x91abb422, 0xccb812ee, 0xac62e055, 529}, - {0xb616a12b, 0x7fe617aa, 0x577b986b, 532}, - {0xe39c4976, 0x5fdf9d94, 0xed5a7e85, 535}, - {0x8e41ade9, 0xfbebc27d, 0x14588f13, 539}, - {0xb1d21964, 0x7ae6b31c, 0x596eb2d8, 542}, - {0xde469fbd, 0x99a05fe3, 0x6fca5f8e, 545}, - {0x8aec23d6, 0x80043bee, 0x25de7bb9, 549}, - {0xada72ccc, 0x20054ae9, 0xaf561aa7, 552}, - {0xd910f7ff, 0x28069da4, 0x1b2ba151, 555}, - {0x87aa9aff, 0x79042286, 0x90fb44d2, 559}, - {0xa99541bf, 0x57452b28, 0x353a1607, 562}, - {0xd3fa922f, 0x2d1675f2, 0x42889b89, 565}, - {0x847c9b5d, 0x7c2e09b7, 0x69956135, 569}, - {0xa59bc234, 0xdb398c25, 0x43fab983, 572}, - {0xcf02b2c2, 0x1207ef2e, 0x94f967e4, 575}, - {0x8161afb9, 0x4b44f57d, 0x1d1be0ee, 579}, - {0xa1ba1ba7, 0x9e1632dc, 0x6462d92a, 582}, - {0xca28a291, 0x859bbf93, 0x7d7b8f75, 585}, - {0xfcb2cb35, 0xe702af78, 0x5cda7352, 588}, - {0x9defbf01, 0xb061adab, 0x3a088813, 592}, - {0xc56baec2, 0x1c7a1916, 0x088aaa18, 595}, - {0xf6c69a72, 0xa3989f5b, 0x8aad549e, 598}, - {0x9a3c2087, 0xa63f6399, 0x36ac54e2, 602}, - {0xc0cb28a9, 0x8fcf3c7f, 0x84576a1b, 605}, - {0xf0fdf2d3, 0xf3c30b9f, 0x656d44a2, 608}, - {0x969eb7c4, 0x7859e743, 0x9f644ae5, 612}, - {0xbc4665b5, 0x96706114, 0x873d5d9f, 615}, - {0xeb57ff22, 0xfc0c7959, 0xa90cb506, 618}, - {0x9316ff75, 0xdd87cbd8, 0x09a7f124, 622}, - {0xb7dcbf53, 0x54e9bece, 0x0c11ed6d, 625}, - {0xe5d3ef28, 0x2a242e81, 0x8f1668c8, 628}, - {0x8fa47579, 0x1a569d10, 0xf96e017d, 632}, - {0xb38d92d7, 0x60ec4455, 0x37c981dc, 635}, - {0xe070f78d, 0x3927556a, 0x85bbe253, 638}, - {0x8c469ab8, 0x43b89562, 0x93956d74, 642}, - {0xaf584166, 0x54a6babb, 0x387ac8d1, 645}, - {0xdb2e51bf, 0xe9d0696a, 0x06997b05, 648}, - {0x88fcf317, 0xf22241e2, 0x441fece3, 652}, - {0xab3c2fdd, 0xeeaad25a, 0xd527e81c, 655}, - {0xd60b3bd5, 0x6a5586f1, 0x8a71e223, 658}, - {0x85c70565, 0x62757456, 0xf6872d56, 662}, - {0xa738c6be, 0xbb12d16c, 0xb428f8ac, 665}, - {0xd106f86e, 0x69d785c7, 0xe13336d7, 668}, - {0x82a45b45, 0x0226b39c, 0xecc00246, 672}, - {0xa34d7216, 0x42b06084, 0x27f002d7, 675}, - {0xcc20ce9b, 0xd35c78a5, 0x31ec038d, 678}, - {0xff290242, 0xc83396ce, 0x7e670471, 681}, - {0x9f79a169, 0xbd203e41, 0x0f0062c6, 685}, - {0xc75809c4, 0x2c684dd1, 0x52c07b78, 688}, - {0xf92e0c35, 0x37826145, 0xa7709a56, 691}, - {0x9bbcc7a1, 0x42b17ccb, 0x88a66076, 695}, - {0xc2abf989, 0x935ddbfe, 0x6acff893, 698}, - {0xf356f7eb, 0xf83552fe, 0x0583f6b8, 701}, - {0x98165af3, 0x7b2153de, 0xc3727a33, 705}, - {0xbe1bf1b0, 0x59e9a8d6, 0x744f18c0, 708}, - {0xeda2ee1c, 0x7064130c, 0x1162def0, 711}, - {0x9485d4d1, 0xc63e8be7, 0x8addcb56, 715}, - {0xb9a74a06, 0x37ce2ee1, 0x6d953e2b, 718}, - {0xe8111c87, 0xc5c1ba99, 0xc8fa8db6, 721}, - {0x910ab1d4, 0xdb9914a0, 0x1d9c9892, 725}, - {0xb54d5e4a, 0x127f59c8, 0x2503beb6, 728}, - {0xe2a0b5dc, 0x971f303a, 0x2e44ae64, 731}, - {0x8da471a9, 0xde737e24, 0x5ceaecfe, 735}, - {0xb10d8e14, 0x56105dad, 0x7425a83e, 738}, - {0xdd50f199, 0x6b947518, 0xd12f124e, 741}, - {0x8a5296ff, 0xe33cc92f, 0x82bd6b70, 745}, - {0xace73cbf, 0xdc0bfb7b, 0x636cc64d, 748}, - {0xd8210bef, 0xd30efa5a, 0x3c47f7e0, 751}, - {0x8714a775, 0xe3e95c78, 0x65acfaec, 755}, - {0xa8d9d153, 0x5ce3b396, 0x7f1839a7, 758}, - {0xd31045a8, 0x341ca07c, 0x1ede4811, 761}, - {0x83ea2b89, 0x2091e44d, 0x934aed0a, 765}, - {0xa4e4b66b, 0x68b65d60, 0xf81da84d, 768}, - {0xce1de406, 0x42e3f4b9, 0x36251260, 771}, - {0x80d2ae83, 0xe9ce78f3, 0xc1d72b7c, 775}, - {0xa1075a24, 0xe4421730, 0xb24cf65b, 778}, - {0xc94930ae, 0x1d529cfc, 0xdee033f2, 781}, - {0xfb9b7cd9, 0xa4a7443c, 0x169840ef, 784}, - {0x9d412e08, 0x06e88aa5, 0x8e1f2895, 788}, - {0xc491798a, 0x08a2ad4e, 0xf1a6f2ba, 791}, - {0xf5b5d7ec, 0x8acb58a2, 0xae10af69, 794}, - {0x9991a6f3, 0xd6bf1765, 0xacca6da1, 798}, - {0xbff610b0, 0xcc6edd3f, 0x17fd090a, 801}, - {0xeff394dc, 0xff8a948e, 0xddfc4b4c, 804}, - {0x95f83d0a, 0x1fb69cd9, 0x4abdaf10, 808}, - {0xbb764c4c, 0xa7a4440f, 0x9d6d1ad4, 811}, - {0xea53df5f, 0xd18d5513, 0x84c86189, 814}, - {0x92746b9b, 0xe2f8552c, 0x32fd3cf5, 818}, - {0xb7118682, 0xdbb66a77, 0x3fbc8c33, 821}, - {0xe4d5e823, 0x92a40515, 0x0fabaf3f, 824}, - {0x8f05b116, 0x3ba6832d, 0x29cb4d87, 828}, - {0xb2c71d5b, 0xca9023f8, 0x743e20e9, 831}, - {0xdf78e4b2, 0xbd342cf6, 0x914da924, 834}, - {0x8bab8eef, 0xb6409c1a, 0x1ad089b6, 838}, - {0xae9672ab, 0xa3d0c320, 0xa184ac24, 841}, - {0xda3c0f56, 0x8cc4f3e8, 0xc9e5d72d, 844}, - {0x88658996, 0x17fb1871, 0x7e2fa67c, 848}, - {0xaa7eebfb, 0x9df9de8d, 0xddbb901b, 851}, - {0xd51ea6fa, 0x85785631, 0x552a7422, 854}, - {0x8533285c, 0x936b35de, 0xd53a8895, 858}, - {0xa67ff273, 0xb8460356, 0x8a892aba, 861}, - {0xd01fef10, 0xa657842c, 0x2d2b7569, 864}, - {0x8213f56a, 0x67f6b29b, 0x9c3b2962, 868}, - {0xa298f2c5, 0x01f45f42, 0x8349f3ba, 871}, - {0xcb3f2f76, 0x42717713, 0x241c70a9, 874}, - {0xfe0efb53, 0xd30dd4d7, 0xed238cd3, 877}, - {0x9ec95d14, 0x63e8a506, 0xf4363804, 881}, - {0xc67bb459, 0x7ce2ce48, 0xb143c605, 884}, - {0xf81aa16f, 0xdc1b81da, 0xdd94b786, 887}, - {0x9b10a4e5, 0xe9913128, 0xca7cf2b4, 891}, - {0xc1d4ce1f, 0x63f57d72, 0xfd1c2f61, 894}, - {0xf24a01a7, 0x3cf2dccf, 0xbc633b39, 897}, - {0x976e4108, 0x8617ca01, 0xd5be0503, 901}, - {0xbd49d14a, 0xa79dbc82, 0x4b2d8644, 904}, - {0xec9c459d, 0x51852ba2, 0xddf8e7d6, 907}, - {0x93e1ab82, 0x52f33b45, 0xcabb90e5, 911}, - {0xb8da1662, 0xe7b00a17, 0x3d6a751f, 914}, - {0xe7109bfb, 0xa19c0c9d, 0x0cc51267, 917}, - {0x906a617d, 0x450187e2, 0x27fb2b80, 921}, - {0xb484f9dc, 0x9641e9da, 0xb1f9f660, 924}, - {0xe1a63853, 0xbbd26451, 0x5e7873f8, 927}, - {0x8d07e334, 0x55637eb2, 0xdb0b487b, 931}, - {0xb049dc01, 0x6abc5e5f, 0x91ce1a9a, 934}, - {0xdc5c5301, 0xc56b75f7, 0x7641a140, 937}, - {0x89b9b3e1, 0x1b6329ba, 0xa9e904c8, 941}, - {0xac2820d9, 0x623bf429, 0x546345fa, 944}, - {0xd732290f, 0xbacaf133, 0xa97c1779, 947}, - {0x867f59a9, 0xd4bed6c0, 0x49ed8eab, 951}, - {0xa81f3014, 0x49ee8c70, 0x5c68f256, 954}, - {0xd226fc19, 0x5c6a2f8c, 0x73832eec, 957}, - {0x83585d8f, 0xd9c25db7, 0xc831fd53, 961}, - {0xa42e74f3, 0xd032f525, 0xba3e7ca8, 964}, - {0xcd3a1230, 0xc43fb26f, 0x28ce1bd2, 967}, - {0x80444b5e, 0x7aa7cf85, 0x7980d163, 971}, - {0xa0555e36, 0x1951c366, 0xd7e105bc, 974}, - {0xc86ab5c3, 0x9fa63440, 0x8dd9472b, 977}, - {0xfa856334, 0x878fc150, 0xb14f98f6, 980}, - {0x9c935e00, 0xd4b9d8d2, 0x6ed1bf9a, 984}, - {0xc3b83581, 0x09e84f07, 0x0a862f80, 987}, - {0xf4a642e1, 0x4c6262c8, 0xcd27bb61, 990}, - {0x98e7e9cc, 0xcfbd7dbd, 0x8038d51c, 994}, - {0xbf21e440, 0x03acdd2c, 0xe0470a63, 997}, - {0xeeea5d50, 0x04981478, 0x1858ccfc, 1000}, - {0x95527a52, 0x02df0ccb, 0x0f37801e, 1004}, - {0xbaa718e6, 0x8396cffd, 0xd3056025, 1007}, - {0xe950df20, 0x247c83fd, 0x47c6b82e, 1010}, - {0x91d28b74, 0x16cdd27e, 0x4cdc331d, 1014}, - {0xb6472e51, 0x1c81471d, 0xe0133fe4, 1017}, - {0xe3d8f9e5, 0x63a198e5, 0x58180fdd, 1020}, - {0x8e679c2f, 0x5e44ff8f, 0x570f09ea, 1024}, - {0xb201833b, 0x35d63f73, 0x2cd2cc65, 1027}, - {0xde81e40a, 0x034bcf4f, 0xf8077f7e, 1030}, - {0x8b112e86, 0x420f6191, 0xfb04afaf, 1034}, - {0xadd57a27, 0xd29339f6, 0x79c5db9a, 1037}, - {0xd94ad8b1, 0xc7380874, 0x18375281, 1040}, - {0x87cec76f, 0x1c830548, 0x8f229391, 1044}, - {0xa9c2794a, 0xe3a3c69a, 0xb2eb3875, 1047}, - {0xd433179d, 0x9c8cb841, 0x5fa60692, 1050}, - {0x849feec2, 0x81d7f328, 0xdbc7c41b, 1054}, - {0xa5c7ea73, 0x224deff3, 0x12b9b522, 1057}, - {0xcf39e50f, 0xeae16bef, 0xd768226b, 1060}, - {0x81842f29, 0xf2cce375, 0xe6a11583, 1064}, - {0xa1e53af4, 0x6f801c53, 0x60495ae3, 1067}, - {0xca5e89b1, 0x8b602368, 0x385bb19c, 1070}, - {0xfcf62c1d, 0xee382c42, 0x46729e03, 1073}, - {0x9e19db92, 0xb4e31ba9, 0x6c07a2c2, 1077}}; -static const short int kDtoaLhint[2098] = { - /*18,*/ 19, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, - 22, 23, 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, - 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, - 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 33, - 33, 33, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, - 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 40, 40, - 40, 41, 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, - 44, 44, 44, 45, 45, 45, 46, 46, 46, 47, 47, 47, - 47, 48, 48, 48, 49, 49, 49, 50, 50, 50, 51, 51, - 51, 51, 52, 52, 52, 53, 53, 53, 54, 54, 54, 54, - 55, 55, 55, 56, 56, 56, 57, 57, 57, 57, 58, 58, - 58, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 62, - 62, 62, 63, 63, 63, 63, 64, 64, 64, 65, 65, 65, - 66, 66, 66, 66, 67, 67, 67, 68, 68, 68, 69, 69, - 69, 69, 70, 70, 70, 71, 71, 71, 72, 72, 72, 72, - 73, 73, 73, 74, 74, 74, 75, 75, 75, 75, 76, 76, - 76, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 80, - 80, 80, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, - 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 87, 87, - 87, 88, 88, 88, 88, 89, 89, 89, 90, 90, 90, 91, - 91, 91, 91, 92, 92, 92, 93, 93, 93, 94, 94, 94, - 94, 95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 98, - 98, 98, 99, 99, 99, 100, 100, 100, 100, 101, 101, 101, - 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 105, 105, - 105, 106, 106, 106, 106, 107, 107, 107, 108, 108, 108, 109, - 109, 109, 110, 110, 110, 110, 111, 111, 111, 112, 112, 112, - 113, 113, 113, 113, 114, 114, 114, 115, 115, 115, 116, 116, - 116, 116, 117, 117, 117, 118, 118, 118, 119, 119, 119, 119, - 120, 120, 120, 121, 121, 121, 122, 122, 122, 122, 123, 123, - 123, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, 127, - 127, 127, 128, 128, 128, 128, 129, 129, 129, 130, 130, 130, - 131, 131, 131, 131, 132, 132, 132, 133, 133, 133, 134, 134, - 134, 134, 135, 135, 135, 136, 136, 136, 137, 137, 137, 137, - 138, 138, 138, 139, 139, 139, 140, 140, 140, 141, 141, 141, - 141, 142, 142, 142, 143, 143, 143, 144, 144, 144, 144, 145, - 145, 145, 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, - 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, 152, 152, - 152, 153, 153, 153, 153, 154, 154, 154, 155, 155, 155, 156, - 156, 156, 156, 157, 157, 157, 158, 158, 158, 159, 159, 159, - 159, 160, 160, 160, 161, 161, 161, 162, 162, 162, 162, 163, - 163, 163, 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, - 167, 167, 167, 168, 168, 168, 169, 169, 169, 169, 170, 170, - 170, 171, 171, 171, 172, 172, 172, 172, 173, 173, 173, 174, - 174, 174, 175, 175, 175, 175, 176, 176, 176, 177, 177, 177, - 178, 178, 178, 178, 179, 179, 179, 180, 180, 180, 181, 181, - 181, 181, 182, 182, 182, 183, 183, 183, 184, 184, 184, 184, - 185, 185, 185, 186, 186, 186, 187, 187, 187, 187, 188, 188, - 188, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 192, - 192, 192, 193, 193, 193, 193, 194, 194, 194, 195, 195, 195, - 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 199, 199, - 199, 200, 200, 200, 200, 201, 201, 201, 202, 202, 202, 203, - 203, 203, 203, 204, 204, 204, 205, 205, 205, 206, 206, 206, - 206, 207, 207, 207, 208, 208, 208, 209, 209, 209, 209, 210, - 210, 210, 211, 211, 211, 212, 212, 212, 212, 213, 213, 213, - 214, 214, 214, 215, 215, 215, 215, 216, 216, 216, 217, 217, - 217, 218, 218, 218, 218, 219, 219, 219, 220, 220, 220, 221, - 221, 221, 221, 222, 222, 222, 223, 223, 223, 224, 224, 224, - 224, 225, 225, 225, 226, 226, 226, 227, 227, 227, 228, 228, - 228, 228, 229, 229, 229, 230, 230, 230, 231, 231, 231, 231, - 232, 232, 232, 233, 233, 233, 234, 234, 234, 234, 235, 235, - 235, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 239, - 239, 239, 240, 240, 240, 240, 241, 241, 241, 242, 242, 242, - 243, 243, 243, 243, 244, 244, 244, 245, 245, 245, 246, 246, - 246, 246, 247, 247, 247, 248, 248, 248, 249, 249, 249, 249, - 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, - 253, 254, 254, 254, 255, 255, 255, 256, 256, 256, 256, 257, - 257, 257, 258, 258, 258, 259, 259, 259, 259, 260, 260, 260, - 261, 261, 261, 262, 262, 262, 262, 263, 263, 263, 264, 264, - 264, 265, 265, 265, 265, 266, 266, 266, 267, 267, 267, 268, - 268, 268, 268, 269, 269, 269, 270, 270, 270, 271, 271, 271, - 271, 272, 272, 272, 273, 273, 273, 274, 274, 274, 274, 275, - 275, 275, 276, 276, 276, 277, 277, 277, 277, 278, 278, 278, - 279, 279, 279, 280, 280, 280, 280, 281, 281, 281, 282, 282, - 282, 283, 283, 283, 283, 284, 284, 284, 285, 285, 285, 286, - 286, 286, 287, 287, 287, 287, 288, 288, 288, 289, 289, 289, - 290, 290, 290, 290, 291, 291, 291, 292, 292, 292, 293, 293, - 293, 293, 294, 294, 294, 295, 295, 295, 296, 296, 296, 296, - 297, 297, 297, 298, 298, 298, 299, 299, 299, 299, 300, 300, - 300, 301, 301, 301, 302, 302, 302, 302, 303, 303, 303, 304, - 304, 304, 305, 305, 305, 305, 306, 306, 306, 307, 307, 307, - 308, 308, 308, 308, 309, 309, 309, 310, 310, 310, 311, 311, - 311, 311, 312, 312, 312, 313, 313, 313, 314, 314, 314, 315, - 315, 315, 315, 316, 316, 316, 317, 317, 317, 318, 318, 318, - 318, 319, 319, 319, 320, 320, 320, 321, 321, 321, 321, 322, - 322, 322, 323, 323, 323, 324, 324, 324, 324, 325, 325, 325, - 326, 326, 326, 327, 327, 327, 327, 328, 328, 328, 329, 329, - 329, 330, 330, 330, 330, 331, 331, 331, 332, 332, 332, 333, - 333, 333, 333, 334, 334, 334, 335, 335, 335, 336, 336, 336, - 336, 337, 337, 337, 338, 338, 338, 339, 339, 339, 339, 340, - 340, 340, 341, 341, 341, 342, 342, 342, 342, 343, 343, 343, - 344, 344, 344, 345, 345, 345, 346, 346, 346, 346, 347, 347, - 347, 348, 348, 348, 349, 349, 349, 349, 350, 350, 350, 351, - 351, 351, 352, 352, 352, 352, 353, 353, 353, 354, 354, 354, - 355, 355, 355, 355, 356, 356, 356, 357, 357, 357, 358, 358, - 358, 358, 359, 359, 359, 360, 360, 360, 361, 361, 361, 361, - 362, 362, 362, 363, 363, 363, 364, 364, 364, 364, 365, 365, - 365, 366, 366, 366, 367, 367, 367, 367, 368, 368, 368, 369, - 369, 369, 370, 370, 370, 370, 371, 371, 371, 372, 372, 372, - 373, 373, 373, 374, 374, 374, 374, 375, 375, 375, 376, 376, - 376, 377, 377, 377, 377, 378, 378, 378, 379, 379, 379, 380, - 380, 380, 380, 381, 381, 381, 382, 382, 382, 383, 383, 383, - 383, 384, 384, 384, 385, 385, 385, 386, 386, 386, 386, 387, - 387, 387, 388, 388, 388, 389, 389, 389, 389, 390, 390, 390, - 391, 391, 391, 392, 392, 392, 392, 393, 393, 393, 394, 394, - 394, 395, 395, 395, 395, 396, 396, 396, 397, 397, 397, 398, - 398, 398, 398, 399, 399, 399, 400, 400, 400, 401, 401, 401, - 402, 402, 402, 402, 403, 403, 403, 404, 404, 404, 405, 405, - 405, 405, 406, 406, 406, 407, 407, 407, 408, 408, 408, 408, - 409, 409, 409, 410, 410, 410, 411, 411, 411, 411, 412, 412, - 412, 413, 413, 413, 414, 414, 414, 414, 415, 415, 415, 416, - 416, 416, 417, 417, 417, 417, 418, 418, 418, 419, 419, 419, - 420, 420, 420, 420, 421, 421, 421, 422, 422, 422, 423, 423, - 423, 423, 424, 424, 424, 425, 425, 425, 426, 426, 426, 426, - 427, 427, 427, 428, 428, 428, 429, 429, 429, 429, 430, 430, - 430, 431, 431, 431, 432, 432, 432, 433, 433, 433, 433, 434, - 434, 434, 435, 435, 435, 436, 436, 436, 436, 437, 437, 437, - 438, 438, 438, 439, 439, 439, 439, 440, 440, 440, 441, 441, - 441, 442, 442, 442, 442, 443, 443, 443, 444, 444, 444, 445, - 445, 445, 445, 446, 446, 446, 447, 447, 447, 448, 448, 448, - 448, 449, 449, 449, 450, 450, 450, 451, 451, 451, 451, 452, - 452, 452, 453, 453, 453, 454, 454, 454, 454, 455, 455, 455, - 456, 456, 456, 457, 457, 457, 457, 458, 458, 458, 459, 459, - 459, 460, 460, 460, 461, 461, 461, 461, 462, 462, 462, 463, - 463, 463, 464, 464, 464, 464, 465, 465, 465, 466, 466, 466, - 467, 467, 467, 467, 468, 468, 468, 469, 469, 469, 470, 470, - 470, 470, 471, 471, 471, 472, 472, 472, 473, 473, 473, 473, - 474, 474, 474, 475, 475, 475, 476, 476, 476, 476, 477, 477, - 477, 478, 478, 478, 479, 479, 479, 479, 480, 480, 480, 481, - 481, 481, 482, 482, 482, 482, 483, 483, 483, 484, 484, 484, - 485, 485, 485, 485, 486, 486, 486, 487, 487, 487, 488, 488, - 488, 488, 489, 489, 489, 490, 490, 490, 491, 491, 491, 492, - 492, 492, 492, 493, 493, 493, 494, 494, 494, 495, 495, 495, - 495, 496, 496, 496, 497, 497, 497, 498, 498, 498, 498, 499, - 499, 499, 500, 500, 500, 501, 501, 501, 501, 502, 502, 502, - 503, 503, 503, 504, 504, 504, 504, 505, 505, 505, 506, 506, - 506, 507, 507, 507, 507, 508, 508, 508, 509, 509, 509, 510, - 510, 510, 510, 511, 511, 511, 512, 512, 512, 513, 513, 513, - 513, 514, 514, 514, 515, 515, 515, 516, 516, 516, 516, 517, - 517, 517, 518, 518, 518, 519, 519, 519, 520, 520, 520, 520, - 521, 521, 521, 522, 522, 522, 523, 523, 523, 523, 524, 524, - 524, 525, 525, 525, 526, 526, 526, 526, 527, 527, 527, 528, - 528, 528, 529, 529, 529, 529, 530, 530, 530, 531, 531, 531, - 532, 532, 532, 532, 533, 533, 533, 534, 534, 534, 535, 535, - 535, 535, 536, 536, 536, 537, 537, 537, 538, 538, 538, 538, - 539, 539, 539, 540, 540, 540, 541, 541, 541, 541, 542, 542, - 542, 543, 543, 543, 544, 544, 544, 544, 545, 545, 545, 546, - 546, 546, 547, 547, 547, 548, 548, 548, 548, 549, 549, 549, - 550, 550, 550, 551, 551, 551, 551, 552, 552, 552, 553, 553, - 553, 554, 554, 554, 554, 555, 555, 555, 556, 556, 556, 557, - 557, 557, 557, 558, 558, 558, 559, 559, 559, 560, 560, 560, - 560, 561, 561, 561, 562, 562, 562, 563, 563, 563, 563, 564, - 564, 564, 565, 565, 565, 566, 566, 566, 566, 567, 567, 567, - 568, 568, 568, 569, 569, 569, 569, 570, 570, 570, 571, 571, - 571, 572, 572, 572, 572, 573, 573, 573, 574, 574, 574, 575, - 575, 575, 575, 576, 576, 576, 577, 577, 577, 578, 578, 578, - 579, 579, 579, 579, 580, 580, 580, 581, 581, 581, 582, 582, - 582, 582, 583, 583, 583, 584, 584, 584, 585, 585, 585, 585, - 586, 586, 586, 587, 587, 587, 588, 588, 588, 588, 589, 589, - 589, 590, 590, 590, 591, 591, 591, 591, 592, 592, 592, 593, - 593, 593, 594, 594, 594, 594, 595, 595, 595, 596, 596, 596, - 597, 597, 597, 597, 598, 598, 598, 599, 599, 599, 600, 600, - 600, 600, 601, 601, 601, 602, 602, 602, 603, 603, 603, 603, - 604, 604, 604, 605, 605, 605, 606, 606, 606, 607, 607, 607, - 607, 608, 608, 608, 609, 609, 609, 610, 610, 610, 610, 611, - 611, 611, 612, 612, 612, 613, 613, 613, 613, 614, 614, 614, - 615, 615, 615, 616, 616, 616, 616, 617, 617, 617, 618, 618, - 618, 619, 619, 619, 619, 620, 620, 620, 621, 621, 621, 622, - 622, 622, 622, 623, 623, 623, 624, 624, 624, 625, 625, 625, - 625, 626, 626, 626, 627, 627, 627, 628, 628, 628, 628, 629, - 629, 629, 630, 630, 630, 631, 631, 631, 631, 632, 632, 632, - 633, 633, 633, 634, 634, 634, 634, 635, 635, 635, 636, 636, - 636, 637, 637, 637, 638, 638, 638, 638, 639, 639, 639, 640, - 640, 640, 641, 641, 641, 641, 642, 642, 642, 643, 643, 643, - 644, 644, 644, 644, 645, 645, 645, 646, 646, 646, 647, 647, - 647, 647, 648, 648, 648, 649, 649, 649, 650, 650}; -static ULLong kDtoaPfive[27] = {5ll, - 25ll, - 125ll, - 625ll, - 3125ll, - 15625ll, - 78125ll, - 390625ll, - 1953125ll, - 9765625ll, - 48828125ll, - 244140625ll, - 1220703125ll, - 6103515625ll, - 30517578125ll, - 152587890625ll, - 762939453125ll, - 3814697265625ll, - 19073486328125ll, - 95367431640625ll, - 476837158203125ll, - 2384185791015625ll, - 11920928955078125ll, - 59604644775390625ll, - 298023223876953125ll, - 1490116119384765625ll, - 7450580596923828125ll}; - -static int kDtoaPfiveBits[25] = {3, 5, 7, 10, 12, 14, 17, 19, 21, - 24, 26, 28, 31, 33, 35, 38, 40, 42, - 45, 47, 49, 52, 54, 56, 59}; -#endif /*}*/ -#endif /*}} NO_LONG_LONG */ - - typedef union { - double d; - ULong L[2]; -#ifdef USE_BF96 - ULLong LL; -#endif -} U; - -#ifdef IEEE_8087 -#define word0(x) (x)->L[1] -#define word1(x) (x)->L[0] -#else -#define word0(x) (x)->L[0] -#define word1(x) (x)->L[1] -#endif -#define dval(x) (x)->d -#define LLval(x) (x)->LL - -#ifndef STRTOD_DIGLIM -#define STRTOD_DIGLIM 40 -#endif - -#ifdef DIGLIM_DEBUG -extern int strtod_diglim; -#else -#define strtod_diglim STRTOD_DIGLIM -#endif - -/* The following definition of Storeinc is appropriate for MIPS processors. - * An alternative that might be better on some machines is - * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) - */ -#if defined(IEEE_8087) + defined(VAX) -#define Storeinc(a, b, c) \ - (((unsigned short *)a)[1] = (unsigned short)b, \ - ((unsigned short *)a)[0] = (unsigned short)c, a++) -#else -#define Storeinc(a, b, c) \ - (((unsigned short *)a)[0] = (unsigned short)b, \ - ((unsigned short *)a)[1] = (unsigned short)c, a++) -#endif - -/* #define P DBL_MANT_DIG */ -/* Ten_pmax = floor(P*log(2)/log(5)) */ -/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ -/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ -/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ - -#ifdef IEEE_Arith -#define Exp_shift 20 -#define Exp_shift1 20 -#define Exp_msk1 0x100000 -#define Exp_msk11 0x100000 -#define Exp_mask 0x7ff00000 -#define P 53 -#define Nbits 53 -#define Bias 1023 -#define Emax 1023 -#define Emin (-1022) -#define Exp_1 0x3ff00000 -#define Exp_11 0x3ff00000 -#define Ebits 11 -#define Frac_mask 0xfffff -#define Frac_mask1 0xfffff -#define Ten_pmax 22 -#define Bletch 0x10 -#define Bndry_mask 0xfffff -#define Bndry_mask1 0xfffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 1 -#define Tiny0 0 -#define Tiny1 1 -#define Quick_max 14 -#define Int_max 14 -#ifndef NO_IEEE_Scale -#define Avoid_Underflow -#ifdef Flush_Denorm /* debugging option */ -#undef Sudden_Underflow -#endif -#endif - -#ifndef Flt_Rounds -#ifdef FLT_ROUNDS -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /*Flt_Rounds*/ - -#ifdef Honor_FLT_ROUNDS -#undef Check_FLT_ROUNDS -#define Check_FLT_ROUNDS -#else -#define Rounding Flt_Rounds -#endif - -#else /* ifndef IEEE_Arith */ -#undef Check_FLT_ROUNDS -#undef Honor_FLT_ROUNDS -#undef SET_INEXACT -#undef Sudden_Underflow -#define Sudden_Underflow -#ifdef IBM -#undef Flt_Rounds -#define Flt_Rounds 0 -#define Exp_shift 24 -#define Exp_shift1 24 -#define Exp_msk1 0x1000000 -#define Exp_msk11 0x1000000 -#define Exp_mask 0x7f000000 -#define P 14 -#define Nbits 56 -#define Bias 65 -#define Emax 248 -#define Emin (-260) -#define Exp_1 0x41000000 -#define Exp_11 0x41000000 -#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ -#define Frac_mask 0xffffff -#define Frac_mask1 0xffffff -#define Bletch 4 -#define Ten_pmax 22 -#define Bndry_mask 0xefffff -#define Bndry_mask1 0xffffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 4 -#define Tiny0 0x100000 -#define Tiny1 0 -#define Quick_max 14 -#define Int_max 15 -#else /* VAX */ -#undef Flt_Rounds -#define Flt_Rounds 1 -#define Exp_shift 23 -#define Exp_shift1 7 -#define Exp_msk1 0x80 -#define Exp_msk11 0x800000 -#define Exp_mask 0x7f80 -#define P 56 -#define Nbits 56 -#define Bias 129 -#define Emax 126 -#define Emin (-129) -#define Exp_1 0x40800000 -#define Exp_11 0x4080 -#define Ebits 8 -#define Frac_mask 0x7fffff -#define Frac_mask1 0xffff007f -#define Ten_pmax 24 -#define Bletch 2 -#define Bndry_mask 0xffff007f -#define Bndry_mask1 0xffff007f -#define LSB 0x10000 -#define Sign_bit 0x8000 -#define Log2P 1 -#define Tiny0 0x80 -#define Tiny1 0 -#define Quick_max 15 -#define Int_max 15 -#endif /* IBM, VAX */ -#endif /* IEEE_Arith */ - -#ifndef IEEE_Arith -#define ROUND_BIASED -#else -#ifdef ROUND_BIASED_without_Round_Up -#undef ROUND_BIASED -#define ROUND_BIASED -#endif -#endif - -#ifdef RND_PRODQUOT -#define rounded_product(a, b) a = rnd_prod(a, b) -#define rounded_quotient(a, b) a = rnd_quot(a, b) -extern double rnd_prod(double, double), rnd_quot(double, double); -#else -#define rounded_product(a, b) a *= b -#define rounded_quotient(a, b) a /= b -#endif - -#define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) -#define Big1 0xffffffff - -#ifndef Pack_32 -#define Pack_32 -#endif - -typedef struct BCinfo BCinfo; -struct BCinfo { - int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; -}; - -#define FFFFFFFF 0xffffffffUL - -#ifdef MULTIPLE_THREADS -#define MTa , PTI -#define MTb , &TI -#define MTd , ThInfo **PTI -static unsigned int maxthreads = 0; -#else -#define MTa /*nothing*/ -#define MTb /*nothing*/ -#define MTd /*nothing*/ -#endif - -#define Kmax 7 - -#ifdef __cplusplus -extern "C" double(strtod)(const char *s00, char **se); -extern "C" char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, - char **rve); -#endif - -struct Bigint { - struct Bigint *next; - int k, maxwds, sign, wds; - ULong x[1]; -}; - -typedef struct Bigint Bigint; -typedef struct ThInfo { - Bigint *Freelist[Kmax + 1]; - Bigint *P5s; -} ThInfo; - -static ThInfo TI0; - -#ifdef MULTIPLE_THREADS -static ThInfo *TI1; -static int TI0_used; - -void set_max_dtoa_threads(unsigned int n) { - size_t L; - - if (n > maxthreads) { - L = n * sizeof(ThInfo); - if (TI1) { - TI1 = (ThInfo *)REALLOC(TI1, L); - memset(TI1 + maxthreads, 0, (n - maxthreads) * sizeof(ThInfo)); - } else { - TI1 = (ThInfo *)MALLOC(L); - if (TI0_used) { - memcpy(TI1, &TI0, sizeof(ThInfo)); - if (n > 1) memset(TI1 + 1, 0, L - sizeof(ThInfo)); - memset(&TI0, 0, sizeof(ThInfo)); - } else - memset(TI1, 0, L); - } - maxthreads = n; - } -} - -static ThInfo *get_TI(void) { - unsigned int thno = dtoa_get_threadno(); - if (thno < maxthreads) return TI1 + thno; - if (thno == 0) TI0_used = 1; - return &TI0; -} -#define freelist TI->Freelist -#define p5s TI->P5s -#else -#define freelist TI0.Freelist -#define p5s TI0.P5s -#endif - -static Bigint *dtoa_balloc(int k MTd) { - int x; - Bigint *rv; -#ifndef Omit_Private_Memory - unsigned int len; -#endif -#ifdef MULTIPLE_THREADS - ThInfo *TI; - - if (!(TI = *PTI)) *PTI = TI = get_TI(); - if (TI == &TI0) ACQUIRE_DTOA_LOCK(0); -#endif - /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ - /* but this case seems very unlikely. */ - if (k <= Kmax && (rv = freelist[k])) - freelist[k] = rv->next; - else { - x = 1u << k; -#ifdef Omit_Private_Memory - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x - 1) * sizeof(ULong)); -#else - len = (sizeof(Bigint) + (x - 1) * sizeof(ULong) + sizeof(double) - 1) / - sizeof(double); - if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem -#ifdef MULTIPLE_THREADS - && TI == TI1 -#endif - ) { - rv = (Bigint *)pmem_next; - pmem_next += len; - } else - rv = (Bigint *)MALLOC(len * sizeof(double)); -#endif - rv->k = k; - rv->maxwds = x; - } -#ifdef MULTIPLE_THREADS - if (TI == &TI0) FREE_DTOA_LOCK(0); -#endif - rv->sign = rv->wds = 0; - return rv; -} - -static void dtoa_bfree(Bigint *v MTd) { -#ifdef MULTIPLE_THREADS - ThInfo *TI; -#endif - if (v) { - if (v->k > Kmax) - FREE((void *)v); - else { -#ifdef MULTIPLE_THREADS - if (!(TI = *PTI)) *PTI = TI = get_TI(); - if (TI == &TI0) ACQUIRE_DTOA_LOCK(0); -#endif - v->next = freelist[v->k]; - freelist[v->k] = v; -#ifdef MULTIPLE_THREADS - if (TI == &TI0) FREE_DTOA_LOCK(0); -#endif - } - } -} - -#define Bcopy(x, y) \ - memcpy((char *)&x->sign, (char *)&y->sign, \ - y->wds * sizeof(Long) + 2 * sizeof(int)) - -static Bigint *dtoa_multadd(Bigint *b, int m, - int a MTd) /* multiply by m and add a */ -{ - int i, wds; -#ifdef ULLong - ULong *x; - ULLong carry, y; -#else - ULong carry, *x, y; -#ifdef Pack_32 - ULong xi, z; -#endif -#endif - Bigint *b1; - - wds = b->wds; - x = b->x; - i = 0; - carry = a; - do { -#ifdef ULLong - y = *x * (ULLong)m + carry; - carry = y >> 32; - *x++ = y & FFFFFFFF; -#else -#ifdef Pack_32 - xi = *x; - y = (xi & 0xffff) * m + carry; - z = (xi >> 16) * m + (y >> 16); - carry = z >> 16; - *x++ = (z << 16) + (y & 0xffff); -#else - y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif -#endif - } while (++i < wds); - if (carry) { - if (wds >= b->maxwds) { - b1 = dtoa_balloc(b->k + 1 MTa); - Bcopy(b1, b); - dtoa_bfree(b MTa); - b = b1; - } - b->x[wds++] = carry; - b->wds = wds; - } - return b; -} - -static Bigint *s2b(const char *s, int nd0, int nd, ULong y9, int dplen MTd) { - Bigint *b; - int i, k; - Long x, y; - - x = (nd + 8) / 9; - for (k = 0, y = 1; x > y; y <<= 1, k++) - ; -#ifdef Pack_32 - b = dtoa_balloc(k MTa); - b->x[0] = y9; - b->wds = 1; -#else - b = dtoa_balloc(k + 1 MTa); - b->x[0] = y9 & 0xffff; - b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; -#endif - - i = 9; - if (9 < nd0) { - s += 9; - do - b = dtoa_multadd(b, 10, *s++ - '0' MTa); - while (++i < nd0); - s += dplen; - } else - s += dplen + 9; - for (; i < nd; i++) b = dtoa_multadd(b, 10, *s++ - '0' MTa); - return b; -} - -static int dtoa_hi0bits(ULong x) { - int k = 0; - - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; - } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) return 32; - } - return k; -} - -static int dtoa_lo0bits(ULong *y) { - int k; - ULong x = *y; - - if (x & 7) { - if (x & 1) return 0; - if (x & 2) { - *y = x >> 1; - return 1; - } - *y = x >> 2; - return 2; - } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x) return 32; - } - *y = x; - return k; -} - -static Bigint *dtoa_i2b(int i MTd) { - Bigint *b; - - b = dtoa_balloc(1 MTa); - b->x[0] = i; - b->wds = 1; - return b; -} - -static Bigint *dtoa_mult(Bigint *a, Bigint *b MTd) { - Bigint *c; - int k, wa, wb, wc; - ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; - ULong y; -#ifdef ULLong - ULLong carry, z; -#else - ULong carry, z; -#ifdef Pack_32 - ULong z2; -#endif -#endif - - if (a->wds < b->wds) { - c = a; - a = b; - b = c; - } - k = a->k; - wa = a->wds; - wb = b->wds; - wc = wa + wb; - if (wc > a->maxwds) k++; - c = dtoa_balloc(k MTa); - for (x = c->x, xa = x + wc; x < xa; x++) *x = 0; - xa = a->x; - xae = xa + wa; - xb = b->x; - xbe = xb + wb; - xc0 = c->x; -#ifdef ULLong - for (; xb < xbe; xc0++) { - if ((y = *xb++)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * (ULLong)y + *xc + carry; - carry = z >> 32; - *xc++ = z & FFFFFFFF; - } while (x < xae); - *xc = carry; - } - } -#else -#ifdef Pack_32 - for (; xb < xbe; xb++, xc0++) { - if (y = *xb & 0xffff) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } while (x < xae); - *xc = carry; - } - if (y = *xb >> 16) { - x = xa; - xc = xc0; - carry = 0; - z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } while (x < xae); - *xc = z2; - } - } -#else - for (; xb < xbe; xc0++) { - if (y = *xb++) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } while (x < xae); - *xc = carry; - } - } -#endif -#endif - for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) - ; - c->wds = wc; - return c; -} - -static Bigint *dtoa_pow5mult(Bigint *b, int k MTd) { - Bigint *b1, *p5, *p51; -#ifdef MULTIPLE_THREADS - ThInfo *TI; -#endif - int i; - static int p05[3] = {5, 25, 125}; - - if ((i = k & 3)) b = dtoa_multadd(b, p05[i - 1], 0 MTa); - - if (!(k >>= 2)) return b; -#ifdef MULTIPLE_THREADS - if (!(TI = *PTI)) *PTI = TI = get_TI(); -#endif - if (!(p5 = p5s)) { - /* first time */ -#ifdef MULTIPLE_THREADS - if (!(TI = *PTI)) *PTI = TI = get_TI(); - if (TI == &TI0) ACQUIRE_DTOA_LOCK(1); - if (!(p5 = p5s)) { - p5 = p5s = dtoa_i2b(625 MTa); - p5->next = 0; - } - if (TI == &TI0) FREE_DTOA_LOCK(1); -#else - p5 = p5s = dtoa_i2b(625 MTa); - p5->next = 0; -#endif - } - for (;;) { - if (k & 1) { - b1 = dtoa_mult(b, p5 MTa); - dtoa_bfree(b MTa); - b = b1; - } - if (!(k >>= 1)) break; - if (!(p51 = p5->next)) { -#ifdef MULTIPLE_THREADS - if (!TI && !(TI = *PTI)) *PTI = TI = get_TI(); - if (TI == &TI0) ACQUIRE_DTOA_LOCK(1); - if (!(p51 = p5->next)) { - p51 = p5->next = dtoa_mult(p5, p5 MTa); - p51->next = 0; - } - if (TI == &TI0) FREE_DTOA_LOCK(1); -#else - p51 = p5->next = dtoa_mult(p5, p5); - p51->next = 0; -#endif - } - p5 = p51; - } - return b; -} - -static Bigint *dtoa_lshift(Bigint *b, int k MTd) { - int i, k1, n, n1; - Bigint *b1; - ULong *x, *x1, *xe, z; - -#ifdef Pack_32 - n = k >> 5; -#else - n = k >> 4; -#endif - k1 = b->k; - n1 = n + b->wds + 1; - for (i = b->maxwds; n1 > i; i <<= 1) k1++; - b1 = dtoa_balloc(k1 MTa); - x1 = b1->x; - for (i = 0; i < n; i++) *x1++ = 0; - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - if (k &= 0x1f) { - k1 = 32 - k; - z = 0; - do { - *x1++ = *x << k | z; - z = *x++ >> k1; - } while (x < xe); - if ((*x1 = z)) ++n1; - } -#else - if (k &= 0xf) { - k1 = 16 - k; - z = 0; - do { - *x1++ = *x << k & 0xffff | z; - z = *x++ >> k1; - } while (x < xe); - if (*x1 = z) ++n1; - } -#endif - else - do - *x1++ = *x++; - while (x < xe); - b1->wds = n1 - 1; - dtoa_bfree(b MTa); - return b1; -} - -static int dtoa_cmp(Bigint *a, Bigint *b) { - ULong *xa, *xa0, *xb, *xb0; - int i, j; - - i = a->wds; - j = b->wds; -#ifdef DEBUG - if (i > 1 && !a->x[i - 1]) Bug("dtoa_cmp called with a->x[a->wds-1] == 0"); - if (j > 1 && !b->x[j - 1]) Bug("dtoa_cmp called with b->x[b->wds-1] == 0"); -#endif - if (i -= j) return i; - xa0 = a->x; - xa = xa0 + j; - xb0 = b->x; - xb = xb0 + j; - for (;;) { - if (*--xa != *--xb) return *xa < *xb ? -1 : 1; - if (xa <= xa0) break; - } - return 0; -} - -static Bigint *dtoa_diff(Bigint *a, Bigint *b MTd) { - Bigint *c; - int i, wa, wb; - ULong *xa, *xae, *xb, *xbe, *xc; -#ifdef ULLong - ULLong borrow, y; -#else - ULong borrow, y; -#ifdef Pack_32 - ULong z; -#endif -#endif - - i = dtoa_cmp(a, b); - if (!i) { - c = dtoa_balloc(0 MTa); - c->wds = 1; - c->x[0] = 0; - return c; - } - if (i < 0) { - c = a; - a = b; - b = c; - i = 1; - } else - i = 0; - c = dtoa_balloc(a->k MTa); - c->sign = i; - wa = a->wds; - xa = a->x; - xae = xa + wa; - wb = b->wds; - xb = b->x; - xbe = xb + wb; - xc = c->x; - borrow = 0; -#ifdef ULLong - do { - y = (ULLong)*xa++ - *xb++ - borrow; - borrow = y >> 32 & (ULong)1; - *xc++ = y & FFFFFFFF; - } while (xb < xbe); - while (xa < xae) { - y = *xa++ - borrow; - borrow = y >> 32 & (ULong)1; - *xc++ = y & FFFFFFFF; - } -#else -#ifdef Pack_32 - do { - y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } while (xb < xbe); - while (xa < xae) { - y = (*xa & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } while (xb < xbe); - while (xa < xae) { - y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif -#endif - while (!*--xc) wa--; - c->wds = wa; - return c; -} - -static double ulp(U *x) { - Long L; - U u; - - L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#endif -#ifdef IBM - L |= Exp_msk1 >> 4; -#endif - word0(&u) = L; - word1(&u) = 0; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - } else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(&u) = 0x80000 >> L; - word1(&u) = 0; - } else { - word0(&u) = 0; - L -= Exp_shift; - word1(&u) = L >= 31 ? 1 : 1 << 31 - L; - } - } -#endif -#endif - return dval(&u); -} - -static double dtoa_b2d(Bigint *a, int *e) { - ULong *xa, *xa0, w, y, z; - int k; - U d; -#ifdef VAX - ULong d0, d1; -#else -#define d0 word0(&d) -#define d1 word1(&d) -#endif - - xa0 = a->x; - xa = xa0 + a->wds; - y = *--xa; -#ifdef DEBUG - if (!y) Bug("zero y in dtoa_b2d"); -#endif - k = dtoa_hi0bits(y); - *e = 32 - k; -#ifdef Pack_32 - if (k < Ebits) { - d0 = Exp_1 | y >> (Ebits - k); - w = xa > xa0 ? *--xa : 0; - d1 = y << ((32 - Ebits) + k) | w >> (Ebits - k); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - d0 = Exp_1 | y << k | z >> (32 - k); - y = xa > xa0 ? *--xa : 0; - d1 = z << k | y >> (32 - k); - } else { - d0 = Exp_1 | y; - d1 = z; - } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif -ret_d: -#ifdef VAX - word0(&d) = d0 >> 16 | d0 << 16; - word1(&d) = d1 >> 16 | d1 << 16; -#else -#undef d0 -#undef d1 -#endif - return dval(&d); -} - -static Bigint *dtoa_d2b(U *d, int *e, int *bits MTd) { - Bigint *b; - int de, k; - ULong *x, y, z; -#ifndef Sudden_Underflow - int i; -#endif -#ifdef VAX - ULong d0, d1; - d0 = word0(d) >> 16 | word0(d) << 16; - d1 = word1(d) >> 16 | word1(d) << 16; -#else -#define d0 word0(d) -#define d1 word1(d) -#endif - -#ifdef Pack_32 - b = dtoa_balloc(1 MTa); -#else - b = dtoa_balloc(2 MTa); -#endif - x = b->x; - - z = d0 & Frac_mask; - d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#ifndef IBM - z |= Exp_msk11; -#endif -#else - if ((de = (int)(d0 >> Exp_shift))) z |= Exp_msk1; -#endif -#ifdef Pack_32 - if ((y = d1)) { - if ((k = dtoa_lo0bits(&y))) { - x[0] = y | z << (32 - k); - z >>= k; - } else - x[0] = y; -#ifndef Sudden_Underflow - i = -#endif - b->wds = (x[1] = z) ? 2 : 1; - } else { - k = dtoa_lo0bits(&z); - x[0] = z; -#ifndef Sudden_Underflow - i = -#endif - b->wds = 1; - k += 32; - } -#else - if (y = d1) { - if (k = dtoa_lo0bits(&y)) - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k + 16; - i = 3; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } else { -#ifdef DEBUG - if (!z) Bug("Zero passed to dtoa_d2b"); -#endif - k = dtoa_lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } - while (!x[i]) --i; - b->wds = i + 1; -#endif -#ifndef Sudden_Underflow - if (de) { -#endif -#ifdef IBM - *e = (de - Bias - (P - 1) << 2) + k; - *bits = 4 * P + 8 - k - dtoa_hi0bits(word0(d) & Frac_mask); -#else - *e = de - Bias - (P - 1) + k; - *bits = P - k; -#endif -#ifndef Sudden_Underflow - } else { - *e = de - Bias - (P - 1) + 1 + k; -#ifdef Pack_32 - *bits = 32 * i - dtoa_hi0bits(x[i - 1]); -#else - *bits = (i + 2) * 16 - dtoa_hi0bits(x[i]); -#endif - } -#endif - return b; -} -#undef d0 -#undef d1 - -static double dtoaratio(Bigint *a, Bigint *b) { - U da, db; - int k, ka, kb; - - dval(&da) = dtoa_b2d(a, &ka); - dval(&db) = dtoa_b2d(b, &kb); -#ifdef Pack_32 - k = ka - kb + 32 * (a->wds - b->wds); -#else - k = ka - kb + 16 * (a->wds - b->wds); -#endif -#ifdef IBM - if (k > 0) { - word0(&da) += (k >> 2) * Exp_msk1; - if (k &= 3) dval(&da) *= 1u << k; - } else { - k = -k; - word0(&db) += (k >> 2) * Exp_msk1; - if (k &= 3) dval(&db) *= 1u << k; - } -#else - if (k > 0) - word0(&da) += k * Exp_msk1; - else { - k = -k; - word0(&db) += k * Exp_msk1; - } -#endif - return dval(&da) / dval(&db); -} - -static const double kDtoaTens[] = {1e0, - 1e1, - 1e2, - 1e3, - 1e4, - 1e5, - 1e6, - 1e7, - 1e8, - 1e9, - 1e10, - 1e11, - 1e12, - 1e13, - 1e14, - 1e15, - 1e16, - 1e17, - 1e18, - 1e19, - 1e20, - 1e21, - 1e22 -#ifdef VAX - , - 1e23, - 1e24 -#endif -}; - -static const double -#ifdef IEEE_Arith - kDtoaBigTens[] = {1e16, 1e32, 1e64, 1e128, 1e256}; -static const double kDtoaTinyTens[] = { - 1e-16, 1e-32, 1e-64, 1e-128, -#ifdef Avoid_Underflow - 9007199254740992. * 9007199254740992.e-256 -/* = 2^106 * 1e-256 */ -#else - 1e-256 -#endif -}; -/* The factor of 2^53 in kDtoaTinyTens[4] helps us avoid setting the underflow - */ -/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ -#define Scale_Bit 0x10 -#define n_bigtens 5 -#else -#ifdef IBM - kDtoaBigTens[] = {1e16, 1e32, 1e64}; -static const double kDtoaTinyTens[] = {1e-16, 1e-32, 1e-64}; -#define n_bigtens 3 -#else - kDtoaBigTens[] = {1e16, 1e32}; -static const double kDtoaTinyTens[] = {1e-16, 1e-32}; -#define n_bigtens 2 -#endif -#endif - -#undef Need_Hexdig -#ifdef INFNAN_CHECK -#ifndef No_Hex_NaN -#define Need_Hexdig -#endif -#endif - -#ifndef Need_Hexdig -#ifndef NO_HEX_FP -#define Need_Hexdig -#endif -#endif - -#ifdef Need_Hexdig /*{*/ -#if 0 -static unsigned char hexdig[256]; - - static void -htinit(unsigned char *h, unsigned char *s, int inc) -{ - int i, j; - for(i = 0; (j = s[i]) !=0; i++) - h[j] = i + inc; - } - - static void -hexdig_init(void) /* Use of hexdig_init omitted 20121220 to avoid a */ - /* race condition when multiple threads are used. */ -{ -#define USC (unsigned char *) - htinit(hexdig, USC "0123456789", 0x10); - htinit(hexdig, USC "abcdef", 0x10 + 10); - htinit(hexdig, USC "ABCDEF", 0x10 + 10); - } -#else -static unsigned char kDtoaHexdig[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 0, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 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, 26, 27, 28, 29, 30, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0}; -#endif -#endif /* } Need_Hexdig */ - -#ifdef INFNAN_CHECK - -#ifndef NAN_WORD0 -#define NAN_WORD0 0x7ff80000 -#endif - -#ifndef NAN_WORD1 -#define NAN_WORD1 0 -#endif - -static int dtoa_match(const char **sp, const char *t) { - int c, d; - const char *s = *sp; - - while ((d = *t++)) { - if ((c = *++s) >= 'A' && c <= 'Z') c += 'a' - 'A'; - if (c != d) return 0; - } - *sp = s + 1; - return 1; -} - -#ifndef No_Hex_NaN -static void dtoa_hexnan(U *rvp, const char **sp) { - ULong c, x[2]; - const char *s; - int c1, havedig, udx0, xshift; - - /**** if (!hexdig['0']) hexdig_init(); ****/ - x[0] = x[1] = 0; - havedig = xshift = 0; - udx0 = 1; - s = *sp; - /* allow optional initial 0x or 0X */ - while ((c = *(const unsigned char *)(s + 1)) && c <= ' ') ++s; - if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) s += 2; - while ((c = *(const unsigned char *)++s)) { - if ((c1 = kDtoaHexdig[c])) - c = c1 & 0xf; - else if (c <= ' ') { - if (udx0 && havedig) { - udx0 = 0; - xshift = 1; - } - continue; - } -#ifdef GDTOA_NON_PEDANTIC_NANCHECK - else if (/*(*/ c == ')' && havedig) { - *sp = s + 1; - break; - } else - return; /* invalid form: don't change *sp */ -#else - else { - do { - if (/*(*/ c == ')') { - *sp = s + 1; - break; - } - } while ((c = *++s)); - break; - } -#endif - havedig = 1; - if (xshift) { - xshift = 0; - x[0] = x[1]; - x[1] = 0; - } - if (udx0) x[0] = (x[0] << 4) | (x[1] >> 28); - x[1] = (x[1] << 4) | c; - } - if ((x[0] &= 0xfffff) || x[1]) { - word0(rvp) = Exp_mask | x[0]; - word1(rvp) = x[1]; - } -} -#endif /*No_Hex_NaN*/ -#endif /* INFNAN_CHECK */ - -#ifdef Pack_32 -#define ULbits 32 -#define kshift 5 -#define kmask 31 -#else -#define ULbits 16 -#define kshift 4 -#define kmask 15 -#endif - -#if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/ -static Bigint *increment(Bigint *b MTd) { - ULong *x, *xe; - Bigint *b1; - - x = b->x; - xe = x + b->wds; - do { - if (*x < (ULong)0xffffffffL) { - ++*x; - return b; - } - *x++ = 0; - } while (x < xe); - { - if (b->wds >= b->maxwds) { - b1 = dtoa_balloc(b->k + 1 MTa); - Bcopy(b1, b); - dtoa_bfree(b MTa); - b = b1; - } - b->x[b->wds++] = 1; - } - return b; -} - -#endif /*}*/ - -#ifndef NO_HEX_FP /*{*/ - -static void dtoa_rshift(Bigint *b, int k) { - ULong *x, *x1, *xe, y; - int n; - - x = x1 = b->x; - n = k >> kshift; - if (n < b->wds) { - xe = x + b->wds; - x += n; - if (k &= kmask) { - n = 32 - k; - y = *x++ >> k; - while (x < xe) { - *x1++ = (y | (*x << n)) & 0xffffffff; - y = *x++ >> k; - } - if ((*x1 = y) != 0) x1++; - } else - while (x < xe) *x1++ = *x++; - } - if ((b->wds = x1 - b->x) == 0) b->x[0] = 0; -} - -static ULong dtoa_any_on(Bigint *b, int k) { - int n, nwds; - ULong *x, *x0, x1, x2; - - x = b->x; - nwds = b->wds; - n = k >> kshift; - if (n > nwds) - n = nwds; - else if (n < nwds && (k &= kmask)) { - x1 = x2 = x[n]; - x1 >>= k; - x1 <<= k; - if (x1 != x2) return 1; - } - x0 = x; - x += n; - while (x > x0) - if (*--x) return 1; - return 0; -} - -enum { /* rounding values: same as FLT_ROUNDS */ - Round_zero = 0, - Round_near = 1, - Round_up = 2, - Round_down = 3 -}; - -static void gethex(const char **sp, U *rvp, int rounding, int sign MTd) { - Bigint *b; - const unsigned char *decpt, *s0, *s, *s1; - Long e, e1; - ULong L, lostbits, *x; - int big, denorm, esign, havedig, k, n, nbits, up, zret; -#ifdef IBM - int j; -#endif - enum { -#ifdef IEEE_Arith /*{{*/ - emax = 0x7fe - Bias - P + 1, - emin = Emin - P + 1 -#else /*}{*/ - emin = Emin - P, -#ifdef VAX - emax = 0x7ff - Bias - P + - 1 -#endif -#ifdef IBM - emax = 0x7f - Bias - P -#endif -#endif /*}}*/ - }; -#ifdef USE_LOCALE - int i; -#ifdef NO_LOCALE_CACHE - const unsigned char *decimalpoint = - (unsigned char *)localeconv()->decimal_point; -#else - const unsigned char *decimalpoint; - static unsigned char *decimalpoint_cache; - if (!(s0 = decimalpoint_cache)) { - s0 = (unsigned char *)localeconv()->decimal_point; - if ((decimalpoint_cache = - (unsigned char *)MALLOC(strlen((const char *)s0) + 1))) { - strcpy((char *)decimalpoint_cache, (const char *)s0); - s0 = decimalpoint_cache; - } - } - decimalpoint = s0; -#endif -#endif - - /**** if (!hexdig['0']) hexdig_init(); ****/ - havedig = 0; - s0 = *(const unsigned char **)sp + 2; - while (s0[havedig] == '0') havedig++; - s0 += havedig; - s = s0; - decpt = 0; - zret = 0; - e = 0; - if (kDtoaHexdig[*s]) - havedig++; - else { - zret = 1; -#ifdef USE_LOCALE - for (i = 0; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) goto pcheck; - } - decpt = s += i; -#else - if (*s != '.') goto pcheck; - decpt = ++s; -#endif - if (!kDtoaHexdig[*s]) goto pcheck; - while (*s == '0') s++; - if (kDtoaHexdig[*s]) zret = 0; - havedig = 1; - s0 = s; - } - while (kDtoaHexdig[*s]) s++; -#ifdef USE_LOCALE - if (*s == *decimalpoint && !decpt) { - for (i = 1; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) goto pcheck; - } - decpt = s += i; -#else - if (*s == '.' && !decpt) { - decpt = ++s; -#endif - while (kDtoaHexdig[*s]) s++; - } /*}*/ - if (decpt) e = -(((Long)(s - decpt)) << 2); -pcheck: - s1 = s; - big = esign = 0; - switch (*s) { - case 'p': - case 'P': - switch (*++s) { - case '-': - esign = 1; - /* no break */ - case '+': - s++; - } - if ((n = kDtoaHexdig[*s]) == 0 || n > 0x19) { - s = s1; - break; - } - e1 = n - 0x10; - while ((n = kDtoaHexdig[*++s]) != 0 && n <= 0x19) { - if (e1 & 0xf8000000) big = 1; - e1 = 10 * e1 + n - 0x10; - } - if (esign) e1 = -e1; - e += e1; - } - *sp = (char *)s; - if (!havedig) *sp = (char *)s0 - 1; - if (zret) goto retz1; - if (big) { - if (esign) { -#ifdef IEEE_Arith - switch (rounding) { - case Round_up: - if (sign) break; - goto ret_tiny; - case Round_down: - if (!sign) break; - goto ret_tiny; - } -#endif - goto retz; -#ifdef IEEE_Arith - ret_tinyf: - dtoa_bfree(b MTa); - ret_tiny: - Set_errno(erange); - word0(rvp) = 0; - word1(rvp) = 1; - return; -#endif /* IEEE_Arith */ - } - switch (rounding) { - case Round_near: - goto ovfl1; - case Round_up: - if (!sign) goto ovfl1; - goto ret_big; - case Round_down: - if (sign) goto ovfl1; - goto ret_big; - } - ret_big: - word0(rvp) = Big0; - word1(rvp) = Big1; - return; - } - n = s1 - s0 - 1; - for (k = 0; n > (1 << (kshift - 2)) - 1; n >>= 1) k++; - b = dtoa_balloc(k MTa); - x = b->x; - n = 0; - L = 0; -#ifdef USE_LOCALE - for (i = 0; decimalpoint[i + 1]; ++i) - ; -#endif - while (s1 > s0) { -#ifdef USE_LOCALE - if (*--s1 == decimalpoint[i]) { - s1 -= i; - continue; - } -#else - if (*--s1 == '.') continue; -#endif - if (n == ULbits) { - *x++ = L; - L = 0; - n = 0; - } - L |= (kDtoaHexdig[*s1] & 0x0f) << n; - n += 4; - } - *x++ = L; - b->wds = n = x - b->x; - n = ULbits * n - dtoa_hi0bits(L); - nbits = Nbits; - lostbits = 0; - x = b->x; - if (n > nbits) { - n -= nbits; - if (dtoa_any_on(b, n)) { - lostbits = 1; - k = n - 1; - if (x[k >> kshift] & 1 << (k & kmask)) { - lostbits = 2; - if (k > 0 && dtoa_any_on(b, k)) lostbits = 3; - } - } - dtoa_rshift(b, n); - e += n; - } else if (n < nbits) { - n = nbits - n; - b = dtoa_lshift(b, n MTa); - e -= n; - x = b->x; - } - if (e > emax) { - ovfl: - dtoa_bfree(b MTa); - ovfl1: - Set_errno(erange); -#ifdef Honor_FLT_ROUNDS - switch (rounding) { - case Round_zero: - goto ret_big; - case Round_down: - if (!sign) goto ret_big; - break; - case Round_up: - if (sign) goto ret_big; - } -#endif - word0(rvp) = Exp_mask; - word1(rvp) = 0; - return; - } - denorm = 0; - if (e < emin) { - denorm = 1; - n = emin - e; - if (n >= nbits) { -#ifdef IEEE_Arith /*{*/ - switch (rounding) { - case Round_near: - if (n == nbits && (n < 2 || lostbits || dtoa_any_on(b, n - 1))) - goto ret_tinyf; - break; - case Round_up: - if (!sign) goto ret_tinyf; - break; - case Round_down: - if (sign) goto ret_tinyf; - } -#endif /* } IEEE_Arith */ - dtoa_bfree(b MTa); - retz: - Set_errno(erange); - retz1: - rvp->d = 0.; - return; - } - k = n - 1; - if (lostbits) - lostbits = 1; - else if (k > 0) - lostbits = dtoa_any_on(b, k); - if (x[k >> kshift] & 1 << (k & kmask)) lostbits |= 2; - nbits -= n; - dtoa_rshift(b, n); - e = emin; - } - if (lostbits) { - up = 0; - switch (rounding) { - case Round_zero: - break; - case Round_near: - if (lostbits & 2 && (lostbits & 1) | (x[0] & 1)) up = 1; - break; - case Round_up: - up = 1 - sign; - break; - case Round_down: - up = sign; - } - if (up) { - k = b->wds; - b = increment(b MTa); - x = b->x; - if (denorm) { -#if 0 - if (nbits == Nbits - 1 - && x[nbits >> kshift] & 1 << (nbits & kmask)) - denorm = 0; /* not currently used */ -#endif - } else if (b->wds > k || ((n = nbits & kmask) != 0 && - dtoa_hi0bits(x[k - 1]) < 32 - n)) { - dtoa_rshift(b, 1); - if (++e > Emax) goto ovfl; - } - } - } -#ifdef IEEE_Arith - if (denorm) - word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0; - else - word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20); - word1(rvp) = b->x[0]; -#endif -#ifdef IBM - if ((j = e & 3)) { - k = b->x[0] & ((1u << j) - 1); - dtoa_rshift(b, j); - if (k) { - switch (rounding) { - case Round_up: - if (!sign) increment(b); - break; - case Round_down: - if (sign) increment(b); - break; - case Round_near: - j = 1 << (j - 1); - if (k & j && ((k & (j - 1)) | lostbits)) increment(b); - } - } - } - e >>= 2; - word0(rvp) = b->x[1] | ((e + 65 + 13) << 24); - word1(rvp) = b->x[0]; -#endif -#ifdef VAX - /* The next two lines ignore swap of low- and high-order 2 bytes. */ - /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */ - /* word1(rvp) = b->x[0]; */ - word0(rvp) = - ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); - word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); -#endif - dtoa_bfree(b MTa); -} -#endif /*!NO_HEX_FP}*/ - -static int dtoa_dshift(Bigint *b, int p2) { - int rv = dtoa_hi0bits(b->x[b->wds - 1]) - 4; - if (p2 > 0) rv -= p2; - return rv & kmask; -} - -static int dtoa_quorem(Bigint *b, Bigint *S) { - int n; - ULong *bx, *bxe, q, *sx, *sxe; -#ifdef ULLong - ULLong borrow, carry, y, ys; -#else - ULong borrow, carry, y, ys; -#ifdef Pack_32 - ULong si, z, zs; -#endif -#endif - - n = S->wds; -#ifdef DEBUG - /*debug*/ if (b->wds > n) - /*debug*/ Bug("oversize b in dtoa_quorem"); -#endif - if (b->wds < n) return 0; - sx = S->x; - sxe = sx + --n; - bx = b->x; - bxe = bx + n; - q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ -#ifdef DEBUG -#ifdef NO_STRTOD_BIGCOMP - /*debug*/ if (q > 9) -#else - /* An oversized q is possible when dtoa_quorem is called from dtoa_bigcomp and - */ - /* the input is near, e.g., twice the smallest denormalized number. */ - /*debug*/ if (q > 15) -#endif - /*debug*/ Bug("oversized quotient in dtoa_quorem"); -#endif - if (q) { - borrow = 0; - carry = 0; - do { -#ifdef ULLong - ys = *sx++ * (ULLong)q + carry; - carry = ys >> 32; - y = *bx - (ys & FFFFFFFF) - borrow; - borrow = y >> 32 & (ULong)1; - *bx++ = y & FFFFFFFF; -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } while (sx <= sxe); - if (!*bxe) { - bx = b->x; - while (--bxe > bx && !*bxe) --n; - b->wds = n; - } - } - if (dtoa_cmp(b, S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = b->x; - sx = S->x; - do { -#ifdef ULLong - ys = *sx++ + carry; - carry = ys >> 32; - y = *bx - (ys & FFFFFFFF) - borrow; - borrow = y >> 32 & (ULong)1; - *bx++ = y & FFFFFFFF; -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } while (sx <= sxe); - bx = b->x; - bxe = bx + n; - if (!*bxe) { - while (--bxe > bx && !*bxe) --n; - b->wds = n; - } - } - return q; -} - -#if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/ -static double dtoa_sulp(U *x, BCinfo *bc) { - U u; - double rv; - int i; - - rv = ulp(x); - if (!bc->scale || (i = 2 * P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) - return rv; /* Is there an example where i <= 0 ? */ - word0(&u) = Exp_1 + (i << Exp_shift); - word1(&u) = 0; - return rv * u.d; -} -#endif /*}*/ - -#ifndef NO_STRTOD_BIGCOMP -static void dtoa_bigcomp(U *rv, const char *s0, BCinfo *bc MTd) { - Bigint *b, *d; - int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase; - dd = 0; /* TODO(jart): Why does compiler complain? */ - - dsign = bc->dsign; - nd = bc->nd; - nd0 = bc->nd0; - p5 = nd + bc->e0 - 1; - speccase = 0; -#ifndef Sudden_Underflow - if (rv->d == 0.) { /* special case: value near underflow-to-zero */ - /* threshold was rounded to zero */ - b = dtoa_i2b(1 MTa); - p2 = Emin - P + 1; - bbits = 1; -#ifdef Avoid_Underflow - word0(rv) = (P + 2) << Exp_shift; -#else - word1(rv) = 1; -#endif - i = 0; -#ifdef Honor_FLT_ROUNDS - if (bc->rounding == 1) -#endif - { - speccase = 1; - --p2; - dsign = 0; - goto have_i; - } - } else -#endif - b = dtoa_d2b(rv, &p2, &bbits MTa); -#ifdef Avoid_Underflow - p2 -= bc->scale; -#endif - /* floor(log2(rv)) == bbits - 1 + p2 */ - /* Check for denormal case. */ - i = P - bbits; - if (i > (j = P - Emin - 1 + p2)) { -#ifdef Sudden_Underflow - dtoa_bfree(b MTa); - b = dtoa_i2b(1 MTa); - p2 = Emin; - i = P - 1; -#ifdef Avoid_Underflow - word0(rv) = (1 + bc->scale) << Exp_shift; -#else - word0(rv) = Exp_msk1; -#endif - word1(rv) = 0; -#else - i = j; -#endif - } -#ifdef Honor_FLT_ROUNDS - if (bc->rounding != 1) { - if (i > 0) b = dtoa_lshift(b, i MTa); - if (dsign) b = increment(b MTa); - } else -#endif - { - b = dtoa_lshift(b, ++i MTa); - b->x[0] |= 1; - } -#ifndef Sudden_Underflow -have_i: -#endif - p2 -= p5 + i; - d = dtoa_i2b(1 MTa); - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - */ - if (p5 > 0) - d = dtoa_pow5mult(d, p5 MTa); - else if (p5 < 0) - b = dtoa_pow5mult(b, -p5 MTa); - if (p2 > 0) { - b2 = p2; - d2 = 0; - } else { - b2 = 0; - d2 = -p2; - } - i = dtoa_dshift(d, d2); - if ((b2 += i) > 0) b = dtoa_lshift(b, b2 MTa); - if ((d2 += i) > 0) d = dtoa_lshift(d, d2 MTa); - - /* Now b/d = exactly half-way between the two floating-point values */ - /* on either side of the input string. Compute first digit of b/d. */ - - if (!(dig = dtoa_quorem(b, d))) { - b = dtoa_multadd(b, 10, 0 MTa); /* very unlikely */ - dig = dtoa_quorem(b, d); - } - - /* Compare b/d with s0 */ - - for (i = 0; i < nd0;) { - if ((dd = s0[i++] - '0' - dig)) goto ret; - if (!b->x[0] && b->wds == 1) { - if (i < nd) dd = 1; - goto ret; - } - b = dtoa_multadd(b, 10, 0 MTa); - dig = dtoa_quorem(b, d); - } - for (j = bc->dp1; i++ < nd;) { - if ((dd = s0[j++] - '0' - dig)) goto ret; - if (!b->x[0] && b->wds == 1) { - if (i < nd) dd = 1; - goto ret; - } - b = dtoa_multadd(b, 10, 0 MTa); - dig = dtoa_quorem(b, d); - } - if (dig > 0 || b->x[0] || b->wds > 1) dd = -1; -ret: - dtoa_bfree(b MTa); - dtoa_bfree(d MTa); -#ifdef Honor_FLT_ROUNDS - if (bc->rounding != 1) { - if (dd < 0) { - if (bc->rounding == 0) { - if (!dsign) goto retlow1; - } else if (dsign) - goto rethi1; - } else if (dd > 0) { - if (bc->rounding == 0) { - if (dsign) goto rethi1; - goto ret1; - } - if (!dsign) goto rethi1; - dval(rv) += 2. * dtoa_sulp(rv, bc); - } else { - bc->inexact = 0; - if (dsign) goto rethi1; - } - } else -#endif - if (speccase) { - if (dd <= 0) rv->d = 0.; - } else if (dd < 0) { - if (!dsign) /* does not happen for round-near */ - retlow1: - dval(rv) -= dtoa_sulp(rv, bc); - } else if (dd > 0) { - if (dsign) { - rethi1: - dval(rv) += dtoa_sulp(rv, bc); - } - } else { - /* Exact half-way case: apply round-even rule. */ - if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) { - i = 1 - j; - if (i <= 31) { - if (word1(rv) & (0x1 << i)) goto odd; - } else if (word0(rv) & (0x1 << (i - 32))) - goto odd; - } else if (word1(rv) & 1) { - odd: - if (dsign) goto rethi1; - goto retlow1; - } - } - -#ifdef Honor_FLT_ROUNDS -ret1: -#endif - return; -} -#endif /* NO_STRTOD_BIGCOMP */ - -double(strtod)(const char *s00, char **se) { - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1; - int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign; - const char *s, *s0, *s1; - double aadj, aadj1; - Long L; - U aadj2, adj, rv, rv0; - ULong y, z; - BCinfo bc; - Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; -#ifdef USE_BF96 - ULLong bhi, blo, brv, t00, t01, t02, t10, t11, terv, tg, tlo, yz; - const BF96 *p10; - int bexact, erv; -#endif -#ifdef Avoid_Underflow - ULong Lsb, Lsb1; -#endif -#ifdef SET_INEXACT - int oldinexact; -#endif -#ifndef NO_STRTOD_BIGCOMP - int req_dtoa_bigcomp = 0; -#endif -#ifdef MULTIPLE_THREADS - ThInfo *TI = 0; -#endif -#ifdef Honor_FLT_ROUNDS /*{*/ -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - bc.rounding = Flt_Rounds; -#else /*}{*/ - bc.rounding = 1; - switch (fegetround()) { - case FE_TOWARDZERO: - bc.rounding = 0; - break; - case FE_UPWARD: - bc.rounding = 2; - break; - case FE_DOWNWARD: - bc.rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ -#ifdef USE_LOCALE - const char *s2; -#endif - - sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0; - dval(&rv) = 0.; - for (s = s00;; s++) switch (*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) goto break2; - /* no break */ - case 0: - goto ret0; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } -break2: - if (*s == '0') { -#ifndef NO_HEX_FP /*{*/ - switch (s[1]) { - case 'x': - case 'X': -#ifdef Honor_FLT_ROUNDS - gethex(&s, &rv, bc.rounding, sign MTb); -#else - gethex(&s, &rv, 1, sign MTb); -#endif - goto ret; - } -#endif /*}*/ - nz0 = 1; - while (*++s == '0') - ; - if (!*s) goto ret; - } - s0 = s; - nd = nf = 0; -#ifdef USE_BF96 - yz = 0; - for (; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 19) yz = 10 * yz + c - '0'; -#else - y = z = 0; - for (; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10 * y + c - '0'; - else if (nd < DBL_DIG + 2) - z = 10 * z + c - '0'; -#endif - nd0 = nd; - bc.dp0 = bc.dp1 = s - s0; - for (s1 = s; s1 > s0 && *--s1 == '0';) ++nz1; -#ifdef USE_LOCALE - s1 = localeconv()->decimal_point; - if (c == *s1) { - c = '.'; - if (*++s1) { - s2 = s; - for (;;) { - if (*++s2 != *s1) { - c = 0; - break; - } - if (!*++s1) { - s = s2; - break; - } - } - } - } -#endif - if (c == '.') { - c = *++s; - bc.dp1 = s - s0; - bc.dplen = bc.dp1 - bc.dp0; - if (!nd) { - for (; c == '0'; c = *++s) nz++; - if (c > '0' && c <= '9') { - bc.dp0 = s0 - s; - bc.dp1 = bc.dp0 + bc.dplen; - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for (; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - i = 1; -#ifdef USE_BF96 - for (; i < nz; ++i) { - if (++nd <= 19) yz *= 10; - } - if (++nd <= 19) yz = 10 * yz + c; -#else - for (; i < nz; ++i) { - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 2) - z *= 10; - } - if (nd++ < 9) - y = 10 * y + c; - else if (nd <= DBL_DIG + 2) - z = 10 * z + c; -#endif - nz = nz1 = 0; - } - } - } -dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - goto ret0; - } - s00 = s; - esign = 0; - switch (c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while (c == '0') c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while ((c = *++s) >= '0' && c <= '9') L = 10 * L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = (int)L; - if (esign) e = -e; - } else - e = 0; - } else - s = s00; - } - if (!nd) { - if (!nz && !nz0) { -#ifdef INFNAN_CHECK /*{*/ - /* Check for Nan and Infinity */ - if (!bc.dplen) switch (c) { - case 'i': - case 'I': - if (dtoa_match(&s, "nf")) { - --s; - if (!dtoa_match(&s, "inity")) ++s; - word0(&rv) = 0x7ff00000; - word1(&rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (dtoa_match(&s, "an")) { - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; -#ifndef No_Hex_NaN - if (*s == '(') /*)*/ - dtoa_hexnan(&rv, &s); -#endif - goto ret; - } - } -#endif /*} INFNAN_CHECK */ - ret0: - s = s00; - sign = 0; - } - goto ret; - } - bc.e0 = e1 = e -= nf; - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) nd0 = nd; -#ifndef USE_BF96 - k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2; - dval(&rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) oldinexact = get_inexact(); -#endif - dval(&rv) = kDtoaTens[k - 9] * dval(&rv) + z; - } -#endif - bd0 = 0; - if (nd <= DBL_DIG -#ifndef RND_PRODQUOT -#ifndef Honor_FLT_ROUNDS - && Flt_Rounds == 1 -#endif -#endif - ) { -#ifdef USE_BF96 - dval(&rv) = yz; -#endif - if (!e) goto ret; -#ifndef ROUND_BIASED_without_Round_Up - if (e > 0) { - if (e <= Ten_pmax) { -#ifdef SET_INEXACT - bc.inexact = 0; - oldinexact = 1; -#endif -#ifdef VAX - goto vax_ovfl_check; -#else -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_product(dval(&rv), kDtoaTens[e]); - goto ret; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ -#ifdef SET_INEXACT - bc.inexact = 0; - oldinexact = 1; -#endif -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - e -= i; - dval(&rv) *= kDtoaTens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - word0(&rv) -= P * Exp_msk1; - /* rv = */ rounded_product(dval(&rv), kDtoaTens[e]); - if ((word0(&rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) - goto ovfl; - word0(&rv) += P * Exp_msk1; -#else - /* rv = */ rounded_product(dval(&rv), kDtoaTens[e]); -#endif - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { -#ifdef SET_INEXACT - bc.inexact = 0; - oldinexact = 1; -#endif -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_quotient(dval(&rv), kDtoaTens[-e]); - goto ret; - } -#endif -#endif /* ROUND_BIASED_without_Round_Up */ - } -#ifdef USE_BF96 - k = nd < 19 ? nd : 19; -#endif - e1 += nd - k; /* scale factor = 10^e1 */ - -#ifdef IEEE_Arith -#ifdef SET_INEXACT - bc.inexact = 1; -#ifndef USE_BF96 - if (k <= DBL_DIG) -#endif - oldinexact = get_inexact(); -#endif -#ifdef Honor_FLT_ROUNDS - if (bc.rounding >= 2) { - if (sign) - bc.rounding = bc.rounding == 2 ? 0 : 2; - else if (bc.rounding != 2) - bc.rounding = 0; - } -#endif -#endif /*IEEE_Arith*/ - -#ifdef USE_BF96 /*{*/ - Debug(++dtoa_stats[0]); - i = e1 + 342; - if (i < 0) goto undfl; - if (i > 650) goto ovfl; - p10 = &kDtoaPten[i]; - brv = yz; - /* shift brv left, with i = number of bits shifted */ - i = 0; - if (!(brv & 0xffffffff00000000ull)) { - i = 32; - brv <<= 32; - } - if (!(brv & 0xffff000000000000ull)) { - i += 16; - brv <<= 16; - } - if (!(brv & 0xff00000000000000ull)) { - i += 8; - brv <<= 8; - } - if (!(brv & 0xf000000000000000ull)) { - i += 4; - brv <<= 4; - } - if (!(brv & 0xc000000000000000ull)) { - i += 2; - brv <<= 2; - } - if (!(brv & 0x8000000000000000ull)) { - i += 1; - brv <<= 1; - } - erv = (64 + 0x3fe) + p10->e - i; - if (erv <= 0 && nd > 19) - goto many_digits; /* denormal: may need to look at all digits */ - bhi = brv >> 32; - blo = brv & 0xffffffffull; - /* Unsigned 32-bit ints lie in [0,2^32-1] and */ - /* unsigned 64-bit ints lie in [0, 2^64-1]. The product of two unsigned */ - /* 32-bit ints is <= 2^64 - 2*2^32-1 + 1 = 2^64 - 1 - 2*(2^32 - 1), so */ - /* we can add two unsigned 32-bit ints to the product of two such ints, */ - /* and 64 bits suffice to contain the result. */ - t01 = bhi * p10->b1; - t10 = blo * p10->b0 + (t01 & 0xffffffffull); - t00 = bhi * p10->b0 + (t01 >> 32) + (t10 >> 32); - if (t00 & 0x8000000000000000ull) { - if ((t00 & 0x3ff) && (~t00 & 0x3fe)) { /* unambiguous result? */ - if (nd > 19 && ((t00 + (1 << i) + 2) & 0x400) ^ (t00 & 0x400)) - goto many_digits; - if (erv <= 0) goto denormal; -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto noround; - case 2: - goto roundup; - } -#endif - if (t00 & 0x400 && t00 & 0xbff) goto roundup; - goto noround; - } - } else { - if ((t00 & 0x1ff) && (~t00 & 0x1fe)) { /* unambiguous result? */ - if (nd > 19 && ((t00 + (1 << i) + 2) & 0x200) ^ (t00 & 0x200)) - goto many_digits; - if (erv <= 1) goto denormal1; -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto noround1; - case 2: - goto roundup1; - } -#endif - if (t00 & 0x200) goto roundup1; - goto noround1; - } - } - /* 3 multiplies did not suffice; try a 96-bit approximation */ - Debug(++dtoa_stats[1]); - t02 = bhi * p10->b2; - t11 = blo * p10->b1 + (t02 & 0xffffffffull); - bexact = 1; - if (e1 < 0 || e1 > 41 || (t10 | t11) & 0xffffffffull || nd > 19) bexact = 0; - tlo = (t10 & 0xffffffffull) + (t02 >> 32) + (t11 >> 32); - if (!bexact && (tlo + 0x10) >> 32 > tlo >> 32) goto many_digits; - t00 += tlo >> 32; - if (t00 & 0x8000000000000000ull) { - if (erv <= 0) { /* denormal result */ - if (nd >= 20 || !((tlo & 0xfffffff0) | (t00 & 0x3ff))) goto many_digits; - denormal: - if (erv <= -52) { -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto undfl; - case 2: - goto tiniest; - } -#endif - if (erv < -52 || !(t00 & 0x7fffffffffffffffull)) goto undfl; - goto tiniest; - } - tg = 1ull << (11 - erv); - t00 &= ~(tg - 1); /* clear low bits */ -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto noround_den; - case 2: - goto roundup_den; - } -#endif - if (t00 & tg) { -#ifdef Honor_FLT_ROUNDS - roundup_den: -#endif - t00 += tg << 1; - if (!(t00 & 0x8000000000000000ull)) { - if (++erv > 0) goto smallest_normal; - t00 = 0x8000000000000000ull; - } - } -#ifdef Honor_FLT_ROUNDS - noround_den: -#endif - LLval(&rv) = t00 >> (12 - erv); - Set_errno(erange); - goto ret; - } - if (bexact) { -#ifdef SET_INEXACT - if (!(t00 & 0x7ff) && !(tlo & 0xffffffffull)) { - bc.inexact = 0; - goto noround; - } -#endif -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 2: - if (t00 & 0x7ff) goto roundup; - case 0: - goto noround; - } -#endif - if (t00 & 0x400 && (tlo & 0xffffffff) | (t00 & 0xbff)) goto roundup; - goto noround; - } - if ((tlo & 0xfffffff0) | (t00 & 0x3ff) && - (nd <= 19 || ((t00 + (1ull << i)) & 0xfffffffffffffc00ull) == - (t00 & 0xfffffffffffffc00ull))) { - /* Unambiguous result. */ - /* If nd > 19, then incrementing the 19th digit */ - /* does not affect rv. */ -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto noround; - case 2: - goto roundup; - } -#endif - if (t00 & 0x400) { /* round up */ - roundup: - t00 += 0x800; - if (!(t00 & 0x8000000000000000ull)) { - /* rounded up to a power of 2 */ - if (erv >= 0x7fe) goto ovfl; - terv = erv + 1; - LLval(&rv) = terv << 52; - goto ret; - } - } - noround: - if (erv >= 0x7ff) goto ovfl; - terv = erv; - LLval(&rv) = (terv << 52) | ((t00 & 0x7ffffffffffff800ull) >> 11); - goto ret; - } - } else { - if (erv <= 1) { /* denormal result */ - if (nd >= 20 || !((tlo & 0xfffffff0) | (t00 & 0x1ff))) goto many_digits; - denormal1: - if (erv <= -51) { -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto undfl; - case 2: - goto tiniest; - } -#endif - if (erv < -51 || !(t00 & 0x3fffffffffffffffull)) goto undfl; - tiniest: - LLval(&rv) = 1; - Set_errno(erange); - goto ret; - } - tg = 1ull << (11 - erv); -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto noround1_den; - case 2: - goto roundup1_den; - } -#endif - if (t00 & tg) { -#ifdef Honor_FLT_ROUNDS - roundup1_den: -#endif - if (0x8000000000000000ull & (t00 += (tg << 1)) && erv == 1) { - - smallest_normal: - LLval(&rv) = 0x0010000000000000ull; - goto ret; - } - } -#ifdef Honor_FLT_ROUNDS - noround1_den: -#endif - if (erv <= -52) goto undfl; - LLval(&rv) = t00 >> (12 - erv); - Set_errno(erange); - goto ret; - } - if (bexact) { -#ifdef SET_INEXACT - if (!(t00 & 0x3ff) && !(tlo & 0xffffffffull)) { - bc.inexact = 0; - goto noround1; - } -#endif -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 2: - if (t00 & 0x3ff) goto roundup1; - case 0: - goto noround1; - } -#endif - if (t00 & 0x200 && (t00 & 0x5ff || tlo)) goto roundup1; - goto noround1; - } - if ((tlo & 0xfffffff0) | (t00 & 0x1ff) && - (nd <= 19 || ((t00 + (1ull << i)) & 0x7ffffffffffffe00ull) == - (t00 & 0x7ffffffffffffe00ull))) { - /* Unambiguous result. */ -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: - goto noround1; - case 2: - goto roundup1; - } -#endif - if (t00 & 0x200) { /* round up */ - roundup1: - t00 += 0x400; - if (!(t00 & 0x4000000000000000ull)) { - /* rounded up to a power of 2 */ - if (erv >= 0x7ff) goto ovfl; - terv = erv; - LLval(&rv) = terv << 52; - goto ret; - } - } - noround1: - if (erv >= 0x800) goto ovfl; - terv = erv - 1; - LLval(&rv) = (terv << 52) | ((t00 & 0x3ffffffffffffc00ull) >> 10); - goto ret; - } - } -many_digits: - Debug(++dtoa_stats[2]); - if (nd > 17) { - if (nd > 18) { - yz /= 100; - e1 += 2; - } else { - yz /= 10; - e1 += 1; - } - y = yz / 100000000; - } else if (nd > 9) { - i = nd - 9; - y = (yz >> i) / kDtoaPfive[i - 1]; - } else - y = yz; - dval(&rv) = yz; -#endif /*}*/ - -#ifdef IEEE_Arith -#ifdef Avoid_Underflow - bc.scale = 0; -#endif -#endif /*IEEE_Arith*/ - - /* Get starting approximation = rv * 10**e1 */ - - if (e1 > 0) { - if ((i = e1 & 15)) dval(&rv) *= kDtoaTens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { - ovfl: - /* Can't trust HUGE_VAL */ -#ifdef IEEE_Arith -#ifdef Honor_FLT_ROUNDS - switch (bc.rounding) { - case 0: /* toward 0 */ - case 3: /* toward -infinity */ - word0(&rv) = Big0; - word1(&rv) = Big1; - break; - default: - word0(&rv) = Exp_mask; - word1(&rv) = 0; - } -#else /*Honor_FLT_ROUNDS*/ - word0(&rv) = Exp_mask; - word1(&rv) = 0; -#endif /*Honor_FLT_ROUNDS*/ -#ifdef SET_INEXACT - /* set overflow bit */ - dval(&rv0) = 1e300; - dval(&rv0) *= dval(&rv0); -#endif -#else /*IEEE_Arith*/ - word0(&rv) = Big0; - word1(&rv) = Big1; -#endif /*IEEE_Arith*/ - range_err: - if (bd0) { - dtoa_bfree(bb MTb); - dtoa_bfree(bd MTb); - dtoa_bfree(bs MTb); - dtoa_bfree(bd0 MTb); - dtoa_bfree(delta MTb); - } - Set_errno(erange); - goto ret; - } - e1 >>= 4; - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) dval(&rv) *= kDtoaBigTens[j]; - /* The last multiplication could overflow. */ - word0(&rv) -= P * Exp_msk1; - dval(&rv) *= kDtoaBigTens[j]; - if ((z = word0(&rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - P)) - goto ovfl; - if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - word0(&rv) = Big0; - word1(&rv) = Big1; - } else - word0(&rv) += P * Exp_msk1; - } - } else if (e1 < 0) { - e1 = -e1; - if ((i = e1 & 15)) dval(&rv) /= kDtoaTens[i]; - if (e1 >>= 4) { - if (e1 >= 1u << n_bigtens) goto undfl; -#ifdef Avoid_Underflow - if (e1 & Scale_Bit) bc.scale = 2 * P; - for (j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) dval(&rv) *= kDtoaTinyTens[j]; - if (bc.scale && - (j = 2 * P + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { - /* scaled rv is denormal; clear j low bits */ - if (j >= 32) { - if (j > 54) goto undfl; - word1(&rv) = 0; - if (j >= 53) - word0(&rv) = (P + 2) * Exp_msk1; - else - word0(&rv) &= 0xffffffff << (j - 32); - } else - word1(&rv) &= 0xffffffff << j; - } -#else - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) dval(&rv) *= kDtoaTinyTens[j]; - /* The last multiplication could underflow. */ - dval(&rv0) = dval(&rv); - dval(&rv) *= kDtoaTinyTens[j]; - if (!dval(&rv)) { - dval(&rv) = 2. * dval(&rv0); - dval(&rv) *= kDtoaTinyTens[j]; -#endif - if (!dval(&rv)) { - undfl: - dval(&rv) = 0.; -#ifdef Honor_FLT_ROUNDS - if (bc.rounding == 2) word1(&rv) = 1; -#endif - goto range_err; - } -#ifndef Avoid_Underflow - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif - } -} - -/* Now the hard part -- adjusting rv to the correct value.*/ - -/* Put digits into bd: true value = bd * 10^e */ - -bc.nd = nd - nz1; -#ifndef NO_STRTOD_BIGCOMP -bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */ -/* to silence an erroneous warning about bc.nd0 */ -/* possibly not being initialized. */ -if (nd > strtod_diglim) { - /* ASSERT(strtod_diglim >= 18); 18 == one more than the */ - /* minimum number of decimal digits to distinguish double values */ - /* in IEEE arithmetic. */ - i = j = 18; - if (i > nd0) j += bc.dplen; - for (;;) { - if (--j < bc.dp1 && j >= bc.dp0) j = bc.dp0 - 1; - if (s0[j] != '0') break; - --i; - } - e += nd - i; - nd = i; - if (nd0 > nd) nd0 = nd; - if (nd < 9) { /* must recompute y */ - y = 0; - for (i = 0; i < nd0; ++i) y = 10 * y + s0[i] - '0'; - for (j = bc.dp1; i < nd; ++i) y = 10 * y + s0[j++] - '0'; - } -} -#endif -bd0 = s2b(s0, nd0, nd, y, bc.dplen MTb); - -for (;;) { - bd = dtoa_balloc(bd0->k MTb); - Bcopy(bd, bd0); - bb = dtoa_d2b(&rv, &bbe, &bbbits MTb); /* rv = bb * 2^bbe */ - bs = dtoa_i2b(1 MTb); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; -#ifdef Honor_FLT_ROUNDS - if (bc.rounding != 1) bs2++; -#endif -#ifdef Avoid_Underflow - Lsb = LSB; - Lsb1 = 0; - j = bbe - bc.scale; - i = j + bbbits - 1; /* logb(rv) */ - j = P + 1 - bbbits; - if (i < Emin) { /* denormal */ - i = Emin - i; - j -= i; - if (i < 32) - Lsb <<= i; - else if (i < 52) - Lsb1 = Lsb << (i - 32); - else - Lsb1 = Exp_mask; - } -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow -#ifdef IBM - j = 1 + 4 * P - 3 - bbbits + ((bbe + bbbits - 1) & 3); -#else - j = P + 1 - bbbits; -#endif -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - bb2 += j; - bd2 += j; -#ifdef Avoid_Underflow - bd2 += bc.scale; -#endif - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = dtoa_pow5mult(bs, bb5 MTb); - bb1 = dtoa_mult(bs, bb MTb); - dtoa_bfree(bb MTb); - bb = bb1; - } - if (bb2 > 0) bb = dtoa_lshift(bb, bb2 MTb); - if (bd5 > 0) bd = dtoa_pow5mult(bd, bd5 MTb); - if (bd2 > 0) bd = dtoa_lshift(bd, bd2 MTb); - if (bs2 > 0) bs = dtoa_lshift(bs, bs2 MTb); - delta = dtoa_diff(bb, bd MTb); - bc.dsign = delta->sign; - delta->sign = 0; - i = dtoa_cmp(delta, bs); -#ifndef NO_STRTOD_BIGCOMP /*{*/ - if (bc.nd > nd && i <= 0) { - if (bc.dsign) { - /* Must use dtoa_bigcomp(). */ - req_dtoa_bigcomp = 1; - break; - } -#ifdef Honor_FLT_ROUNDS - if (bc.rounding != 1) { - if (i < 0) { - req_dtoa_bigcomp = 1; - break; - } - } else -#endif - i = -1; /* Discarded digits make delta smaller. */ - } -#endif /*}*/ -#ifdef Honor_FLT_ROUNDS /*{*/ - if (bc.rounding != 1) { - if (i < 0) { - /* Error is less than an ulp */ - if (!delta->x[0] && delta->wds <= 1) { - /* exact */ -#ifdef SET_INEXACT - bc.inexact = 0; -#endif - break; - } - if (bc.rounding) { - if (bc.dsign) { - adj.d = 1.; - goto apply_adj; - } - } else if (!bc.dsign) { - adj.d = -1.; - if (!word1(&rv) && !(word0(&rv) & Frac_mask)) { - y = word0(&rv) & Exp_mask; -#ifdef Avoid_Underflow - if (!bc.scale || y > 2 * P * Exp_msk1) -#else - if (y) -#endif - { - delta = dtoa_lshift(delta, Log2P MTb); - if (dtoa_cmp(delta, bs) <= 0) adj.d = -0.5; - } - } - apply_adj: -#ifdef Avoid_Underflow /*{*/ - if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) - word0(&adj) += (2 * P + 1) * Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) { - word0(&rv) += P * Exp_msk1; - dval(&rv) += adj.d * ulp(dval(&rv)); - word0(&rv) -= P * Exp_msk1; - } else -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow}*/ - dval(&rv) += adj.d * ulp(&rv); - } - break; - } - adj.d = dtoaratio(delta, bs); - if (adj.d < 1.) adj.d = 1.; - if (adj.d <= 0x7ffffffe) { - /* adj = rounding ? ceil(adj) : floor(adj); */ - y = adj.d; - if (y != adj.d) { - if (!((bc.rounding >> 1) ^ bc.dsign)) y++; - adj.d = y; - } - } -#ifdef Avoid_Underflow /*{*/ - if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) - word0(&adj) += (2 * P + 1) * Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) { - word0(&rv) += P * Exp_msk1; - adj.d *= ulp(dval(&rv)); - if (bc.dsign) - dval(&rv) += adj.d; - else - dval(&rv) -= adj.d; - word0(&rv) -= P * Exp_msk1; - goto cont; - } -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow}*/ - adj.d *= ulp(&rv); - if (bc.dsign) { - if (word0(&rv) == Big0 && word1(&rv) == Big1) goto ovfl; - dval(&rv) += adj.d; - } else - dval(&rv) -= adj.d; - goto cont; - } -#endif /*}Honor_FLT_ROUNDS*/ - - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask -#ifdef IEEE_Arith /*{*/ -#ifdef Avoid_Underflow - || (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1 -#else - || (word0(&rv) & Exp_mask) <= Exp_msk1 -#endif -#endif /*}*/ - ) { -#ifdef SET_INEXACT - if (!delta->x[0] && delta->wds <= 1) bc.inexact = 0; -#endif - break; - } - if (!delta->x[0] && delta->wds <= 1) { - /* exact result */ -#ifdef SET_INEXACT - bc.inexact = 0; -#endif - break; - } - delta = dtoa_lshift(delta, Log2P MTb); - if (dtoa_cmp(delta, bs) > 0) goto drop_down; - break; - } - if (i == 0) { - /* exactly half-way between */ - if (bc.dsign) { - if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && - word1(&rv) == - ( -#ifdef Avoid_Underflow - (bc.scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) - ? (0xffffffff & - (0xffffffff << (2 * P + 1 - (y >> Exp_shift)))) - : -#endif - 0xffffffff)) { - /*boundary case -- increment exponent*/ - if (word0(&rv) == Big0 && word1(&rv) == Big1) goto ovfl; - word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1 -#ifdef IBM - | Exp_msk1 >> 4 -#endif - ; - word1(&rv) = 0; -#ifdef Avoid_Underflow - bc.dsign = 0; -#endif - break; - } - } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { - drop_down: - /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(&rv) & Exp_mask; -#ifdef IBM - if (L < Exp_msk1) -#else -#ifdef Avoid_Underflow - if (L <= (bc.scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ -#endif /*IBM*/ - { - if (bc.nd > nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow - if (bc.scale) { - L = word0(&rv) & Exp_mask; - if (L <= (2 * P + 1) * Exp_msk1) { - if (L > (P + 2) * Exp_msk1) /* round even ==> */ - /* accept rv */ - break; - /* rv = smallest denormal */ - if (bc.nd > nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } - } -#endif /*Avoid_Underflow*/ - L = (word0(&rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ - word0(&rv) = L | Bndry_mask1; - word1(&rv) = 0xffffffff; -#ifdef IBM - goto cont; -#else -#ifndef NO_STRTOD_BIGCOMP - if (bc.nd > nd) goto cont; -#endif - break; -#endif - } -#ifndef ROUND_BIASED -#ifdef Avoid_Underflow - if (Lsb1) { - if (!(word0(&rv) & Lsb1)) break; - } else if (!(word1(&rv) & Lsb)) - break; -#else - if (!(word1(&rv) & LSB)) break; -#endif -#endif - if (bc.dsign) -#ifdef Avoid_Underflow - dval(&rv) += dtoa_sulp(&rv, &bc); -#else - dval(&rv) += ulp(&rv); -#endif -#ifndef ROUND_BIASED - else { -#ifdef Avoid_Underflow - dval(&rv) -= dtoa_sulp(&rv, &bc); -#else - dval(&rv) -= ulp(&rv); -#endif -#ifndef Sudden_Underflow - if (!dval(&rv)) { - if (bc.nd > nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } -#endif - } -#ifdef Avoid_Underflow - bc.dsign = 1 - bc.dsign; -#endif -#endif - break; - } - if ((aadj = dtoaratio(delta, bs)) <= 2.) { - if (bc.dsign) - aadj = aadj1 = 1.; - else if (word1(&rv) || word0(&rv) & Bndry_mask) { -#ifndef Sudden_Underflow - if (word1(&rv) == Tiny1 && !word0(&rv)) { - if (bc.nd > nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } -#endif - aadj = 1.; - aadj1 = -1.; - } else { - /* special case -- power of FLT_RADIX to be */ - /* rounded down... */ - - if (aadj < 2. / FLT_RADIX) - aadj = 1. / FLT_RADIX; - else - aadj *= 0.5; - aadj1 = -aadj; - } - } else { - aadj *= 0.5; - aadj1 = bc.dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch (bc.rounding) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (Flt_Rounds == 0) aadj1 += 0.5; -#endif /*Check_FLT_ROUNDS*/ - } - y = word0(&rv) & Exp_mask; - - /* Check for overflow */ - - if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) { - dval(&rv0) = dval(&rv); - word0(&rv) -= P * Exp_msk1; - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - if ((word0(&rv) & Exp_mask) >= Exp_msk1 * (DBL_MAX_EXP + Bias - P)) { - if (word0(&rv0) == Big0 && word1(&rv0) == Big1) goto ovfl; - word0(&rv) = Big0; - word1(&rv) = Big1; - goto cont; - } else - word0(&rv) += P * Exp_msk1; - } else { -#ifdef Avoid_Underflow - if (bc.scale && y <= 2 * P * Exp_msk1) { - if (aadj <= 0x7fffffff) { - if ((z = aadj) <= 0) z = 1; - aadj = z; - aadj1 = bc.dsign ? aadj : -aadj; - } - dval(&aadj2) = aadj1; - word0(&aadj2) += (2 * P + 1) * Exp_msk1 - y; - aadj1 = dval(&aadj2); - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - if (rv.d == 0.) -#ifdef NO_STRTOD_BIGCOMP - goto undfl; -#else - { - req_dtoa_bigcomp = 1; - break; - } -#endif - } else { - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - } -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) { - dval(&rv0) = dval(&rv); - word0(&rv) += P * Exp_msk1; - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; -#ifdef IBM - if ((word0(&rv) & Exp_mask) < P * Exp_msk1) -#else - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) -#endif - { - if (word0(&rv0) == Tiny0 && word1(&rv0) == Tiny1) { - if (bc.nd > nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - goto cont; - } else - word0(&rv) -= P * Exp_msk1; - } else { - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - } -#else /*Sudden_Underflow*/ - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., - * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P - 1) * Exp_msk1 && aadj > 1.) { - aadj1 = (double)(int)(aadj + 0.5); - if (!bc.dsign) aadj1 = -aadj1; - } - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - } - z = word0(&rv) & Exp_mask; -#ifndef SET_INEXACT - if (bc.nd == nd) { -#ifdef Avoid_Underflow - if (!bc.scale) -#endif - if (y == z) { - /* Can we stop now? */ - L = (Long)aadj; - aadj -= L; - /* The tolerances below are conservative. */ - if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) break; - } else if (aadj < .4999999 / FLT_RADIX) - break; - } - } -#endif -cont: - dtoa_bfree(bb MTb); - dtoa_bfree(bd MTb); - dtoa_bfree(bs MTb); - dtoa_bfree(delta MTb); -} -dtoa_bfree(bb MTb); -dtoa_bfree(bd MTb); -dtoa_bfree(bs MTb); -dtoa_bfree(bd0 MTb); -dtoa_bfree(delta MTb); -#ifndef NO_STRTOD_BIGCOMP -if (req_dtoa_bigcomp) { - bd0 = 0; - bc.e0 += nz1; - dtoa_bigcomp(&rv, s0, &bc MTb); - y = word0(&rv) & Exp_mask; - if (y == Exp_mask) goto ovfl; - if (y == 0 && rv.d == 0.) goto undfl; -} -#endif -#ifdef Avoid_Underflow -if (bc.scale) { - word0(&rv0) = Exp_1 - 2 * P * Exp_msk1; - word1(&rv0) = 0; - dval(&rv) *= dval(&rv0); -#ifndef NO_ERRNO - /* try to avoid the bug of testing an 8087 register value */ -#ifdef IEEE_Arith - if (!(word0(&rv) & Exp_mask)) -#else - if (word0(&rv) == 0 && word1(&rv) == 0) -#endif - Set_errno(erange); -#endif -} -#endif /* Avoid_Underflow */ -ret : -#ifdef SET_INEXACT - if (bc.inexact) { - if (!(word0(&rv) & Exp_mask)) { - /* set underflow and inexact bits */ - dval(&rv0) = 1e-300; - dval(&rv0) *= dval(&rv0); - } else if (!oldinexact) { - word0(&rv0) = Exp_1 + (70 << Exp_shift); - word1(&rv0) = 0; - dval(&rv0) += 1.; - } -} -else if (!oldinexact) clear_inexact(); -#endif -if (se) *se = (char *)s; -if (sign) { - return -dval(&rv); -} else { - return dval(&rv); -} -} - -#ifndef MULTIPLE_THREADS -static char *dtoa_result; -#endif - -static char *dtoa_rv_alloc(int i MTd) { - int j, k, *r; - - j = sizeof(ULong); - for (k = 0; sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; j <<= 1) - k++; - r = (int *)dtoa_balloc(k MTa); - *r = k; - return -#ifndef MULTIPLE_THREADS - dtoa_result = -#endif - (char *)(r + 1); -} - -static char *dtoa_nrv_alloc(const char *s, char *s0, size_t s0len, char **rve, - int n MTd) { - char *rv, *t; - - if (!s0) - s0 = dtoa_rv_alloc(n MTa); - else if (s0len <= n) { - rv = 0; - t = rv + n; - goto rve_chk; - } - t = rv = s0; - while ((*t = *s++)) ++t; -rve_chk: - if (rve) *rve = t; - return rv; -} - -/* freedtoa(s) must be used to free values s returned by dtoa - * when MULTIPLE_THREADS is #defined. It should be used in all cases, - * but for consistency with earlier versions of dtoa, it is optional - * when MULTIPLE_THREADS is not defined. - */ - -void freedtoa(char *s) { -#ifdef MULTIPLE_THREADS - ThInfo *TI = 0; -#endif - Bigint *b = (Bigint *)((int *)s - 1); - b->maxwds = 1 << (b->k = *(int *)b); - dtoa_bfree(b MTb); -#ifndef MULTIPLE_THREADS - if (s == dtoa_result) dtoa_result = 0; -#endif -} - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - -char *dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign, - char **rve, char *buf, size_t blen) { - /* Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4,5 ==> similar to 2 and 3, respectively, but (in - round-nearest mode) with the tests of mode 0 to - possibly return a shorter string that rounds to d. - With IEEE arithmetic and compilation with - -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same - as modes 2 and 3 when FLT_ROUNDS != 1. - 6-9 ==> Debugging modes similar to mode - 4: don't try - fast floating-point estimate (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - When not NULL, buf is an output buffer of length blen, which must - be large enough to accommodate suppressed trailing zeros and a trailing - null byte. If blen is too small, rv = NULL is returned, in which case - if rve is not NULL, a subsequent call with blen >= (*rve - rv) + 1 - should succeed in returning buf. - - When buf is NULL, sufficient space is allocated for the return value, - which, when done using, the caller should pass to freedtoa(). - - USE_BF is automatically defined when neither NO_LONG_LONG nor NO_BF96 - is defined. - */ - -#ifdef MULTIPLE_THREADS - ThInfo *TI = 0; -#endif - int bbits, b2, b5, be, dig, i, ilim, ilim1, j, j1, k, leftright, m2, m5, s2, - s5, spec_case; -#if !defined(Sudden_Underflow) || defined(USE_BF96) - int denorm; -#endif - Bigint *b, *b1, *delta, *mlo, *mhi, *S; - U u; - char *s; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif -#ifdef USE_BF96 /*{{*/ - BF96 *p10; - ULLong dbhi, dbits, dblo, den, hb, rb, rblo, res, res0, res3, reslo, sres, - dtoa_sulp, tv0, tv1, tv2, tv3, ulp, ulplo, ulpmask, ures, ureslo, zb; - int eulp, k1, n2, ulpadj, ulpshift; -#else /*}{*/ -#ifndef Sudden_Underflow - ULong x; -#endif - Long L; - U d2, eps; - double ds; - int ieps, ilim0, k0, k_check, try_quick; -#ifndef No_leftright -#ifdef IEEE_Arith - U eps1; -#endif -#endif -#endif /*}}*/ -#ifdef Honor_FLT_ROUNDS /*{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch (fegetround()) { - case FE_TOWARDZERO: - Rounding = 0; - break; - case FE_UPWARD: - Rounding = 2; - break; - case FE_DOWNWARD: - Rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ - - u.d = dd; - if (word0(&u) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(&u) &= ~Sign_bit; /* clear sign bit */ - } else - *sign = 0; - -#if defined(IEEE_Arith) + defined(VAX) -#ifdef IEEE_Arith - if ((word0(&u) & Exp_mask) == Exp_mask) -#else - if (word0(&u) == 0x8000) -#endif - { - /* Infinity or NaN */ - *decpt = 9999; -#ifdef IEEE_Arith - if (!word1(&u) && !(word0(&u) & 0xfffff)) - return dtoa_nrv_alloc("inf", buf, blen, rve, 8 MTb); -#endif - return dtoa_nrv_alloc("nan", buf, blen, rve, 3 MTb); - } -#endif -#ifdef IBM - dval(&u) += 0; /* normalize */ -#endif - if (!dval(&u)) { - *decpt = 1; - return dtoa_nrv_alloc("0", buf, blen, rve, 1 MTb); - } - -#ifdef SET_INEXACT -#ifndef USE_BF96 - try_quick = -#endif - oldinexact = get_inexact(); - inexact = 1; -#endif -#ifdef Honor_FLT_ROUNDS - if (Rounding >= 2) { - if (*sign) - Rounding = Rounding == 2 ? 0 : 2; - else if (Rounding != 2) - Rounding = 0; - } -#endif -#ifdef USE_BF96 /*{{*/ - dbits = (u.LL & 0xfffffffffffffull) << 11; /* fraction bits */ - if ((be = u.LL >> 52)) /* biased exponent; nonzero ==> normal */ { - dbits |= 0x8000000000000000ull; - denorm = ulpadj = 0; - } else { - denorm = 1; - ulpadj = be + 1; - dbits <<= 1; - if (!(dbits & 0xffffffff00000000ull)) { - dbits <<= 32; - be -= 32; - } - if (!(dbits & 0xffff000000000000ull)) { - dbits <<= 16; - be -= 16; - } - if (!(dbits & 0xff00000000000000ull)) { - dbits <<= 8; - be -= 8; - } - if (!(dbits & 0xf000000000000000ull)) { - dbits <<= 4; - be -= 4; - } - if (!(dbits & 0xc000000000000000ull)) { - dbits <<= 2; - be -= 2; - } - if (!(dbits & 0x8000000000000000ull)) { - dbits <<= 1; - be -= 1; - } - assert(be >= -51); - ulpadj -= be; - } - j = kDtoaLhint[be + 51]; - p10 = &kDtoaPten[j]; - dbhi = dbits >> 32; - dblo = dbits & 0xffffffffull; - i = be - 0x3fe; - if (i < p10->e || - (i == p10->e && (dbhi < p10->b0 || (dbhi == p10->b0 && dblo < p10->b1)))) - --j; - k = j - 342; - - /* now 10^k <= dd < 10^(k+1) */ - -#else /*}{*/ - - b = dtoa_d2b(&u, &be, &bbits MTb); -#ifdef Sudden_Underflow - i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)); -#else - if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) { -#endif - dval(&d2) = dval(&u); - word0(&d2) &= Frac_mask1; - word0(&d2) |= Exp_11; -#ifdef IBM - if (j = 11 - dtoa_hi0bits(word0(&d2) & Frac_mask)) dval(&d2) /= 1u << j; -#endif - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ - - i -= Bias; -#ifdef IBM - i <<= 2; - i += j; -#endif -#ifndef Sudden_Underflow - denorm = 0; - } - else { - /* d is denormalized */ - - i = bbits + be + (Bias + (P - 1) - 1); - x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) - : word1(&u) << (32 - i); - dval(&d2) = x; - word0(&d2) -= 31 * Exp_msk1; /* adjust exponent */ - i -= (Bias + (P - 1) - 1) + 1; - denorm = 1; - } -#endif - ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + - i * 0.301029995663981; - k = (int)ds; - if (ds < 0. && ds != k) k--; /* want k = floor(ds) */ - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (dval(&u) < kDtoaTens[k]) k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } else { - b2 -= k; - b5 = -k; - s5 = 0; - } -#endif /*}}*/ - if (mode < 0 || mode > 9) mode = 0; - -#ifndef USE_BF96 -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#endif -#endif /*SET_INEXACT*/ -#endif - - if (mode > 5) { - mode -= 4; -#ifndef USE_BF96 - try_quick = 0; -#endif - } - leftright = 1; - ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ - /* silence erroneous "gcc -Wall" warning. */ - switch (mode) { - case 0: - case 1: - i = 18; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) i = 1; - } - if (!buf) { - buf = dtoa_rv_alloc(i MTb); - blen = sizeof(Bigint) + ((1 << ((int *)buf)[-1]) - 1) * sizeof(ULong) - - sizeof(int); - } else if (blen <= i) { - buf = 0; - if (rve) *rve = buf + i; - return buf; - } - s = buf; - - /* Check for special case that d is a normalized power of 2. */ - - spec_case = 0; - if (mode < 2 || (leftright -#ifdef Honor_FLT_ROUNDS - && Rounding == 1 -#endif - )) { - if (!word1(&u) && !(word0(&u) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(&u) & (Exp_mask & ~Exp_msk1) -#endif - ) { - /* The special case */ - spec_case = 1; - } - } - -#ifdef USE_BF96 /*{*/ - b = 0; - if (ilim < 0 && (mode == 3 || mode == 5)) { - S = mhi = 0; - goto no_digits; - } - i = 1; - j = 52 + 0x3ff - be; - ulpshift = 0; - ulplo = 0; - /* Can we do an exact computation with 64-bit integer arithmetic? */ - if (k < 0) { - if (k < -25) goto toobig; - res = dbits >> 11; - n2 = kDtoaPfiveBits[k1 = -(k + 1)] + 53; - j1 = j; - if (n2 > 61) { - ulpshift = n2 - 61; - if (res & (ulpmask = (1ull << ulpshift) - 1)) goto toobig; - j -= ulpshift; - res >>= ulpshift; - } - /* Yes. */ - res *= ulp = kDtoaPfive[k1]; - if (ulpshift) { - ulplo = ulp; - ulp >>= ulpshift; - } - j += k; - if (ilim == 0) { - S = mhi = 0; - if (res > (5ull << j)) goto one_digit; - goto no_digits; - } - goto no_div; - } - if (ilim == 0 && j + k >= 0) { - S = mhi = 0; - if ((dbits >> 11) > (kDtoaPfive[k - 1] << j)) goto one_digit; - goto no_digits; - } - if (k <= dtoa_divmax && j + k >= 0) { - /* Another "yes" case -- we will use exact integer arithmetic. */ - use_exact: - Debug(++dtoa_stats[3]); - res = dbits >> 11; /* residual */ - ulp = 1; - if (k <= 0) goto no_div; - j1 = j + k + 1; - den = kDtoaPfive[k - i] << (j1 - i); - for (;;) { - dig = res / den; - *s++ = '0' + dig; - if (!(res -= dig * den)) { -#ifdef SET_INEXACT - inexact = 0; - oldinexact = 1; -#endif - goto retc; - } - if (ilim < 0) { - ures = den - res; - if (2 * res <= ulp && - (spec_case ? 4 * res <= ulp : (2 * res < ulp || dig & 1))) - goto ulp_reached; - if (2 * ures < ulp) goto Roundup; - } else if (i == ilim) { - switch (Rounding) { - case 0: - goto retc; - case 2: - goto Roundup; - default: - (void)0; /* added by jart */ - } - ures = 2 * res; - if (ures > den || (ures == den && dig & 1) || - (spec_case && res <= ulp && 2 * res >= ulp)) - goto Roundup; - goto retc; - } - if (j1 < ++i) { - res *= 10; - ulp *= 10; - } else { - if (i > k) break; - den = kDtoaPfive[k - i] << (j1 - i); - } - } - no_div: - for (;;) { - dig = den = res >> j; - *s++ = '0' + dig; - if (!(res -= den << j)) { -#ifdef SET_INEXACT - inexact = 0; - oldinexact = 1; -#endif - goto retc; - } - if (ilim < 0) { - ures = (1ull << j) - res; - if (2 * res <= ulp && - (spec_case ? 4 * res <= ulp : (2 * res < ulp || dig & 1))) { - ulp_reached: - if (ures < res || (ures == res && dig & 1)) goto Roundup; - goto retc; - } - if (2 * ures < ulp) goto Roundup; - } - --j; - if (i == ilim) { -#ifdef Honor_FLT_ROUNDS - switch (Rounding) { - case 0: - goto retc; - case 2: - goto Roundup; - } -#endif - hb = 1ull << j; - if (res & hb && (dig & 1 || res & (hb - 1))) goto Roundup; - if (spec_case && res <= ulp && 2 * res >= ulp) { - Roundup: - while (*--s == '9') - if (s == buf) { - ++k; - *s++ = '1'; - goto ret1; - } - ++*s++; - goto ret1; - } - goto retc; - } - ++i; - res *= 5; - if (ulpshift) { - ulplo = 5 * (ulplo & ulpmask); - ulp = 5 * ulp + (ulplo >> ulpshift); - } else - ulp *= 5; - } - } -toobig: - if (ilim > 28) goto Fast_failed1; - /* Scale by 10^-k */ - p10 = &kDtoaPten[342 - k]; - tv0 = p10->b2 * - dblo; /* rarely matters, but does, e.g., for 9.862818194192001e18 */ - tv1 = p10->b1 * dblo + (tv0 >> 32); - tv2 = p10->b2 * dbhi + (tv1 & 0xffffffffull); - tv3 = p10->b0 * dblo + (tv1 >> 32) + (tv2 >> 32); - res3 = p10->b1 * dbhi + (tv3 & 0xffffffffull); - res = p10->b0 * dbhi + (tv3 >> 32) + (res3 >> 32); - be += p10->e - 0x3fe; - eulp = j1 = be - 54 + ulpadj; - if (!(res & 0x8000000000000000ull)) { - --be; - res3 <<= 1; - res = (res << 1) | ((res3 & 0x100000000ull) >> 32); - } - res0 = res; /* save for Fast_failed */ -#if !defined(SET_INEXACT) && !defined(NO_DTOA_64) /*{*/ - if (ilim > 19) goto Fast_failed; - Debug(++dtoa_stats[4]); - assert(be >= 0 && be <= 4); /* be = 0 is rare, but possible, e.g., for 1e20 */ - res >>= 4 - be; - ulp = p10->b0; /* ulp */ - ulp = (ulp << 29) | (p10->b1 >> 3); - /* scaled ulp = ulp * 2^(eulp - 60) */ - /* We maintain 61 bits of the scaled ulp. */ - if (ilim == 0) { - if (!(res & 0x7fffffffffffffeull) || !((~res) & 0x7fffffffffffffeull)) - goto Fast_failed1; - S = mhi = 0; - if (res >= 0x5000000000000000ull) goto one_digit; - goto no_digits; - } - rb = 1; /* upper bound on rounding error */ - for (;; ++i) { - dig = res >> 60; - *s++ = '0' + dig; - res &= 0xfffffffffffffffull; - if (ilim < 0) { - ures = 0x1000000000000000ull - res; - if (eulp > 0) { - assert(eulp <= 4); - dtoa_sulp = ulp << (eulp - 1); - if (res <= ures) { - if (res + rb > ures - rb) goto Fast_failed; - if (res < dtoa_sulp) goto retc; - } else { - if (res - rb <= ures + rb) goto Fast_failed; - if (ures < dtoa_sulp) goto Roundup; - } - } else { - zb = -(1ull << (eulp + 63)); - if (!(zb & res)) { - sres = res << (1 - eulp); - if (sres < ulp && (!spec_case || 2 * sres < ulp)) { - if ((res + rb) << (1 - eulp) >= ulp) goto Fast_failed; - if (ures < res) { - if (ures + rb >= res - rb) goto Fast_failed; - goto Roundup; - } - if (ures - rb < res + rb) goto Fast_failed; - goto retc; - } - } - if (!(zb & ures) && ures << -eulp < ulp) { - if (ures << (1 - eulp) < ulp) goto Roundup; - goto Fast_failed; - } - } - } else if (i == ilim) { - ures = 0x1000000000000000ull - res; - if (ures < res) { - if (ures <= rb || res - rb <= ures + rb) { - if (j + k >= 0 && k >= 0 && k <= 27) goto use_exact1; - goto Fast_failed; - } -#ifdef Honor_FLT_ROUNDS - if (Rounding == 0) goto retc; -#endif - goto Roundup; - } - if (res <= rb || ures - rb <= res + rb) { - if (j + k >= 0 && k >= 0 && k <= 27) { - use_exact1: - s = buf; - i = 1; - goto use_exact; - } - goto Fast_failed; - } -#ifdef Honor_FLT_ROUNDS - if (Rounding == 2) goto Roundup; -#endif - goto retc; - } - rb *= 10; - if (rb >= 0x1000000000000000ull) goto Fast_failed; - res *= 10; - ulp *= 5; - if (ulp & 0x8000000000000000ull) { - eulp += 4; - ulp >>= 3; - } else { - eulp += 3; - ulp >>= 2; - } - } -#endif /*}*/ -#ifndef NO_BF96 -Fast_failed: -#endif - Debug(++dtoa_stats[5]); - s = buf; - i = 4 - be; - res = res0 >> i; - reslo = 0xffffffffull & res3; - if (i) reslo = (res0 << (64 - i)) >> 32 | (reslo >> i); - rb = 0; - rblo = 4; /* roundoff bound */ - ulp = p10->b0; /* ulp */ - ulp = (ulp << 29) | (p10->b1 >> 3); - eulp = j1; - for (i = 1;; ++i) { - dig = res >> 60; - *s++ = '0' + dig; - res &= 0xfffffffffffffffull; -#ifdef SET_INEXACT - if (!res && !reslo) { - if (!(res3 & 0xffffffffull)) { - inexact = 0; - oldinexact = 1; - } - goto retc; - } -#endif - if (ilim < 0) { - ures = 0x1000000000000000ull - res; - ureslo = 0; - if (reslo) { - ureslo = 0x100000000ull - reslo; - --ures; - } - if (eulp > 0) { - assert(eulp <= 4); - dtoa_sulp = (ulp << (eulp - 1)) - rb; - if (res <= ures) { - if (res < dtoa_sulp) { - if (res + rb < ures - rb) goto retc; - } - } else if (ures < dtoa_sulp) { - if (res - rb > ures + rb) goto Roundup; - } - goto Fast_failed1; - } else { - zb = -(1ull << (eulp + 60)); - if (!(zb & (res + rb))) { - sres = (res - rb) << (1 - eulp); - if (sres < ulp && (!spec_case || 2 * sres < ulp)) { - sres = res << (1 - eulp); - if ((j = eulp + 31) > 0) - sres += (rblo + reslo) >> j; - else - sres += (rblo + reslo) << -j; - if (sres + (rb << (1 - eulp)) >= ulp) goto Fast_failed1; - if (sres >= ulp) goto more96; - if (ures < res || (ures == res && ureslo < reslo)) { - if (ures + rb >= res - rb) goto Fast_failed1; - goto Roundup; - } - if (ures - rb <= res + rb) goto Fast_failed1; - goto retc; - } - } - if (!(zb & ures) && (ures - rb) << (1 - eulp) < ulp) { - if ((ures + rb) << (1 - eulp) < ulp) goto Roundup; - goto Fast_failed1; - } - } - } else if (i == ilim) { - ures = 0x1000000000000000ull - res; - sres = ureslo = 0; - if (reslo) { - ureslo = 0x100000000ull - reslo; - --ures; - sres = (reslo + rblo) >> 31; - } - sres += 2 * rb; - if (ures <= res) { - if (ures <= sres || res - ures <= sres) goto Fast_failed1; -#ifdef Honor_FLT_ROUNDS - if (Rounding == 0) goto retc; -#endif - goto Roundup; - } - if (res <= sres || ures - res <= sres) goto Fast_failed1; -#ifdef Honor_FLT_ROUNDS - if (Rounding == 2) goto Roundup; -#endif - goto retc; - } - more96: - rblo *= 10; - rb = 10 * rb + (rblo >> 32); - rblo &= 0xffffffffull; - if (rb >= 0x1000000000000000ull) goto Fast_failed1; - reslo *= 10; - res = 10 * res + (reslo >> 32); - reslo &= 0xffffffffull; - ulp *= 5; - if (ulp & 0x8000000000000000ull) { - eulp += 4; - ulp >>= 3; - } else { - eulp += 3; - ulp >>= 2; - } - } -Fast_failed1: - Debug(++dtoa_stats[6]); - S = mhi = mlo = 0; -#ifdef USE_BF96 - b = dtoa_d2b(&u, &be, &bbits MTb); -#endif - s = buf; - i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)); - i -= Bias; - if (ulpadj) i -= ulpadj - 1; - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } else { - b2 -= k; - b5 = -k; - s5 = 0; - } -#endif /*}*/ - -#ifdef Honor_FLT_ROUNDS - if (mode > 1 && Rounding != 1) leftright = 0; -#endif - -#ifndef USE_BF96 /*{*/ - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - dval(&d2) = dval(&u); - j1 = -(k0 = k); - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = kDtoaTens[k & 0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - dval(&u) /= kDtoaBigTens[n_bigtens - 1]; - ieps++; - } - for (; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= kDtoaBigTens[i]; - } - dval(&u) /= ds; - } else if (j1 > 0) { - dval(&u) *= kDtoaTens[j1 & 0xf]; - for (j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - dval(&u) *= kDtoaBigTens[i]; - } - } - if (k_check && dval(&u) < 1. && ilim > 0) { - if (ilim1 <= 0) goto fast_failed; - ilim = ilim1; - k--; - dval(&u) *= 10.; - ieps++; - } - dval(&eps) = ieps * dval(&u) + 7.; - word0(&eps) -= (P - 1) * Exp_msk1; - if (ilim == 0) { - S = mhi = 0; - dval(&u) -= 5.; - if (dval(&u) > dval(&eps)) goto one_digit; - if (dval(&u) < -dval(&eps)) goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - dval(&eps) = 0.5 / kDtoaTens[ilim - 1] - dval(&eps); -#ifdef IEEE_Arith - if (j1 >= 307) { - eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */ - word0(&eps1) -= Exp_msk1 * (Bias + P - 1); - dval(&eps1) *= kDtoaTens[j1 & 0xf]; - for (i = 0, j = (j1 - 256) >> 4; j; j >>= 1, i++) - if (j & 1) dval(&eps1) *= kDtoaBigTens[i]; - if (eps.d < eps1.d) eps.d = eps1.d; - if (10. - u.d < 10. * eps.d && eps.d < 1.) { - /* eps.d < 1. excludes trouble with the tiniest denormal */ - *s++ = '1'; - ++k; - goto ret1; - } - } -#endif - for (i = 0;;) { - L = dval(&u); - dval(&u) -= L; - *s++ = '0' + (int)L; - if (1. - dval(&u) < dval(&eps)) goto bump_up; - if (dval(&u) < dval(&eps)) goto retc; - if (++i >= ilim) break; - dval(&eps) *= 10.; - dval(&u) *= 10.; - } - } else { -#endif - /* Generate ilim digits, then fix them up. */ - dval(&eps) *= kDtoaTens[ilim - 1]; - for (i = 1;; i++, dval(&u) *= 10.) { - L = (Long)(dval(&u)); - if (!(dval(&u) -= L)) ilim = i; - *s++ = '0' + (int)L; - if (i == ilim) { - if (dval(&u) > 0.5 + dval(&eps)) - goto bump_up; - else if (dval(&u) < 0.5 - dval(&eps)) - goto retc; - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = buf; - dval(&u) = dval(&d2); - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= Int_max) { - /* Yes. */ - ds = kDtoaTens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || dval(&u) <= 5 * ds) goto no_digits; - goto one_digit; - } - for (i = 1;; i++, dval(&u) *= 10.) { - L = (Long)(dval(&u) / ds); - dval(&u) -= L * ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&u) < 0) { - L--; - dval(&u) += ds; - } -#endif - *s++ = '0' + (int)L; - if (!dval(&u)) { -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - if (i == ilim) { -#ifdef Honor_FLT_ROUNDS - if (mode > 1) switch (Rounding) { - case 0: - goto retc; - case 2: - goto bump_up; - } -#endif - dval(&u) += dval(&u); -#ifdef ROUND_BIASED - if (dval(&u) >= ds) -#else - if (dval(&u) > ds || (dval(&u) == ds && L & 1)) -#endif - { - bump_up: - while (*--s == '9') - if (s == buf) { - k++; - *s = '0'; - break; - } - ++*s++; - } - break; - } - } - goto retc; - } - -#endif /*}*/ - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P - 1) - 1 + 1) : -#endif -#ifdef IBM - 1 + 4 * P - 3 - bbits + ((bbits + be - 1) & 3); -#else - 1 + P - bbits; -#endif - b2 += i; - s2 += i; - mhi = dtoa_i2b(1 MTb); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = dtoa_pow5mult(mhi, m5 MTb); - b1 = dtoa_mult(mhi, b MTb); - dtoa_bfree(b MTb); - b = b1; - } - if ((j = b5 - m5)) b = dtoa_pow5mult(b, j MTb); - } else - b = dtoa_pow5mult(b, b5 MTb); - } - S = dtoa_i2b(1 MTb); - if (s5 > 0) S = dtoa_pow5mult(S, s5 MTb); - - if (spec_case) { - b2 += Log2P; - s2 += Log2P; - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to dtoa_quorem, so it - * can do shifts and ors to compute the numerator for q. - */ - i = dtoa_dshift(S, s2); - b2 += i; - m2 += i; - s2 += i; - if (b2 > 0) b = dtoa_lshift(b, b2 MTb); - if (s2 > 0) S = dtoa_lshift(S, s2 MTb); -#ifndef USE_BF96 - if (k_check) { - if (dtoa_cmp(b, S) < 0) { - k--; - b = dtoa_multadd(b, 10, 0 MTb); /* we botched the k estimate */ - if (leftright) mhi = dtoa_multadd(mhi, 10, 0 MTb); - ilim = ilim1; - } - } -#endif - if (ilim <= 0 && (mode == 3 || mode == 5)) { - if (ilim < 0 || dtoa_cmp(b, S = dtoa_multadd(S, 5, 0 MTb)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - goto ret; - } - one_digit: - *s++ = '1'; - ++k; - goto ret; - } - if (leftright) { - if (m2 > 0) mhi = dtoa_lshift(mhi, m2 MTb); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = dtoa_balloc(mhi->k MTb); - Bcopy(mhi, mlo); - mhi = dtoa_lshift(mhi, Log2P MTb); - } - - for (i = 1;; i++) { - dig = dtoa_quorem(b, S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = dtoa_cmp(b, mlo); - delta = dtoa_diff(S, mhi MTb); - j1 = delta->sign ? 1 : dtoa_cmp(b, delta); - dtoa_bfree(delta MTb); -#ifndef ROUND_BIASED - if (j1 == 0 && mode != 1 && !(word1(&u) & 1) -#ifdef Honor_FLT_ROUNDS - && (mode <= 1 || Rounding >= 1) -#endif - ) { - if (dig == '9') goto round_9_up; - if (j > 0) dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && mode != 1 -#ifndef ROUND_BIASED - && !(word1(&u) & 1) -#endif - )) { - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto accept_dig; - } -#ifdef Honor_FLT_ROUNDS - if (mode > 1) switch (Rounding) { - case 0: - goto accept_dig; - case 2: - goto keep_dig; - } -#endif /*Honor_FLT_ROUNDS*/ - if (j1 > 0) { - b = dtoa_lshift(b, 1 MTb); - j1 = dtoa_cmp(b, S); -#ifdef ROUND_BIASED - if (j1 >= 0 /*)*/ -#else - if ((j1 > 0 || (j1 == 0 && dig & 1)) -#endif - && dig++ == '9') - goto round_9_up; - } - accept_dig: - *s++ = dig; - goto ret; - } - if (j1 > 0) { -#ifdef Honor_FLT_ROUNDS - if (!Rounding && mode > 1) goto accept_dig; -#endif - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = dig + 1; - goto ret; - } -#ifdef Honor_FLT_ROUNDS - keep_dig: -#endif - *s++ = dig; - if (i == ilim) break; - b = dtoa_multadd(b, 10, 0 MTb); - if (mlo == mhi) - mlo = mhi = dtoa_multadd(mhi, 10, 0 MTb); - else { - mlo = dtoa_multadd(mlo, 10, 0 MTb); - mhi = dtoa_multadd(mhi, 10, 0 MTb); - } - } - } else - for (i = 1;; i++) { - dig = dtoa_quorem(b, S) + '0'; - *s++ = dig; - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto ret; - } - if (i >= ilim) break; - b = dtoa_multadd(b, 10, 0 MTb); - } - - /* Round off last digit */ - -#ifdef Honor_FLT_ROUNDS - if (mode > 1) switch (Rounding) { - case 0: - goto ret; - case 2: - goto roundoff; - } -#endif - b = dtoa_lshift(b, 1 MTb); - j = dtoa_cmp(b, S); -#ifdef ROUND_BIASED - if (j >= 0) -#else - if (j > 0 || (j == 0 && dig & 1)) -#endif - { - roundoff: - while (*--s == '9') - if (s == buf) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } -ret: - dtoa_bfree(S MTb); - if (mhi) { - if (mlo && mlo != mhi) dtoa_bfree(mlo MTb); - dtoa_bfree(mhi MTb); - } -retc: - while (s > buf && s[-1] == '0') --s; -ret1: - if (b) dtoa_bfree(b MTb); - *s = 0; - *decpt = k + 1; - if (rve) *rve = s; -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&u) = Exp_1 + (70 << Exp_shift); - word1(&u) = 0; - dval(&u) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif - return buf; -} - -char *dtoa(double dd, int mode, int ndigits, int *decpt, int *sign, - char **rve) { - /* Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - See dtoa_r() above for details on the other arguments. - */ -#ifndef MULTIPLE_THREADS - if (dtoa_result) freedtoa(dtoa_result); -#endif - return dtoa_r(dd, mode, ndigits, decpt, sign, rve, 0, 0); -} - -#ifdef __cplusplus -} -#endif diff --git a/third_party/dtoa/dtoa.h b/third_party/dtoa/dtoa.h deleted file mode 100644 index 15e1b3fc..00000000 --- a/third_party/dtoa/dtoa.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_ -#define COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -char *g_fmt(char *buf /*[32]*/, double x); -char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, - char **rve) nodiscard; -void freedtoa(char *s); -char *dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign, - char **rve, char *buf, size_t blen); - -double strtod(const char *, char **); -double plan9_strtod(const char *, char **); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_ */ diff --git a/third_party/dtoa/dtoa.mk b/third_party/dtoa/dtoa.mk deleted file mode 100644 index 5815c142..00000000 --- a/third_party/dtoa/dtoa.mk +++ /dev/null @@ -1,62 +0,0 @@ -#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ -#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ - -PKGS += THIRD_PARTY_DTOA - -THIRD_PARTY_DTOA_ARTIFACTS += THIRD_PARTY_DTOA_A -THIRD_PARTY_DTOA = $(THIRD_PARTY_DTOA_A_DEPS) $(THIRD_PARTY_DTOA_A) -THIRD_PARTY_DTOA_A = o/$(MODE)/third_party/dtoa/dtoa.a -THIRD_PARTY_DTOA_A_FILES := $(wildcard third_party/dtoa/*) -THIRD_PARTY_DTOA_A_HDRS = $(filter %.h,$(THIRD_PARTY_DTOA_A_FILES)) -THIRD_PARTY_DTOA_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_DTOA_A_FILES)) -THIRD_PARTY_DTOA_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_DTOA_A_FILES)) - -THIRD_PARTY_DTOA_A_SRCS = \ - $(THIRD_PARTY_DTOA_A_SRCS_S) \ - $(THIRD_PARTY_DTOA_A_SRCS_C) - -THIRD_PARTY_DTOA_A_OBJS = \ - $(THIRD_PARTY_DTOA_A_SRCS:%=o/$(MODE)/%.zip.o) \ - $(THIRD_PARTY_DTOA_A_SRCS_S:%.S=o/$(MODE)/%.o) \ - $(THIRD_PARTY_DTOA_A_SRCS_C:%.c=o/$(MODE)/%.o) - -THIRD_PARTY_DTOA_A_CHECKS = \ - $(THIRD_PARTY_DTOA_A).pkg \ - $(THIRD_PARTY_DTOA_A_HDRS:%=o/$(MODE)/%.ok) - -THIRD_PARTY_DTOA_A_DIRECTDEPS = \ - LIBC_TINYMATH \ - LIBC_STR \ - LIBC_STUBS \ - LIBC_MEM \ - LIBC_NEXGEN32E \ - LIBC_SYSV - -THIRD_PARTY_DTOA_A_DEPS := \ - $(call uniq,$(foreach x,$(THIRD_PARTY_DTOA_A_DIRECTDEPS),$($(x)))) - -$(THIRD_PARTY_DTOA_A): \ - third_party/dtoa/ \ - $(THIRD_PARTY_DTOA_A).pkg \ - $(THIRD_PARTY_DTOA_A_OBJS) - -$(THIRD_PARTY_DTOA_A).pkg: \ - $(THIRD_PARTY_DTOA_A_OBJS) \ - $(foreach x,$(THIRD_PARTY_DTOA_A_DIRECTDEPS),$($(x)_A).pkg) - -$(THIRD_PARTY_DTOA_A_OBJS): \ - OVERRIDE_CFLAGS += \ - $(OLD_CODE) \ - $(IEEE_MATH) \ - -ffunction-sections \ - -fdata-sections - -THIRD_PARTY_DTOA_LIBS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x))) -THIRD_PARTY_DTOA_SRCS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_SRCS)) -THIRD_PARTY_DTOA_HDRS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_HDRS)) -THIRD_PARTY_DTOA_CHECKS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_CHECKS)) -THIRD_PARTY_DTOA_OBJS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_OBJS)) -$(THIRD_PARTY_DTOA_OBJS): $(BUILD_FILES) third_party/dtoa/dtoa.mk - -.PHONY: o/$(MODE)/third_party/dtoa -o/$(MODE)/third_party/dtoa: $(THIRD_PARTY_DTOA_CHECKS) diff --git a/third_party/dtoa/g_fmt.c b/third_party/dtoa/g_fmt.c deleted file mode 100644 index e263ab5b..00000000 --- a/third_party/dtoa/g_fmt.c +++ /dev/null @@ -1,114 +0,0 @@ -#pragma GCC diagnostic ignored "-Wparentheses" -#pragma GCC diagnostic ignored "-Wunused-label" - -asm(".ident\t\"\\n\\n\ -dtoa (MIT License)\\n\ -The author of this software is David M. Gay.\\n\ -Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\""); -asm(".include \"libc/disclaimer.inc\""); - -/* clang-format off */ -/**************************************************************** - * - * The author of this software is David M. Gay. - * - * Copyright (c) 1991, 1996 by Lucent Technologies. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - * - ***************************************************************/ - -/* g_fmt(buf,x) stores the closest decimal approximation to x in buf; - * it suffices to declare buf - * char buf[32]; - */ - -#ifdef __cplusplus -extern "C" { -#endif - extern char *dtoa(double, int, int, int *, int *, char **); - extern char *g_fmt(char *, double); - extern void freedtoa(char*); -#ifdef __cplusplus - } -#endif - - char * -g_fmt(register char *b, double x) -{ - register int i, k; - register char *s; - int decpt, j, sign; - char *b0, *s0, *se; - - b0 = b; -#ifdef IGNORE_ZERO_SIGN - if (!x) { - *b++ = '0'; - *b = 0; - goto done; - } -#endif - s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se); - if (sign) - *b++ = '-'; - if (decpt == 9999) /* Infinity or Nan */ { - while(*b++ = *s++); - goto done0; - } - if (decpt <= -4 || decpt > se - s + 5) { - *b++ = *s++; - if (*s) { - *b++ = '.'; - while(*b = *s++) - b++; - } - *b++ = 'e'; - /* sprintf(b, "%+.2d", decpt - 1); */ - if (--decpt < 0) { - *b++ = '-'; - decpt = -decpt; - } - else - *b++ = '+'; - for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); - for(;;) { - i = decpt / k; - *b++ = i + '0'; - if (--j <= 0) - break; - decpt -= i*k; - decpt *= 10; - } - *b = 0; - } - else if (decpt <= 0) { - *b++ = '.'; - for(; decpt < 0; decpt++) - *b++ = '0'; - while(*b++ = *s++); - } - else { - while(*b = *s++) { - b++; - if (--decpt == 0 && *s) - *b++ = '.'; - } - for(; decpt > 0; decpt--) - *b++ = '0'; - *b = 0; - } - done0: - freedtoa(s0); - done: - return b0; - } diff --git a/third_party/dtoa/strtod.c b/third_party/dtoa/strtod.c deleted file mode 100644 index 64634b0a..00000000 --- a/third_party/dtoa/strtod.c +++ /dev/null @@ -1,531 +0,0 @@ -#include "libc/macros.h" -#include "libc/str/str.h" -#include "third_party/dtoa/dtoa.h" - -/** - * @fileoverview Plan 9 strtod(). - * It's like dtoa but smaller. - */ - -asm(".ident\t\"\\n\\n\ -Plan 9 » strtod (MIT)\\n\ -The authors of this software are Rob Pike and Ken Thompson.\\n\ -Copyright (c) 2002 by Lucent Technologies.\""); -asm(".include \"libc/disclaimer.inc\""); - -#define nelem(a) ARRAYLEN(a) -#define ulong unsigned long -#define nil NULL -#define __NaN() __builtin_nanf("") - -/* clang-format off */ -/* The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ - -#include "libc/str/str.h" -#include "libc/math.h" -#include "libc/sysv/errfuns.h" - -static ulong -umuldiv(ulong a, ulong b, ulong c) -{ - double d; - - d = ((double)a * (double)b) / (double)c; - if(d >= 4294967295.) - d = 4294967295.; - return (ulong)d; -} - -/* - * This routine will convert to arbitrary precision - * floating point entirely in multi-precision fixed. - * The answer is the closest floating point number to - * the given decimal number. Exactly half way are - * rounded ala ieee rules. - * Method is to scale input decimal between .500 and .999... - * with external power of 2, then binary search for the - * closest mantissa to this decimal number. - * Nmant is is the required precision. (53 for ieee dp) - * Nbits is the max number of bits/word. (must be <= 28) - * Prec is calculated - the number of words of fixed mantissa. - */ -enum -{ - Nbits = 28, /* bits safely represented in a ulong */ - Nmant = 53, /* bits of precision required */ - Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */ - Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */ - Ndig = 1500, - One = (ulong)(1<>1), - Maxe = 310, - - Fsign = 1<<0, /* found - */ - Fesign = 1<<1, /* found e- */ - Fdpoint = 1<<2, /* found . */ - - S0 = 0, /* _ _S0 +S1 #S2 .S3 */ - S1, /* _+ #S2 .S3 */ - S2, /* _+# #S2 .S4 eS5 */ - S3, /* _+. #S4 */ - S4, /* _+#.# #S4 eS5 */ - S5, /* _+#.#e +S6 #S7 */ - S6, /* _+#.#e+ #S7 */ - S7 /* _+#.#e+# #S7 */ -}; - -static int fpcmp(char*, ulong*); -static void frnorm(ulong*); -static void divascii(char*, int*, int*, int*); -static void mulascii(char*, int*, int*, int*); - -typedef struct Tab Tab; -struct Tab -{ - int bp; - int siz; - char* cmp; -}; - -double -plan9_strtod(const char *as, char **aas) -{ - int na, ex, dp, bp, c, i, flag, state; - ulong low[Prec], hig[Prec], mid[Prec]; - double d; - char *s, a[Ndig]; - - flag = 0; /* Fsign, Fesign, Fdpoint */ - na = 0; /* number of digits of a[] */ - dp = 0; /* na of decimal point */ - ex = 0; /* exonent */ - - state = S0; - for(s=(char*)as;; s++) { - c = *s; - if(c >= '0' && c <= '9') { - switch(state) { - case S0: - case S1: - case S2: - state = S2; - break; - case S3: - case S4: - state = S4; - break; - - case S5: - case S6: - case S7: - state = S7; - ex = ex*10 + (c-'0'); - continue; - } - if(na == 0 && c == '0') { - dp--; - continue; - } - if(na < Ndig-50) - a[na++] = c; - continue; - } - switch(c) { - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - if(state == S0) - continue; - break; - case '-': - if(state == S0) - flag |= Fsign; - else - flag |= Fesign; - case '+': - if(state == S0) - state = S1; - else - if(state == S5) - state = S6; - else - break; /* syntax */ - continue; - case '.': - flag |= Fdpoint; - dp = na; - if(state == S0 || state == S1) { - state = S3; - continue; - } - if(state == S2) { - state = S4; - continue; - } - break; - case 'e': - case 'E': - if(state == S2 || state == S4) { - state = S5; - continue; - } - break; - } - break; - } - - /* - * clean up return char-pointer - */ - switch(state) { - case S0: - if(strcasecmp(s, "nan") == 0) { - if(aas != nil) - *aas = s+3; - goto retnan; - } - case S1: - if(strcasecmp(s, "infinity") == 0) { - if(aas != nil) - *aas = s+8; - goto retinf; - } - if(strcasecmp(s, "inf") == 0) { - if(aas != nil) - *aas = s+3; - goto retinf; - } - case S3: - if(aas != nil) - *aas = (char*)as; - goto ret0; /* no digits found */ - case S6: - s--; /* back over +- */ - case S5: - s--; /* back over e */ - break; - } - if(aas != nil) - *aas = s; - - if(flag & Fdpoint) - while(na > 0 && a[na-1] == '0') - na--; - if(na == 0) - goto ret0; /* zero */ - a[na] = 0; - if(!(flag & Fdpoint)) - dp = na; - if(flag & Fesign) - ex = -ex; - dp += ex; - if(dp < -Maxe){ - erange(); - goto ret0; /* underflow by exp */ - } else - if(dp > +Maxe) - goto retinf; /* overflow by exp */ - - /* - * normalize the decimal ascii number - * to range .[5-9][0-9]* e0 - */ - bp = 0; /* binary exponent */ - while(dp > 0) - divascii(a, &na, &dp, &bp); - while(dp < 0 || a[0] < '5') - mulascii(a, &na, &dp, &bp); - - /* close approx by naïve conversion */ - mid[0] = 0; - mid[1] = 1; - for(i=0; (c=a[i]) != '\0'; i++) { - mid[0] = mid[0]*10 + (c-'0'); - mid[1] = mid[1]*10; - if(i >= 8) - break; - } - low[0] = umuldiv(mid[0], One, mid[1]); - hig[0] = umuldiv(mid[0]+1, One, mid[1]); - for(i=1; i>= 1; - } - frnorm(mid); - - /* compare */ - c = fpcmp(a, mid); - if(c > 0) { - c = 1; - for(i=0; i= Sigbit/2) { - mid[Prec-1] += Sigbit; - frnorm(mid); - } - goto out; - -ret0: - return 0; - -retnan: - return __NaN(); - -retinf: - /* - * Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */ - erange(); - if(flag & Fsign) - return -HUGE_VAL; - return HUGE_VAL; - -out: - d = 0; - for(i=0; i0; i--) { - f[i] += c; - c = f[i] >> Nbits; - f[i] &= One-1; - } - f[0] += c; -} - -static int -fpcmp(char *a, ulong* f) -{ - ulong tf[Prec]; - int i, d, c; - - for(i=0; i> Nbits) + '0'; - tf[0] &= One-1; - - /* compare next digit */ - c = *a; - if(c == 0) { - if('0' < d) - return -1; - if(tf[0] != 0) - goto cont; - for(i=1; i d) - return +1; - if(c < d) - return -1; - a++; - cont:; - } -} - -static void -divby(char *a, int *na, int b) -{ - int n, c; - char *p; - - p = a; - n = 0; - while(n>>b == 0) { - c = *a++; - if(c == 0) { - while(n) { - c = n*10; - if(c>>b) - break; - n = c; - } - goto xx; - } - n = n*10 + c-'0'; - (*na)--; - } - for(;;) { - c = n>>b; - n -= c<>b; - n -= c<= (int)(nelem(tab1))) - d = (int)(nelem(tab1))-1; - t = tab1 + d; - b = t->bp; - if(memcmp(a, t->cmp, t->siz) > 0) - d--; - *dp -= d; - *bp += b; - divby(a, na, b); -} - -static void -mulby(char *a, char *p, char *q, int b) -{ - int n, c; - - n = 0; - *p = 0; - for(;;) { - q--; - if(q < a) - break; - c = *q - '0'; - c = (c<= (int)(nelem(tab2))) - d = (int)(nelem(tab2))-1; - t = tab2 + d; - b = t->bp; - if(memcmp(a, t->cmp, t->siz) < 0) - d--; - p = a + *na; - *bp -= b; - *dp += d; - *na += d; - mulby(a, p+d, p, b); -} diff --git a/third_party/duktape/duk_config.h b/third_party/duktape/duk_config.h index 441c0dfc..39323b46 100644 --- a/third_party/duktape/duk_config.h +++ b/third_party/duktape/duk_config.h @@ -786,7 +786,7 @@ * Disabled temporarily in GCC 5+ because of an unresolved noreturn-related * issue: https://github.com/svaarala/duktape/issues/2155. */ -#define DUK_NORETURN(decl) decl noreturn +#define DUK_NORETURN(decl) decl wontreturn #endif #if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) diff --git a/third_party/gdtoa/dmisc.c b/third_party/gdtoa/dmisc.c index 0850f6e4..9ddd5be1 100644 --- a/third_party/gdtoa/dmisc.c +++ b/third_party/gdtoa/dmisc.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/dtoa.c b/third_party/gdtoa/dtoa.c index 4c662e87..65892671 100644 --- a/third_party/gdtoa/dtoa.c +++ b/third_party/gdtoa/dtoa.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_Qfmt.c b/third_party/gdtoa/g_Qfmt.c index 69d0507a..cd3f09e4 100644 --- a/third_party/gdtoa/g_Qfmt.c +++ b/third_party/gdtoa/g_Qfmt.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_Qfmt_p.c b/third_party/gdtoa/g_Qfmt_p.c index 80482fdf..181ae8c0 100644 --- a/third_party/gdtoa/g_Qfmt_p.c +++ b/third_party/gdtoa/g_Qfmt_p.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g__fmt.c b/third_party/gdtoa/g__fmt.c index 55afbafb..c1dbb7ef 100644 --- a/third_party/gdtoa/g__fmt.c +++ b/third_party/gdtoa/g__fmt.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_ddfmt.c b/third_party/gdtoa/g_ddfmt.c index 08263d66..ddb96599 100644 --- a/third_party/gdtoa/g_ddfmt.c +++ b/third_party/gdtoa/g_ddfmt.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_ddfmt_p.c b/third_party/gdtoa/g_ddfmt_p.c index 3e514e66..59249648 100644 --- a/third_party/gdtoa/g_ddfmt_p.c +++ b/third_party/gdtoa/g_ddfmt_p.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_dfmt.c b/third_party/gdtoa/g_dfmt.c index c258ca2a..6ce02bfc 100644 --- a/third_party/gdtoa/g_dfmt.c +++ b/third_party/gdtoa/g_dfmt.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_dfmt_p.c b/third_party/gdtoa/g_dfmt_p.c index 6b34cc60..6842019c 100644 --- a/third_party/gdtoa/g_dfmt_p.c +++ b/third_party/gdtoa/g_dfmt_p.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_ffmt.c b/third_party/gdtoa/g_ffmt.c index db4813b9..8270c748 100644 --- a/third_party/gdtoa/g_ffmt.c +++ b/third_party/gdtoa/g_ffmt.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_ffmt_p.c b/third_party/gdtoa/g_ffmt_p.c index d7a0e764..8b9145d3 100644 --- a/third_party/gdtoa/g_ffmt_p.c +++ b/third_party/gdtoa/g_ffmt_p.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_xLfmt.c b/third_party/gdtoa/g_xLfmt.c index f8e54816..1e6d8f7d 100644 --- a/third_party/gdtoa/g_xLfmt.c +++ b/third_party/gdtoa/g_xLfmt.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_xLfmt_p.c b/third_party/gdtoa/g_xLfmt_p.c index b30f3fa7..123fefd7 100644 --- a/third_party/gdtoa/g_xLfmt_p.c +++ b/third_party/gdtoa/g_xLfmt_p.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_xfmt.c b/third_party/gdtoa/g_xfmt.c index f1fa913d..ae172c50 100644 --- a/third_party/gdtoa/g_xfmt.c +++ b/third_party/gdtoa/g_xfmt.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/g_xfmt_p.c b/third_party/gdtoa/g_xfmt_p.c index 70d66343..f0954139 100644 --- a/third_party/gdtoa/g_xfmt_p.c +++ b/third_party/gdtoa/g_xfmt_p.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/gdtoa.c b/third_party/gdtoa/gdtoa.c index 18d2d42f..6a4b7a96 100644 --- a/third_party/gdtoa/gdtoa.c +++ b/third_party/gdtoa/gdtoa.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/gdtoaimp.h b/third_party/gdtoa/gdtoa.internal.h similarity index 99% rename from third_party/gdtoa/gdtoaimp.h rename to third_party/gdtoa/gdtoa.internal.h index 420e759e..6d88abe3 100644 --- a/third_party/gdtoa/gdtoaimp.h +++ b/third_party/gdtoa/gdtoa.internal.h @@ -5,8 +5,9 @@ asm(".ident\t\"\\n\\n\ gdtoa (MIT License)\\n\ -The author of this software is David M. Gay.\\n\ -Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\""); +The author of this software is David M. Gay\\n\ +Kudos go to Guy L. Steele, Jr. and Jon L. White\\n\ +Copyright (C) 1997, 1998, 2000 by Lucent Technologies\""); asm(".include \"libc/disclaimer.inc\""); #define IEEE_8087 1 diff --git a/third_party/gdtoa/gethex.c b/third_party/gdtoa/gethex.c index 098754b8..9a007768 100644 --- a/third_party/gdtoa/gethex.c +++ b/third_party/gdtoa/gethex.c @@ -1,5 +1,5 @@ #include "libc/errno.h" -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/gmisc.c b/third_party/gdtoa/gmisc.c index 71c6f0e8..23fa478f 100644 --- a/third_party/gdtoa/gmisc.c +++ b/third_party/gdtoa/gmisc.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/hd_init.c b/third_party/gdtoa/hd_init.c index 2ffde485..e3888aeb 100644 --- a/third_party/gdtoa/hd_init.c +++ b/third_party/gdtoa/hd_init.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/hexnan.c b/third_party/gdtoa/hexnan.c index 7d5115f1..430dc0a7 100644 --- a/third_party/gdtoa/hexnan.c +++ b/third_party/gdtoa/hexnan.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/misc.c b/third_party/gdtoa/misc.c index 567c1245..afc325a1 100644 --- a/third_party/gdtoa/misc.c +++ b/third_party/gdtoa/misc.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/smisc.c b/third_party/gdtoa/smisc.c index ebcc341f..34879508 100644 --- a/third_party/gdtoa/smisc.c +++ b/third_party/gdtoa/smisc.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtoIQ.c b/third_party/gdtoa/strtoIQ.c index 82ca38cf..af0c66cb 100644 --- a/third_party/gdtoa/strtoIQ.c +++ b/third_party/gdtoa/strtoIQ.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtoId.c b/third_party/gdtoa/strtoId.c index fe284ad2..c1f5ec1c 100644 --- a/third_party/gdtoa/strtoId.c +++ b/third_party/gdtoa/strtoId.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtoIdd.c b/third_party/gdtoa/strtoIdd.c index 6d4c6ea9..6b95f9bc 100644 --- a/third_party/gdtoa/strtoIdd.c +++ b/third_party/gdtoa/strtoIdd.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtoIf.c b/third_party/gdtoa/strtoIf.c index ad2682f8..9c596c32 100644 --- a/third_party/gdtoa/strtoIf.c +++ b/third_party/gdtoa/strtoIf.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtoIg.c b/third_party/gdtoa/strtoIg.c index d16a5d2c..4512db73 100644 --- a/third_party/gdtoa/strtoIg.c +++ b/third_party/gdtoa/strtoIg.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtoIx.c b/third_party/gdtoa/strtoIx.c index a4aed845..c0cf63b4 100644 --- a/third_party/gdtoa/strtoIx.c +++ b/third_party/gdtoa/strtoIx.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtoIxL.c b/third_party/gdtoa/strtoIxL.c index 291d442c..6a574a5d 100644 --- a/third_party/gdtoa/strtoIxL.c +++ b/third_party/gdtoa/strtoIxL.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtod.c b/third_party/gdtoa/strtod.c index 275f2a67..35fae5ae 100644 --- a/third_party/gdtoa/strtod.c +++ b/third_party/gdtoa/strtod.c @@ -1,5 +1,5 @@ #include "libc/errno.h" -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtodI.c b/third_party/gdtoa/strtodI.c index 5a8a4a10..6c2c575a 100644 --- a/third_party/gdtoa/strtodI.c +++ b/third_party/gdtoa/strtodI.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtodg.c b/third_party/gdtoa/strtodg.c index aea9f5c4..bf34aca8 100644 --- a/third_party/gdtoa/strtodg.c +++ b/third_party/gdtoa/strtodg.c @@ -1,5 +1,5 @@ #include "libc/errno.h" -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtodnrp.c b/third_party/gdtoa/strtodnrp.c index 6f415215..5211adf8 100644 --- a/third_party/gdtoa/strtodnrp.c +++ b/third_party/gdtoa/strtodnrp.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtof.c b/third_party/gdtoa/strtof.c index 51509a6b..c7dd4950 100644 --- a/third_party/gdtoa/strtof.c +++ b/third_party/gdtoa/strtof.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtold.c b/third_party/gdtoa/strtold.c index 58cee249..edb431e0 100644 --- a/third_party/gdtoa/strtold.c +++ b/third_party/gdtoa/strtold.c @@ -1,26 +1,19 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif #include "third_party/gdtoa/gdtoa.h" +/** + * Converts string to long double. + */ long double strtold(const char *s, char **endptr) { - long double result; - strtorQ(s, endptr, FPI_Round_near, &result); - return result; + long double x; + strtorx(s, endptr, FPI_Round_near, &x); + return x; } diff --git a/third_party/gdtoa/strtopQ.c b/third_party/gdtoa/strtopQ.c index 5a53013c..6885409e 100644 --- a/third_party/gdtoa/strtopQ.c +++ b/third_party/gdtoa/strtopQ.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtopd.c b/third_party/gdtoa/strtopd.c index a601eea8..f506e4fc 100644 --- a/third_party/gdtoa/strtopd.c +++ b/third_party/gdtoa/strtopd.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtopdd.c b/third_party/gdtoa/strtopdd.c index b2349933..302460a0 100644 --- a/third_party/gdtoa/strtopdd.c +++ b/third_party/gdtoa/strtopdd.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtopf.c b/third_party/gdtoa/strtopf.c index c84709d5..d00d73bc 100644 --- a/third_party/gdtoa/strtopf.c +++ b/third_party/gdtoa/strtopf.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtopx.c b/third_party/gdtoa/strtopx.c index 9b0c3ed7..c1514c82 100644 --- a/third_party/gdtoa/strtopx.c +++ b/third_party/gdtoa/strtopx.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtopxL.c b/third_party/gdtoa/strtopxL.c index c742a7c2..da55bb2e 100644 --- a/third_party/gdtoa/strtopxL.c +++ b/third_party/gdtoa/strtopxL.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtorQ.c b/third_party/gdtoa/strtorQ.c index f718c234..8e6cb02a 100644 --- a/third_party/gdtoa/strtorQ.c +++ b/third_party/gdtoa/strtorQ.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtord.c b/third_party/gdtoa/strtord.c index e43e2a17..61ae0df8 100644 --- a/third_party/gdtoa/strtord.c +++ b/third_party/gdtoa/strtord.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtordd.c b/third_party/gdtoa/strtordd.c index e24aaa3e..490bb1b6 100644 --- a/third_party/gdtoa/strtordd.c +++ b/third_party/gdtoa/strtordd.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtorf.c b/third_party/gdtoa/strtorf.c index b77a9407..ddf21102 100644 --- a/third_party/gdtoa/strtorf.c +++ b/third_party/gdtoa/strtorf.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtorx.c b/third_party/gdtoa/strtorx.c index 48891491..1fe09544 100644 --- a/third_party/gdtoa/strtorx.c +++ b/third_party/gdtoa/strtorx.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/strtorxL.c b/third_party/gdtoa/strtorxL.c index 7be151ad..980dff9b 100644 --- a/third_party/gdtoa/strtorxL.c +++ b/third_party/gdtoa/strtorxL.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/sum.c b/third_party/gdtoa/sum.c index 175eae99..59cc6c58 100644 --- a/third_party/gdtoa/sum.c +++ b/third_party/gdtoa/sum.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/gdtoa/ulp.c b/third_party/gdtoa/ulp.c index 31b9badd..bf51cb4c 100644 --- a/third_party/gdtoa/ulp.c +++ b/third_party/gdtoa/ulp.c @@ -1,4 +1,4 @@ -#include "third_party/gdtoa/gdtoaimp.h" +#include "third_party/gdtoa/gdtoa.internal.h" /* clang-format off */ /**************************************************************** diff --git a/third_party/lemon/lemon.c b/third_party/lemon/lemon.c index fb948d67..be981a99 100644 --- a/third_party/lemon/lemon.c +++ b/third_party/lemon/lemon.c @@ -18,7 +18,7 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" /* ** This file contains all sources (including headers) to the LEMON diff --git a/third_party/lemon/lemon.mk b/third_party/lemon/lemon.mk index 304660c6..97d68bf3 100644 --- a/third_party/lemon/lemon.mk +++ b/third_party/lemon/lemon.mk @@ -32,7 +32,7 @@ THIRD_PARTY_LEMON_DIRECTDEPS = \ LIBC_UNICODE \ LIBC_X \ LIBC_ZIPOS \ - THIRD_PARTY_DTOA + THIRD_PARTY_GDTOA THIRD_PARTY_LEMON_DEPS := \ $(call uniq,$(foreach x,$(THIRD_PARTY_LEMON_DIRECTDEPS),$($(x)))) diff --git a/third_party/m4/extern.h b/third_party/m4/extern.h index 64221dc2..6993a5e3 100644 --- a/third_party/m4/extern.h +++ b/third_party/m4/extern.h @@ -114,7 +114,7 @@ extern void usage(void); extern void resizedivs(int); extern size_t buffer_mark(void); extern void dump_buffer(FILE *, size_t); -extern void m4errx(int, const char *, ...) noreturn; +extern void m4errx(int, const char *, ...) wontreturn; extern int obtain_char(struct input_file *); extern void set_input(struct input_file *, FILE *, const char *); diff --git a/third_party/stb/stb_image.c b/third_party/stb/stb_image.c index 7a5418a0..ff3b1eca 100644 --- a/third_party/stb/stb_image.c +++ b/third_party/stb/stb_image.c @@ -1261,7 +1261,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z) { if (!z->progressive) { if (z->scan_n == 1) { int i, j; - short data[64] aligned(16); + short data[64] forcealign(16); int n = z->order[0]; // non-interleaved data, we just need to process one block at a time, // in trivial scanline order @@ -1292,7 +1292,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z) { return 1; } else { // interleaved int i, j, k, x, y; - short data[64] aligned(16); + short data[64] forcealign(16); for (j = 0; j < z->img_mcu_y; ++j) { for (i = 0; i < z->img_mcu_x; ++i) { // scan an interleaved mcu... process scan_n components in order diff --git a/third_party/third_party.mk b/third_party/third_party.mk index 1d0f55aa..bf463e9a 100644 --- a/third_party/third_party.mk +++ b/third_party/third_party.mk @@ -10,7 +10,6 @@ o/$(MODE)/third_party: \ o/$(MODE)/third_party/compiler_rt \ o/$(MODE)/third_party/ctags \ o/$(MODE)/third_party/dlmalloc \ - o/$(MODE)/third_party/dtoa \ o/$(MODE)/third_party/gdtoa \ o/$(MODE)/third_party/duktape \ o/$(MODE)/third_party/editline \ diff --git a/third_party/zlib/crcfold.c b/third_party/zlib/crcfold.c index e414840a..ca80e54b 100644 --- a/third_party/zlib/crcfold.c +++ b/third_party/zlib/crcfold.c @@ -197,7 +197,7 @@ static inline void fold_4(struct DeflateState *const s, __m128i *xmm_crc0, *xmm_crc3 = _mm_castps_si128(ps_res3); } -static const unsigned aligned(32) pshufb_shf_table[60] = { +static const unsigned forcealign(32) pshufb_shf_table[60] = { 0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d, /* shl 15 (16 - 1)/shr1 */ 0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e, /* shl 14 (16 - 3)/shr2 */ 0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f, /* shl 13 (16 - 4)/shr3 */ diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index f20ac606..0529b773 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -68,7 +68,7 @@ #include "libc/time/time.h" #include "libc/unicode/unicode.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" #include "third_party/getopt/getopt.h" #include "tool/build/lib/address.h" #include "tool/build/lib/breakpoint.h" @@ -277,8 +277,9 @@ static struct sigaction oldsig[4]; static void SetupDraw(void); static void Redraw(void); -static char *FormatDouble(char *b, double x) { - return g_fmt(b, x); +static char *FormatDouble(char buf[32], long double x) { + g_xfmt_p(buf, &x, 15, 32, 0); + return buf; } static int64_t SignExtend(uint64_t x, char b) { @@ -2463,7 +2464,7 @@ static void HandleBreakpointFlag(const char *s) { PushBreakpoint(&breakpoints, &b); } -static noreturn void PrintUsage(int rc, FILE *f) { +static wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "SYNOPSIS\n\n %s%s", program_invocation_name, USAGE); exit(rc); } diff --git a/tool/build/build.mk b/tool/build/build.mk index d6293e14..8c0e64b8 100644 --- a/tool/build/build.mk +++ b/tool/build/build.mk @@ -56,7 +56,7 @@ TOOL_BUILD_DIRECTDEPS = \ LIBC_X \ TOOL_BUILD_LIB \ THIRD_PARTY_COMPILER_RT \ - THIRD_PARTY_DTOA \ + THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_XED \ THIRD_PARTY_ZLIB \ diff --git a/tool/build/calculator.c b/tool/build/calculator.c index 83e6d42e..6d01e167 100644 --- a/tool/build/calculator.c +++ b/tool/build/calculator.c @@ -33,7 +33,7 @@ #include "libc/sysv/consts/sig.h" #include "libc/tinymath/emodl.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" #include "third_party/getopt/getopt.h" #define INT intmax_t @@ -162,7 +162,7 @@ INT Popcnt(INT x) { char *Repr(struct Value x) { static char buf[64]; if (x.t == kFloat) { - g_fmt(buf, x.f); + g_xfmt_p(buf, &x.f, 16, sizeof(buf), 0); } else { sprintf(buf, "%jd", x.i); } @@ -256,36 +256,47 @@ void Pushf(FLOAT f) { void OpDrop(void) { Pop(); } + void OpDup(void) { Push(Push(Pop())); } + void OpExit(void) { exit(Popi()); } + void OpSrand(void) { srand(Popi()); } + void OpEmit(void) { fputwc(Popi(), stdout); } + void OpCr(void) { Cr(stdout); } + void OpPrint(void) { printf("%s ", Repr(Pop())); } + void OpComment(void) { comment = true; } + void Glue0f(FLOAT fn(void)) { Pushf(fn()); } + void Glue0i(INT fn(void)) { Pushi(fn()); } + void Glue1f(FLOAT fn(FLOAT)) { Pushf(fn(Popf())); } + void Glue1i(INT fn(INT)) { Pushi(fn(Popi())); } @@ -562,12 +573,16 @@ void GotoStartOfLine(void) { void GotoEndOfLine(void) { } + void GotoPrevLine(void) { } + void GotoNextLine(void) { } + void GotoPrevChar(void) { } + void GotoNextChar(void) { } diff --git a/tool/build/calculator.ctest b/tool/build/calculator.ctest index 527aada0..9fa50e38 100755 --- a/tool/build/calculator.ctest +++ b/tool/build/calculator.ctest @@ -31,7 +31,7 @@ nan isnormal ! assert 0 0 / dup isnan assert signbit assert # is this right? 1 0 / dup isinf assert signbit ! assert # is this right? nan nan != assert # is this right? --nan -nan != assert # is this right? +# -nan -nan != assert # is this right? inf inf = assert # is this right? -inf -inf = assert # is this right? diff --git a/tool/build/coefficients.c b/tool/build/coefficients.c index 4e21fe08..6bff7cb2 100644 --- a/tool/build/coefficients.c +++ b/tool/build/coefficients.c @@ -32,7 +32,7 @@ #include "libc/sysv/consts/ex.h" #include "libc/sysv/consts/exit.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" #include "third_party/getopt/getopt.h" #define USAGE \ @@ -60,7 +60,7 @@ static struct Flags { .H = 255, }; -static noreturn void PrintUsage(int rc, FILE *f) { +static wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "Usage: %s%s", program_invocation_name, USAGE); exit(rc); } diff --git a/tool/build/img2code.c b/tool/build/img2code.c index 5e2a8e65..2b7aa4c9 100644 --- a/tool/build/img2code.c +++ b/tool/build/img2code.c @@ -37,7 +37,7 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" #include "libc/testlib/testlib.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" #include "third_party/getopt/getopt.h" #include "third_party/stb/stb_image.h" #include "third_party/xed/x86.h" @@ -69,7 +69,7 @@ static struct Flags { .p = 1, }; -static noreturn void PrintUsage(int rc, FILE *f) { +static wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "Usage: %s%s", program_invocation_name, USAGE); exit(rc); } diff --git a/tool/build/lib/machine.h b/tool/build/lib/machine.h index 8a6e9e54..e75e62f5 100644 --- a/tool/build/lib/machine.h +++ b/tool/build/lib/machine.h @@ -63,7 +63,7 @@ struct Machine { uint8_t *p; } real; uint64_t cr3; - uint8_t xmm[16][16] aligned(16); + uint8_t xmm[16][16]; uint8_t es[8]; uint8_t ds[8]; uint8_t fs[8]; @@ -165,7 +165,7 @@ struct Machine { uint8_t icache[1024][40]; void (*onbinbase)(struct Machine *); void (*onlongbranch)(struct Machine *); -} aligned(64); +} forcealign(64); struct Machine *NewMachine(void) nodiscard; void FreeMachine(struct Machine *); diff --git a/tool/build/lib/ssefloat.c b/tool/build/lib/ssefloat.c index 44e95135..9347295d 100644 --- a/tool/build/lib/ssefloat.c +++ b/tool/build/lib/ssefloat.c @@ -38,8 +38,8 @@ (!IsModeDbg() && __SSE3__ + 0 && \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408) -typedef int int_v _Vector_size(16) aligned(16); -typedef long long_v _Vector_size(16) aligned(16); +typedef int int_v _Vector_size(16) forcealign(16); +typedef long long_v _Vector_size(16) forcealign(16); static float_v Addps(struct Machine *m, float_v x, float_v y) { return x + y; diff --git a/tool/build/lib/ssefloat.h b/tool/build/lib/ssefloat.h index 68a9bebc..4471002a 100644 --- a/tool/build/lib/ssefloat.h +++ b/tool/build/lib/ssefloat.h @@ -4,8 +4,8 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -typedef float float_v _Vector_size(16) aligned(16); -typedef double double_v _Vector_size(16) aligned(16); +typedef float float_v _Vector_size(16) forcealign(16); +typedef double double_v _Vector_size(16) forcealign(16); void OpUnpcklpsd(struct Machine *, uint32_t); void OpUnpckhpsd(struct Machine *, uint32_t); diff --git a/tool/build/lib/throw.h b/tool/build/lib/throw.h index f0903cff..6df3b71c 100644 --- a/tool/build/lib/throw.h +++ b/tool/build/lib/throw.h @@ -4,12 +4,12 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void OpUd(struct Machine *, uint32_t) noreturn; -void HaltMachine(struct Machine *, int) noreturn; -void ThrowDivideError(struct Machine *) noreturn; -void ThrowSegmentationFault(struct Machine *, int64_t) noreturn; -void ThrowProtectionFault(struct Machine *) noreturn; -void OpHlt(struct Machine *, uint32_t) noreturn; +void OpUd(struct Machine *, uint32_t) wontreturn; +void HaltMachine(struct Machine *, int) wontreturn; +void ThrowDivideError(struct Machine *) wontreturn; +void ThrowSegmentationFault(struct Machine *, int64_t) wontreturn; +void ThrowProtectionFault(struct Machine *) wontreturn; +void OpHlt(struct Machine *, uint32_t) wontreturn; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lz4toasm.c b/tool/build/lz4toasm.c index 5e248bb6..3f599ec8 100644 --- a/tool/build/lz4toasm.c +++ b/tool/build/lz4toasm.c @@ -49,7 +49,7 @@ struct stat st_; size_t extractedsize; -noreturn void usage(char *argv[], FILE *f, int rc) { +wontreturn void usage(char *argv[], FILE *f, int rc) { fprintf(f, "%s: %s [-o %s] [-s %s] %s\n", "Usage", argv[0], "PATH", "SYMBOL", "FILE"); exit(rc); diff --git a/tool/build/mkdeps.c b/tool/build/mkdeps.c index 9e4b769b..9685117b 100644 --- a/tool/build/mkdeps.c +++ b/tool/build/mkdeps.c @@ -210,7 +210,7 @@ bool ShouldSkipSource(const char *src) { return false; } -noreturn void OnMissingFile(const char *list, const char *src) { +wontreturn void OnMissingFile(const char *list, const char *src) { DCHECK_EQ(ENOENT, errno, "%s", src); /* * This code helps GNU Make automatically fix itself when we diff --git a/tool/build/runit.c b/tool/build/runit.c index d3619dc1..796e3bca 100644 --- a/tool/build/runit.c +++ b/tool/build/runit.c @@ -118,7 +118,7 @@ forceinline pureconst size_t GreatestTwoDivisor(size_t x) { return x & (~x + 1); } -noreturn void ShowUsage(FILE *f, int rc) { +wontreturn void ShowUsage(FILE *f, int rc) { fprintf(f, "Usage: %s RUNITD PROGRAM HOSTNAME[:RUNITDPORT[:SSHPORT]]...\n", program_invocation_name); exit(rc); diff --git a/tool/build/runitd.c b/tool/build/runitd.c index 9d4433ca..48f2694d 100644 --- a/tool/build/runitd.c +++ b/tool/build/runitd.c @@ -121,7 +121,7 @@ void OnChildTerminated(int sig) { g_childterm = true; } -noreturn void ShowUsage(FILE *f, int rc) { +wontreturn void ShowUsage(FILE *f, int rc) { fprintf(f, "%s: %s %s\n", "Usage", program_invocation_name, "[-d] [-r] [-l LISTENIP] [-p PORT] [-t TIMEOUTMS]"); exit(rc); diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c index b7ede745..c729d03f 100644 --- a/tool/build/zipobj.c +++ b/tool/build/zipobj.c @@ -75,7 +75,7 @@ const char kNoCompressExts[][8] = {".gz", ".xz", ".jpg", ".png", ".gif", ".zip", ".bz2", ".mpg", ".mp4", ".lz4", ".webp", ".mpeg"}; -noreturn void PrintUsage(int rc, FILE *f) { +wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, " [-o FILE] [-s SYMBOL] [-y YOINK] [FILE...]\n"); exit(rc); diff --git a/tool/calc/calc.c b/tool/calc/calc.c index 3ff56c7b..37fd2c73 100644 --- a/tool/calc/calc.c +++ b/tool/calc/calc.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +#include "libc/bits/bswap.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/conv/conv.h" @@ -37,6 +38,7 @@ #include "libc/x/x.h" #include "o/tool/calc/calc.c.inc" #include "o/tool/calc/calc.h.inc" +#include "third_party/gdtoa/gdtoa.h" #include "tool/calc/calc.h" /** @@ -51,28 +53,28 @@ static int g_column; static const char *g_file; static yyParser g_parser[1]; -noreturn static void Error(const char *msg) { +wontreturn static void Error(const char *msg) { fprintf(stderr, "%s:%d:%d: %s\n", g_file, g_line, g_column, msg); longjmp(jb, 1); } -noreturn static void SyntaxError(void) { +wontreturn static void SyntaxError(void) { Error("SYNTAX ERROR"); } -noreturn static void LexError(void) { +wontreturn static void LexError(void) { Error("LEX ERROR"); } -noreturn static void MissingArgumentError(void) { +wontreturn static void MissingArgumentError(void) { Error("MISSING ARGUMENT"); } -noreturn static void MissingFunctionError(void) { +wontreturn static void MissingFunctionError(void) { Error("MISSING FUNCTION"); } -noreturn static void SyscallError(const char *name) { +wontreturn static void SyscallError(const char *name) { fprintf(stderr, "ERROR: %s[%s]: %d\n", name, g_file, errno); exit(1); } @@ -395,6 +397,21 @@ static long double FnFpclassify(struct Numbers *a) { return fpclassify(a->x); } +static long double FnBswap16(struct Numbers *a) { + if (!a) MissingArgumentError(); + return bswap_16((uint16_t)a->x); +} + +static long double FnBswap32(struct Numbers *a) { + if (!a) MissingArgumentError(); + return bswap_32((uint32_t)a->x); +} + +static long double FnBswap64(struct Numbers *a) { + if (!a) MissingArgumentError(); + return bswap_64((uint64_t)a->x); +} + static long double FnBsr(struct Numbers *a) { if (!a) MissingArgumentError(); return bsr(a->x); @@ -611,9 +628,9 @@ static long double FnHex(struct Numbers *a) { } static void PrintNumber(long double x) { - char b[32]; - g_fmt(b, x); - fputs(b, stdout); + char buf[32]; + g_xfmt_p(buf, &x, 15, sizeof(buf), 0); + fputs(buf, stdout); } static void Print(struct Numbers *a) { @@ -648,6 +665,9 @@ static const struct Fn { {"bsfl", FnBsfl}, {"bsr", FnBsr}, {"bsrl", FnBsrl}, + {"bswap16", FnBswap16}, + {"bswap32", FnBswap32}, + {"bswap64", FnBswap64}, {"cbrt", FnCbrt}, {"ceil", FnCeil}, {"copysign", FnCopysign}, diff --git a/tool/calc/calc.h b/tool/calc/calc.h index b50896a1..bb00407a 100644 --- a/tool/calc/calc.h +++ b/tool/calc/calc.h @@ -13,7 +13,7 @@ struct Numbers { long double x; }; -static void SyntaxError(void) noreturn; +static void SyntaxError(void) wontreturn; static long double ParseNumber(struct Token); static void NumbersFree(struct Numbers *); static struct Numbers *NumbersAppend(struct Numbers *, long double); diff --git a/tool/calc/calc.mk b/tool/calc/calc.mk index 601d5e54..43f5bc86 100644 --- a/tool/calc/calc.mk +++ b/tool/calc/calc.mk @@ -41,7 +41,7 @@ TOOL_CALC_DIRECTDEPS = \ LIBC_TINYMATH \ LIBC_X \ THIRD_PARTY_COMPILER_RT \ - THIRD_PARTY_DTOA + THIRD_PARTY_GDTOA TOOL_CALC_DEPS := \ $(call uniq,$(foreach x,$(TOOL_CALC_DIRECTDEPS),$($(x)))) diff --git a/tool/calc/calc.y b/tool/calc/calc.y index 9c594a57..76ef7b1b 100644 --- a/tool/calc/calc.y +++ b/tool/calc/calc.y @@ -22,7 +22,6 @@ #include "tool/calc/calc.h" #include "libc/calls/calls.h" #include "libc/str/str.h" -#include "third_party/dtoa/dtoa.h" #include "libc/x/x.h" #include "libc/runtime/gc.h" #include "libc/math.h" diff --git a/tool/cc/c11.l b/tool/cc/c11.l deleted file mode 100644 index 7444cbe2..00000000 --- a/tool/cc/c11.l +++ /dev/null @@ -1,193 +0,0 @@ -/* http://www.quut.com/c/ANSI-C-grammar-l-2011.html */ - -%e 1019 -%p 2807 -%n 371 -%k 284 -%a 1213 -%o 1117 - -O [0-7] -D [0-9] -NZ [1-9] -L [a-zA-Z_] -A [a-zA-Z_0-9] -H [a-fA-F0-9] -HP (0[xX]) -E ([Ee][+-]?{D}+) -P ([Pp][+-]?{D}+) -FS (f|F|l|L) -IS (((u|U)(l|L|ll|LL)?)|((l|L|ll|LL)(u|U)?)) -CP (u|U|L) -SP (u8|u|U|L) -ES (\\(['"\?\\abfnrtv]|[0-7]{1,3}|x[a-fA-F0-9]+)) -WS [ \t\v\n\f] - -%{ -#include -#include "y.tab.h" - -extern void yyerror(const char *); /* prints grammar violation message */ - -extern int sym_type(const char *); /* returns type from symbol table */ - -#define sym_type(identifier) IDENTIFIER /* with no symbol table, fake it */ - -static void comment(void); -static int check_type(void); -%} - -%% -"/*" { comment(); } -"//".* { /* consume //-comment */ } - -"auto" { return(AUTO); } -"break" { return(BREAK); } -"case" { return(CASE); } -"char" { return(CHAR); } -"const" { return(CONST); } -"continue" { return(CONTINUE); } -"default" { return(DEFAULT); } -"do" { return(DO); } -"double" { return(DOUBLE); } -"else" { return(ELSE); } -"enum" { return(ENUM); } -"extern" { return(EXTERN); } -"float" { return(FLOAT); } -"for" { return(FOR); } -"goto" { return(GOTO); } -"if" { return(IF); } -"inline" { return(INLINE); } -"int" { return(INT); } -"long" { return(LONG); } -"register" { return(REGISTER); } -"restrict" { return(RESTRICT); } -"return" { return(RETURN); } -"short" { return(SHORT); } -"signed" { return(SIGNED); } -"sizeof" { return(SIZEOF); } -"static" { return(STATIC); } -"struct" { return(STRUCT); } -"switch" { return(SWITCH); } -"typedef" { return(TYPEDEF); } -"union" { return(UNION); } -"unsigned" { return(UNSIGNED); } -"void" { return(VOID); } -"volatile" { return(VOLATILE); } -"while" { return(WHILE); } -"_Alignas" { return ALIGNAS; } -"_Alignof" { return ALIGNOF; } -"_Atomic" { return ATOMIC; } -"_Bool" { return BOOL; } -"_Complex" { return COMPLEX; } -"_Generic" { return GENERIC; } -"_Imaginary" { return IMAGINARY; } -"_Noreturn" { return NORETURN; } -"_Static_assert" { return STATIC_ASSERT; } -"_Thread_local" { return THREAD_LOCAL; } -"__func__" { return FUNC_NAME; } - -{L}{A}* { return check_type(); } - -{HP}{H}+{IS}? { return I_CONSTANT; } -{NZ}{D}*{IS}? { return I_CONSTANT; } -"0"{O}*{IS}? { return I_CONSTANT; } -{CP}?"'"([^'\\\n]|{ES})+"'" { return I_CONSTANT; } - -{D}+{E}{FS}? { return F_CONSTANT; } -{D}*"."{D}+{E}?{FS}? { return F_CONSTANT; } -{D}+"."{E}?{FS}? { return F_CONSTANT; } -{HP}{H}+{P}{FS}? { return F_CONSTANT; } -{HP}{H}*"."{H}+{P}{FS}? { return F_CONSTANT; } -{HP}{H}+"."{P}{FS}? { return F_CONSTANT; } - -({SP}?\"([^"\\\n]|{ES})*\"{WS}*)+ { return STRING_LITERAL; } - -"..." { return ELLIPSIS; } -">>=" { return RIGHT_ASSIGN; } -"<<=" { return LEFT_ASSIGN; } -"+=" { return ADD_ASSIGN; } -"-=" { return SUB_ASSIGN; } -"*=" { return MUL_ASSIGN; } -"/=" { return DIV_ASSIGN; } -"%=" { return MOD_ASSIGN; } -"&=" { return AND_ASSIGN; } -"^=" { return XOR_ASSIGN; } -"|=" { return OR_ASSIGN; } -">>" { return RIGHT_OP; } -"<<" { return LEFT_OP; } -"++" { return INC_OP; } -"--" { return DEC_OP; } -"->" { return PTR_OP; } -"&&" { return AND_OP; } -"||" { return OR_OP; } -"<=" { return LE_OP; } -">=" { return GE_OP; } -"==" { return EQ_OP; } -"!=" { return NE_OP; } -";" { return ';'; } -("{"|"<%") { return '{'; } -("}"|"%>") { return '}'; } -"," { return ','; } -":" { return ':'; } -"=" { return '='; } -"(" { return '('; } -")" { return ')'; } -("["|"<:") { return '['; } -("]"|":>") { return ']'; } -"." { return '.'; } -"&" { return '&'; } -"!" { return '!'; } -"~" { return '~'; } -"-" { return '-'; } -"+" { return '+'; } -"*" { return '*'; } -"/" { return '/'; } -"%" { return '%'; } -"<" { return '<'; } -">" { return '>'; } -"^" { return '^'; } -"|" { return '|'; } -"?" { return '?'; } - -{WS}+ { /* whitespace separates tokens */ } -. { /* discard bad characters */ } - -%% - -int yywrap(void) /* called at end of input */ -{ - return 1; /* terminate now */ -} - -static void comment(void) -{ - int c; - - while ((c = input()) != 0) - if (c == '*') - { - while ((c = input()) == '*') - ; - - if (c == '/') - return; - - if (c == 0) - break; - } - yyerror("unterminated comment"); -} - -static int check_type(void) -{ - switch (sym_type(yytext)) - { - case TYPEDEF_NAME: /* previously defined */ - return TYPEDEF_NAME; - case ENUMERATION_CONSTANT: /* previously defined */ - return ENUMERATION_CONSTANT; - default: /* includes undefined */ - return IDENTIFIER; - } -} diff --git a/tool/cc/c11.y b/tool/cc/c11.y deleted file mode 100644 index 9338a026..00000000 --- a/tool/cc/c11.y +++ /dev/null @@ -1,535 +0,0 @@ -/* http://www.quut.com/c/ANSI-C-grammar-y-2011.html */ - -%token IDENTIFIER I_CONSTANT F_CONSTANT STRING_LITERAL FUNC_NAME SIZEOF -%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP -%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN -%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN -%token XOR_ASSIGN OR_ASSIGN -%token TYPEDEF_NAME ENUMERATION_CONSTANT - -%token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE -%token CONST RESTRICT VOLATILE -%token BOOL CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE VOID -%token COMPLEX IMAGINARY -%token STRUCT UNION ENUM ELLIPSIS - -%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN - -%token ALIGNAS ALIGNOF ATOMIC GENERIC NORETURN STATIC_ASSERT THREAD_LOCAL - -%start translation_unit -%% - -primary_expression - : IDENTIFIER - | constant - | string - | '(' expression ')' - | generic_selection - ; - -constant - : I_CONSTANT /* includes character_constant */ - | F_CONSTANT - | ENUMERATION_CONSTANT /* after it has been defined as such */ - ; - -enumeration_constant /* before it has been defined as such */ - : IDENTIFIER - ; - -string - : STRING_LITERAL - | FUNC_NAME - ; - -generic_selection - : GENERIC '(' assignment_expression ',' generic_assoc_list ')' - ; - -generic_assoc_list - : generic_association - | generic_assoc_list ',' generic_association - ; - -generic_association - : type_name ':' assignment_expression - | DEFAULT ':' assignment_expression - ; - -postfix_expression - : primary_expression - | postfix_expression '[' expression ']' - | postfix_expression '(' ')' - | postfix_expression '(' argument_expression_list ')' - | postfix_expression '.' IDENTIFIER - | postfix_expression PTR_OP IDENTIFIER - | postfix_expression INC_OP - | postfix_expression DEC_OP - | '(' type_name ')' '{' initializer_list '}' - | '(' type_name ')' '{' initializer_list ',' '}' - ; - -argument_expression_list - : assignment_expression - | argument_expression_list ',' assignment_expression - ; - -unary_expression - : postfix_expression - | INC_OP unary_expression - | DEC_OP unary_expression - | unary_operator cast_expression - | SIZEOF unary_expression - | SIZEOF '(' type_name ')' - | ALIGNOF '(' type_name ')' - ; - -unary_operator - : '&' - | '*' - | '+' - | '-' - | '~' - | '!' - ; - -cast_expression - : unary_expression - | '(' type_name ')' cast_expression - ; - -multiplicative_expression - : cast_expression - | multiplicative_expression '*' cast_expression - | multiplicative_expression '/' cast_expression - | multiplicative_expression '%' cast_expression - ; - -additive_expression - : multiplicative_expression - | additive_expression '+' multiplicative_expression - | additive_expression '-' multiplicative_expression - ; - -shift_expression - : additive_expression - | shift_expression LEFT_OP additive_expression - | shift_expression RIGHT_OP additive_expression - ; - -relational_expression - : shift_expression - | relational_expression '<' shift_expression - | relational_expression '>' shift_expression - | relational_expression LE_OP shift_expression - | relational_expression GE_OP shift_expression - ; - -equality_expression - : relational_expression - | equality_expression EQ_OP relational_expression - | equality_expression NE_OP relational_expression - ; - -and_expression - : equality_expression - | and_expression '&' equality_expression - ; - -exclusive_or_expression - : and_expression - | exclusive_or_expression '^' and_expression - ; - -inclusive_or_expression - : exclusive_or_expression - | inclusive_or_expression '|' exclusive_or_expression - ; - -logical_and_expression - : inclusive_or_expression - | logical_and_expression AND_OP inclusive_or_expression - ; - -logical_or_expression - : logical_and_expression - | logical_or_expression OR_OP logical_and_expression - ; - -conditional_expression - : logical_or_expression - | logical_or_expression '?' expression ':' conditional_expression - ; - -assignment_expression - : conditional_expression - | unary_expression assignment_operator assignment_expression - ; - -assignment_operator - : '=' - | MUL_ASSIGN - | DIV_ASSIGN - | MOD_ASSIGN - | ADD_ASSIGN - | SUB_ASSIGN - | LEFT_ASSIGN - | RIGHT_ASSIGN - | AND_ASSIGN - | XOR_ASSIGN - | OR_ASSIGN - ; - -expression - : assignment_expression - | expression ',' assignment_expression - ; - -constant_expression - : conditional_expression /* with constraints */ - ; - -declaration - : declaration_specifiers ';' - | declaration_specifiers init_declarator_list ';' - | static_assert_declaration - ; - -declaration_specifiers - : storage_class_specifier declaration_specifiers - | storage_class_specifier - | type_specifier declaration_specifiers - | type_specifier - | type_qualifier declaration_specifiers - | type_qualifier - | function_specifier declaration_specifiers - | function_specifier - | alignment_specifier declaration_specifiers - | alignment_specifier - ; - -init_declarator_list - : init_declarator - | init_declarator_list ',' init_declarator - ; - -init_declarator - : declarator '=' initializer - | declarator - ; - -storage_class_specifier - : TYPEDEF /* identifiers must be flagged as TYPEDEF_NAME */ - | EXTERN - | STATIC - | THREAD_LOCAL - | AUTO - | REGISTER - ; - -type_specifier - : VOID - | CHAR - | SHORT - | INT - | LONG - | FLOAT - | DOUBLE - | SIGNED - | UNSIGNED - | BOOL - | COMPLEX - | IMAGINARY /* non-mandated extension */ - | atomic_type_specifier - | struct_or_union_specifier - | enum_specifier - | TYPEDEF_NAME /* after it has been defined as such */ - ; - -struct_or_union_specifier - : struct_or_union '{' struct_declaration_list '}' - | struct_or_union IDENTIFIER '{' struct_declaration_list '}' - | struct_or_union IDENTIFIER - ; - -struct_or_union - : STRUCT - | UNION - ; - -struct_declaration_list - : struct_declaration - | struct_declaration_list struct_declaration - ; - -struct_declaration - : specifier_qualifier_list ';' /* for anonymous struct/union */ - | specifier_qualifier_list struct_declarator_list ';' - | static_assert_declaration - ; - -specifier_qualifier_list - : type_specifier specifier_qualifier_list - | type_specifier - | type_qualifier specifier_qualifier_list - | type_qualifier - ; - -struct_declarator_list - : struct_declarator - | struct_declarator_list ',' struct_declarator - ; - -struct_declarator - : ':' constant_expression - | declarator ':' constant_expression - | declarator - ; - -enum_specifier - : ENUM '{' enumerator_list '}' - | ENUM '{' enumerator_list ',' '}' - | ENUM IDENTIFIER '{' enumerator_list '}' - | ENUM IDENTIFIER '{' enumerator_list ',' '}' - | ENUM IDENTIFIER - ; - -enumerator_list - : enumerator - | enumerator_list ',' enumerator - ; - -enumerator /* identifiers must be flagged as ENUMERATION_CONSTANT */ - : enumeration_constant '=' constant_expression - | enumeration_constant - ; - -atomic_type_specifier - : ATOMIC '(' type_name ')' - ; - -type_qualifier - : CONST - | RESTRICT - | VOLATILE - | ATOMIC - ; - -function_specifier - : INLINE - | NORETURN - ; - -alignment_specifier - : ALIGNAS '(' type_name ')' - | ALIGNAS '(' constant_expression ')' - ; - -declarator - : pointer direct_declarator - | direct_declarator - ; - -direct_declarator - : IDENTIFIER - | '(' declarator ')' - | direct_declarator '[' ']' - | direct_declarator '[' '*' ']' - | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' - | direct_declarator '[' STATIC assignment_expression ']' - | direct_declarator '[' type_qualifier_list '*' ']' - | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' - | direct_declarator '[' type_qualifier_list assignment_expression ']' - | direct_declarator '[' type_qualifier_list ']' - | direct_declarator '[' assignment_expression ']' - | direct_declarator '(' parameter_type_list ')' - | direct_declarator '(' ')' - | direct_declarator '(' identifier_list ')' - ; - -pointer - : '*' type_qualifier_list pointer - | '*' type_qualifier_list - | '*' pointer - | '*' - ; - -type_qualifier_list - : type_qualifier - | type_qualifier_list type_qualifier - ; - - -parameter_type_list - : parameter_list ',' ELLIPSIS - | parameter_list - ; - -parameter_list - : parameter_declaration - | parameter_list ',' parameter_declaration - ; - -parameter_declaration - : declaration_specifiers declarator - | declaration_specifiers abstract_declarator - | declaration_specifiers - ; - -identifier_list - : IDENTIFIER - | identifier_list ',' IDENTIFIER - ; - -type_name - : specifier_qualifier_list abstract_declarator - | specifier_qualifier_list - ; - -abstract_declarator - : pointer direct_abstract_declarator - | pointer - | direct_abstract_declarator - ; - -direct_abstract_declarator - : '(' abstract_declarator ')' - | '[' ']' - | '[' '*' ']' - | '[' STATIC type_qualifier_list assignment_expression ']' - | '[' STATIC assignment_expression ']' - | '[' type_qualifier_list STATIC assignment_expression ']' - | '[' type_qualifier_list assignment_expression ']' - | '[' type_qualifier_list ']' - | '[' assignment_expression ']' - | direct_abstract_declarator '[' ']' - | direct_abstract_declarator '[' '*' ']' - | direct_abstract_declarator '[' STATIC type_qualifier_list assignment_expression ']' - | direct_abstract_declarator '[' STATIC assignment_expression ']' - | direct_abstract_declarator '[' type_qualifier_list assignment_expression ']' - | direct_abstract_declarator '[' type_qualifier_list STATIC assignment_expression ']' - | direct_abstract_declarator '[' type_qualifier_list ']' - | direct_abstract_declarator '[' assignment_expression ']' - | '(' ')' - | '(' parameter_type_list ')' - | direct_abstract_declarator '(' ')' - | direct_abstract_declarator '(' parameter_type_list ')' - ; - -initializer - : '{' initializer_list '}' - | '{' initializer_list ',' '}' - | assignment_expression - ; - -initializer_list - : designation initializer - | initializer - | initializer_list ',' designation initializer - | initializer_list ',' initializer - ; - -designation - : designator_list '=' - ; - -designator_list - : designator - | designator_list designator - ; - -designator - : '[' constant_expression ']' - | '.' IDENTIFIER - ; - -static_assert_declaration - : STATIC_ASSERT '(' constant_expression ',' STRING_LITERAL ')' ';' - ; - -statement - : labeled_statement - | compound_statement - | expression_statement - | selection_statement - | iteration_statement - | jump_statement - ; - -labeled_statement - : IDENTIFIER ':' statement - | CASE constant_expression ':' statement - | DEFAULT ':' statement - ; - -compound_statement - : '{' '}' - | '{' block_item_list '}' - ; - -block_item_list - : block_item - | block_item_list block_item - ; - -block_item - : declaration - | statement - ; - -expression_statement - : ';' - | expression ';' - ; - -selection_statement - : IF '(' expression ')' statement ELSE statement - | IF '(' expression ')' statement - | SWITCH '(' expression ')' statement - ; - -iteration_statement - : WHILE '(' expression ')' statement - | DO statement WHILE '(' expression ')' ';' - | FOR '(' expression_statement expression_statement ')' statement - | FOR '(' expression_statement expression_statement expression ')' statement - | FOR '(' declaration expression_statement ')' statement - | FOR '(' declaration expression_statement expression ')' statement - ; - -jump_statement - : GOTO IDENTIFIER ';' - | CONTINUE ';' - | BREAK ';' - | RETURN ';' - | RETURN expression ';' - ; - -translation_unit - : external_declaration - | translation_unit external_declaration - ; - -external_declaration - : function_definition - | declaration - ; - -function_definition - : declaration_specifiers declarator declaration_list compound_statement - | declaration_specifiers declarator compound_statement - ; - -declaration_list - : declaration - | declaration_list declaration - ; - -%% -#include - -void yyerror(const char *s) { - fflush(stdout); - fprintf(stderr, "*** %s\n", s); -} diff --git a/tool/cc/cc.mk b/tool/cc/cc.mk deleted file mode 100644 index ecfae222..00000000 --- a/tool/cc/cc.mk +++ /dev/null @@ -1,11 +0,0 @@ -#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ -#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ - -PKGS += TOOL_CC - -o/$(MODE)/tool/cc/c11.c: tool/cc/c11.l o/$(MODE)/third_party/lex/lex.com.dbg - @mkdir -p $(dir $@) - o/$(MODE)/third_party/lex/lex.com.dbg -o $@ $< - -.PHONY: o/$(MODE)/tool/cc -o/$(MODE)/tool/cc: diff --git a/tool/decode/decode.mk b/tool/decode/decode.mk index 2b178df1..d3224019 100644 --- a/tool/decode/decode.mk +++ b/tool/decode/decode.mk @@ -41,7 +41,7 @@ TOOL_DECODE_DIRECTDEPS = \ LIBC_UNICODE \ LIBC_X \ TOOL_DECODE_LIB \ - THIRD_PARTY_DTOA \ + THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_XED diff --git a/tool/decode/mkcombos.c b/tool/decode/mkcombos.c index f9ae8a55..654328ae 100644 --- a/tool/decode/mkcombos.c +++ b/tool/decode/mkcombos.c @@ -38,7 +38,7 @@ static uint32_t bit, maxbit; static struct BitaBuilder *bitset; static char *line, *tok, *s1, *category, *g_inpath, *g_outpath; -noreturn void ShowUsage(FILE *f, int rc) { +wontreturn void ShowUsage(FILE *f, int rc) { fprintf(f, "Usage: %s [-o OUTPUT] [INPUT]\n", "Usage", program_invocation_name); exit(rc); diff --git a/tool/decode/mkwides.c b/tool/decode/mkwides.c index 02a9e49c..c21cf4d6 100644 --- a/tool/decode/mkwides.c +++ b/tool/decode/mkwides.c @@ -35,7 +35,7 @@ static size_t linecap, i, x, y; static struct BitaBuilder *bitset; static char *g_inpath, *g_outpath; -noreturn void ShowUsage(FILE *f, int rc) { +wontreturn void ShowUsage(FILE *f, int rc) { fprintf(f, "Usage: %s [-o OUTPUT] [INPUT]\n", "Usage", program_invocation_name); exit(rc); diff --git a/tool/decode/x86opinfo.c b/tool/decode/x86opinfo.c index 90e2ac96..140bc4ae 100644 --- a/tool/decode/x86opinfo.c +++ b/tool/decode/x86opinfo.c @@ -42,7 +42,7 @@ const struct IdName kXedModeNames[] = { enum XedMachineMode g_mode; struct XedDecodedInst g_xedd; -noreturn void ShowUsage(int rc, FILE *f) { +wontreturn void ShowUsage(int rc, FILE *f) { size_t i; fputs("Usage: ", f); fputs(program_invocation_name, f); diff --git a/tool/decode/x87.c b/tool/decode/x87.c index 2ceaae91..18cf8d62 100644 --- a/tool/decode/x87.c +++ b/tool/decode/x87.c @@ -22,7 +22,7 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" const char kConfig[] = "\ /* FPU Control Word (x87) Exception Masks\n\ @@ -73,7 +73,8 @@ void PrintRegister(long double x) { memcpy(buf, &x, sizeof(x)); memcpy(&lo, &buf[0], sizeof(lo)); memcpy(&hi, &buf[8], sizeof(hi)); - printf("/\t%016lb%064lb %s\n", hi, lo, g_fmt(buf, x)); + g_xfmt_p(buf, &x, 15, 32, 0); + printf("/\t%016lb%064lb %s\n", hi, lo, buf); } int main(int argc, char *argv[]) { diff --git a/tool/emacs/cosmo-c-keywords.el b/tool/emacs/cosmo-c-keywords.el index 17aaa4d4..58d10587 100644 --- a/tool/emacs/cosmo-c-keywords.el +++ b/tool/emacs/cosmo-c-keywords.el @@ -168,7 +168,7 @@ "hasatleast" "nodebuginfo" "frownedupon" - "noreturn" + "wontreturn" "initarray" "mayalias" "noinstrument" @@ -190,7 +190,7 @@ "thatispacked" "strlenesque" "textwindows" - "aligned" + "forcealign" "typeof" "textreal" "autotype" diff --git a/tool/emacs/cosmo-cpp-constants.el b/tool/emacs/cosmo-cpp-constants.el index f68097f7..6aac2dbe 100644 --- a/tool/emacs/cosmo-cpp-constants.el +++ b/tool/emacs/cosmo-cpp-constants.el @@ -4,6 +4,10 @@ "__LINE__" "__DATE__")) +(defconst cosmo-cpp-constants-chibicc + '("__cosmo__" + "__chibicc__")) + (defconst cosmo-cpp-constants-gcc-412 '("__BASE_FILE__" "__CHAR_BIT__" @@ -21,6 +25,8 @@ "__SHRT_MAX__" "__DBL_MIN__" "__DBL_MAX__" + "__LDBL_MIN__" + "__LDBL_MAX__" "__FLT_MIN__" "__FLT_MAX__" "__WCHAR_MAX__" @@ -156,6 +162,7 @@ (append cosmo-cpp-constants-c11 cosmo-cpp-constants-gcc-92 cosmo-cpp-constants-gcc-412 + cosmo-cpp-constants-chibicc cosmo-cpp-constants-cosmopolitan)) (defconst cosmo-cpp-constants-regex diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index cc04dd1e..1210a690 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -137,6 +137,7 @@ ;; M-3 C-c C-c Compile w/ MODE=rel ;; M-4 C-c C-c Compile w/ MODE=dbg ;; M-5 C-c C-c Compile w/ MODE="" +;; M-9 C-c C-c Compile w/ chibicc (defun cosmo-intest (&optional file-name) (let (path root pkg) @@ -155,7 +156,15 @@ ((cosmo-intest) "dbg") (t ""))) -(defun cosmo--compile-command (this root kind mode) +(defun cosmo--make-suffix (arg) + (cond ((eq arg 9) ".chibicc") + (t ""))) + +(defun cosmo--make-objdump-flags (arg) + (cond ((eq arg 9) "-x") + (t ""))) + +(defun cosmo--compile-command (this root kind mode suffix objdumpflags) (let* ((ext (file-name-extension this)) ;; e.g. "c" (dir (file-name-directory this)) ;; e.g. "/home/jart/daisy/libc/" (dots (file-relative-name root dir)) ;; e.g. "../" @@ -170,20 +179,21 @@ (directory-file-name (file-name-directory (file-relative-name this root))))) - ((cosmo-contains "_test." (buffer-file-name)) + ((and (equal suffix "") + (cosmo-contains "_test." (buffer-file-name))) (format "m=%s; make -j8 -O MODE=$m %s" mode runs)) - ((file-exists-p (format "%s" buddy)) + ((and (equal suffix "") + (file-exists-p (format "%s" buddy))) (format (cosmo-join " && " - '("m=%s; n=%s; make -j8 -O o/$m/%s.o MODE=$m SILENT=0" - "make -j8 -O MODE=$m %s" + '("m=%s; n=%s; make -j8 -O o/$m/$n%s.o MODE=$m SILENT=0" ;; "bloat o/$m/%s.o | head" ;; "nm -C --size o/$m/%s.o | sort -r" "echo" "size -A o/$m/$n.o | grep '^[.T]' | grep -v 'debug\\|command.line\\|stack' | sort -rnk2" - "objdump -wzCd o/$m/$n.o")) - mode name name buns)) + "objdump %s -wzCd o/$m/$n%s.o")) + mode name suffix objdumpflags suffix)) ((eq kind 'run) (format (cosmo-join @@ -199,13 +209,13 @@ (format (cosmo-join " && " - `("m=%s; f=o/$m/%s.o" + `("m=%s; f=o/$m/%s%s.o" ,(concat "make -j8 -O $f MODE=$m SILENT=0") ;; "nm -C --size $f | sort -r" "echo" "size -A $f | grep '^[.T]' | grep -v 'debug\\|command.line\\|stack' | sort -rnk2" - "objdump -wzCd $f")) - mode name))))) + "objdump %s -wzCd $f")) + mode name suffix objdumpflags))))) (defun cosmo-compile (arg) (interactive "P") @@ -213,9 +223,11 @@ (root (locate-dominating-file this "Makefile"))) (when root (let* ((mode (cosmo--make-mode arg)) + (suffix (cosmo--make-suffix arg)) + (objdumpflags (cosmo--make-objdump-flags arg)) (compilation-scroll-output nil) (default-directory root) - (compile-command (cosmo--compile-command this root nil mode))) + (compile-command (cosmo--compile-command this root nil mode suffix objdumpflags))) (compile compile-command))))) (defun cosmo-compile-hook () @@ -554,7 +566,7 @@ (format "./%s" file)))) ((memq major-mode '(c-mode c++-mode asm-mode fortran-mode)) (let* ((mode (cosmo--make-mode arg)) - (compile-command (cosmo--compile-command this root 'run mode))) + (compile-command (cosmo--compile-command this root 'run mode "" ""))) (compile compile-command))) ((eq major-mode 'sh-mode) (compile (format "sh %s" file))) @@ -590,7 +602,7 @@ (next (file-name-sans-extension name)) (exec (format "o/%s/%s.com.dbg" mode next)) (default-directory root) - (compile-command (cosmo--compile-command this root nil mode))) + (compile-command (cosmo--compile-command this root nil mode "" ""))) (compile compile-command) (gdb (format "gdb -q -nh -i=mi %s -ex run" exec)))))) diff --git a/tool/emacs/key.py b/tool/emacs/key.py index fb5dd0e4..c0262bc3 100644 --- a/tool/emacs/key.py +++ b/tool/emacs/key.py @@ -348,7 +348,7 @@ cosmo_kws = frozenset([ "nointerpose", "nooptimize", "noprune", - "noreturn", + "wontreturn", "nosideeffect", "nothrow", "nothrow", @@ -411,7 +411,7 @@ cosmo_kws = frozenset([ "nointerpose", "nooptimize", "noprune", - "noreturn", + "wontreturn", "nosideeffect", "nothrow", "nothrow", diff --git a/tool/net/echoserver.c b/tool/net/echoserver.c index 71b9734c..c3a1660f 100644 --- a/tool/net/echoserver.c +++ b/tool/net/echoserver.c @@ -100,7 +100,7 @@ nodiscard char *DescribeSocket(struct Socket *s) { gc(DescribeAddress(&s->addr))); } -noreturn void ShowUsageAndExit(bool iserror) { +wontreturn void ShowUsageAndExit(bool iserror) { FILE *f = iserror ? stderr : stdout; int rc = iserror ? EXIT_FAILURE : EXIT_SUCCESS; fprintf(f, "%s: %s %s\n", "Usage", g_argv[0], "PROTOCOL:ADDR:PORT..."); diff --git a/tool/net/greenbean.c b/tool/net/greenbean.c index 13f669b4..52f5370d 100644 --- a/tool/net/greenbean.c +++ b/tool/net/greenbean.c @@ -372,7 +372,7 @@ static const char *GetContentType(const char *path, size_t n) { } } -static noreturn void PrintUsage(FILE *f, int rc) { +static wontreturn void PrintUsage(FILE *f, int rc) { fprintf(f, "SYNOPSIS\n\n %s%s", program_invocation_name, USAGE); exit(rc); } diff --git a/tool/net/redbean.c b/tool/net/redbean.c index fab8275a..2fa774e9 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -353,7 +353,7 @@ static const char *GetContentType(const char *path, size_t n) { } } -static noreturn void PrintUsage(FILE *f, int rc) { +static wontreturn void PrintUsage(FILE *f, int rc) { fprintf(f, "SYNOPSIS\n\n %s%s", program_invocation_name, USAGE); exit(rc); } diff --git a/tool/tags/keywords.gperf b/tool/tags/keywords.gperf deleted file mode 100644 index 22da37fb..00000000 --- a/tool/tags/keywords.gperf +++ /dev/null @@ -1,161 +0,0 @@ -%{ -#include "libc/str/str.h" -#include "tool/tags/tags.h" -#include "o/tool/tags/tags.h.inc" -%} -%compare-strncmp -%language=ANSI-C -%readonly-tables -%struct-type -%define lookup-function-name LookupKeyword -struct KeywordSlot { char *name; int code; }; -%% -auto, TK_AUTO -break, TK_BREAK -case, TK_CASE -char, TK_CHAR -const, TK_CONST -continue, TK_CONTINUE -default, TK_DEFAULT -do, TK_DO -double, TK_DOUBLE -else, TK_ELSE -enum, TK_ENUM -extern, TK_EXTERN -float, TK_FLOAT -for, TK_FOR -goto, TK_GOTO -if, TK_IF -inline, TK_INLINE -int, TK_INT -long, TK_LONG -register, TK_REGISTER -restrict, TK_RESTRICT -return, TK_RETURN -short, TK_SHORT -signed, TK_SIGNED -sizeof, TK_SIZEOF -static, TK_STATIC -struct, TK_STRUCT -switch, TK_SWITCH -typedef, TK_TYPEDEF -union, TK_UNION -unsigned, TK_UNSIGNED -void, TK_VOID -volatile, TK_VOLATILE -while, TK_WHILE -_Alignas, TK_ALIGNAS -_Alignof, TK_ALIGNOF -_Atomic, TK_ATOMIC -_Bool, TK_BOOL -_Complex, TK_COMPLEX -_Generic, TK_GENERIC -_Imaginary, TK_IMAGINARY -_Noreturn, TK_NORETURN -_Static_assert, TK_STATIC_ASSERT -_Thread_local, TK_THREAD_LOCAL -elif, TK_ELIF -endif, TK_ENDIF -ifdef, TK_IFDEF -ifndef, TK_IFNDEF -define, TK_DEFINE -undef, TK_UNDEF -include, TK_INCLUDE -line, TK_LINE -error, TK_ERROR -pragma, TK_PRAGMA -asm, TK_ASM -__attribute__, TK_ATTRIBUTE -__restrict__, TK_RESTRICT -__typeof__, TK_TYPEOF -__typeof, TK_TYPEOF -__inline, TK_INLINE -__const__, TK_CONST -__label__, TK_LABEL -__noinline__, TK_LABEL -__force_align_arg_pointer__, TK_FORCE_ALIGN_ARG_POINTER -__always_inline__, TK_ALWAYS_INLINE -__gnu_inline__, TK_GNU_INLINE -__alignof__, TK_ALIGNOF -__asm__, TK_ASM -__auto_type, TK_AUTO_TYPE -__byte__, TK_BYTE -__complex__, TK_COMPLEX -__imag__, TK_IMAG -__may_alias__, TK_MAY_ALIAS -__noreturn__, TK_NORETURN -__packed__, TK_PACKED -__pointer__, TK_POINTER -__printf__, TK_PRINTF -__real__, TK_REAL -__scanf__, TK_SCANF -__strfmon__, TK_STRFMON -__strftime__, TK_STRFTIME -__strong__, TK_STRONG -__target__, TK_TARGET -__transparent_union__, TK_TRANSPARENT_UNION -__volatile__, TK_VOLATILE -__word__, TK_WORD -__alias__, TK_ALIAS -__aligned__, TK_ALIGNED -__alloc_align__, TK_ALLOC_ALIGN -__alloc_size__, TK_ALLOC_SIZE -__artificial__, TK_ARTIFICIAL -__assume_aligned__, TK_ASSUME_ALIGNED -__cold__, TK_COLD -__constructor__, TK_CONSTRUCTOR -__destructor__, TK_DESTRUCTOR -__copy__, TK_COPY -__deprecated__, TK_DEPRECATED -__error__, TK_ERROR -__warning__, TK_WARNING -__externally_visible__, TK_EXTERNALLY_VISIBLE -__flatten__, TK_FLATTEN -__format__, TK_FORMAT -__gnu_format__, TK_GNU_FORMAT -__gnu_printf__, TK_GNU_PRINTF -__gnu_scanf__, TK_GNU_SCANF -__format_arg__, TK_FORMAT_ARG -__hot__, TK_HOT -__ifunc__, TK_IFUNC -__interrupt__, TK_INTERRUPT -__interrupt_handler__, TK_INTERRUPT_HANDLER -__no_caller_saved_registers__, TK_NO_CALLER_SAVED_REGISTERS -__leaf__, TK_LEAF -__malloc__, TK_MALLOC -__no_icf__, TK_NO_ICF -__no_instrument_function__, TK_NO_INSTRUMENT_FUNCTION -__no_profile_instrument_function__, TK_NO_PROFILE_INSTRUMENT_FUNCTION -__no_reorder__, TK_NO_REORDER -__no_sanitize__, TK_NO_SANITIZE -__no_sanitize_address__, TK_NO_SANITIZE_ADDRESS -__no_address_safety_analysis__, TK_NO_ADDRESS_SAFETY_ANALYSIS -__no_sanitize_thread__, TK_NO_SANITIZE_THREAD -__no_sanitize_undefined__, TK_NO_SANITIZE_UNDEFINED -__no_split_stack__, TK_NO_SPLIT_STACK -__no_stack_limit__, TK_NO_STACK_LIMIT -__noclone__, TK_NOCLONE -__noipa__, TK_NOIPA -__nonnull__, TK_NONNULL -__noplt__, TK_NOPLT -__nothrow__, TK_NOTHROW -__optimize__, TK_OPTIMIZE -__pure__, TK_PURE -__patchable_function_entry__, TK_PATCHABLE_FUNCTION_ENTRY -__returns_nonnull__, TK_RETURNS_NONNULL -__returns_twice__, TK_RETURNS_TWICE -__section__, TK_SECTION -__sentinel__, TK_SENTINEL -__simd__, TK_SIMD -__target_clones__, TK_TARGET_CLONES -__unused__, TK_UNUSED -__used__, TK_USED -__visibility__, TK_VISIBILITY -__warn_unused_result__, TK_WARN_UNUSED_RESULT -__params_nonnull__, TK_PARAMS_NONNULL -__weak__, TK_WEAK -__vector_size__, TK_VECTOR_SIZE -__ms_abi__, TK_MS_ABI -__mode__, TK_MODE -__optnone__, TK_OPTNONE -__nodebug__, TK_NODEBUG diff --git a/tool/tags/keywords.inc b/tool/tags/keywords.inc deleted file mode 100644 index a6e470fb..00000000 --- a/tool/tags/keywords.inc +++ /dev/null @@ -1,516 +0,0 @@ -/* ANSI-C code produced by gperf version 3.1 */ -/* Command-line: gperf keywords.gperf */ -/* Computed positions: -k'1-3,5,8' */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -#error "gperf generated tables don't work with this execution character set. Please report a bug to ." -#endif - -#line 1 "keywords.gperf" - -#include "libc/str/str.h" -#include "tool/tags/tags.h" -#include "o/tool/tags/tags.h.inc" -#line 11 "keywords.gperf" -struct KeywordSlot { char *name; int code; }; - -#define TOTAL_KEYWORDS 149 -#define MIN_WORD_LENGTH 2 -#define MAX_WORD_LENGTH 34 -#define MIN_HASH_VALUE 15 -#define MAX_HASH_VALUE 485 -/* maximum key range = 471, duplicates = 0 */ - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash (register const char *str, register size_t len) -{ - static const unsigned short asso_values[] = - { - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 0, 5, 5, 486, 486, - 486, 5, 486, 0, 486, 486, 486, 486, 0, 486, - 486, 486, 486, 5, 0, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 45, 0, 40, 120, 160, - 80, 60, 0, 130, 0, 55, 15, 486, 175, 20, - 10, 0, 5, 70, 125, 10, 40, 0, 40, 145, - 20, 20, 0, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 486, 486 - }; - register unsigned int hval = len; - - switch (hval) - { - default: - hval += asso_values[(unsigned char)str[7]+1]; - /*FALLTHROUGH*/ - case 7: - case 6: - case 5: - hval += asso_values[(unsigned char)str[4]+1]; - /*FALLTHROUGH*/ - case 4: - case 3: - hval += asso_values[(unsigned char)str[2]]; - /*FALLTHROUGH*/ - case 2: - hval += asso_values[(unsigned char)str[1]]; - /*FALLTHROUGH*/ - case 1: - hval += asso_values[(unsigned char)str[0]]; - break; - } - return hval; -} - -const struct KeywordSlot * -LookupKeyword (register const char *str, register size_t len) -{ - static const struct KeywordSlot wordlist[] = - { - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 35 "keywords.gperf" - {"short", TK_SHORT}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, -#line 28 "keywords.gperf" - {"if", TK_IF}, -#line 56 "keywords.gperf" - {"_Thread_local", TK_THREAD_LOCAL}, - {""}, {""}, {""}, {""}, {""}, -#line 54 "keywords.gperf" - {"_Noreturn", TK_NORETURN}, - {""}, {""}, {""}, {""}, {""}, -#line 42 "keywords.gperf" - {"union", TK_UNION}, -#line 60 "keywords.gperf" - {"ifndef", TK_IFNDEF}, - {""}, -#line 67 "keywords.gperf" - {"asm", TK_ASM}, -#line 23 "keywords.gperf" - {"enum", TK_ENUM}, -#line 50 "keywords.gperf" - {"_Bool", TK_BOOL}, -#line 37 "keywords.gperf" - {"sizeof", TK_SIZEOF}, - {""}, {""}, {""}, {""}, {""}, -#line 20 "keywords.gperf" - {"do", TK_DO}, - {""}, -#line 13 "keywords.gperf" - {"auto", TK_AUTO}, - {""}, {""}, {""}, -#line 43 "keywords.gperf" - {"unsigned", TK_UNSIGNED}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 119 "keywords.gperf" - {"__hot__", TK_HOT}, -#line 152 "keywords.gperf" - {"__used__", TK_USED}, -#line 44 "keywords.gperf" - {"void", TK_VOID}, - {""}, -#line 160 "keywords.gperf" - {"__optnone__", TK_OPTNONE}, -#line 49 "keywords.gperf" - {"_Atomic", TK_ATOMIC}, - {""}, -#line 55 "keywords.gperf" - {"_Static_assert", TK_STATIC_ASSERT}, - {""}, -#line 21 "keywords.gperf" - {"double", TK_DOUBLE}, - {""}, -#line 30 "keywords.gperf" - {"int", TK_INT}, - {""}, -#line 114 "keywords.gperf" - {"__format__", TK_FORMAT}, -#line 38 "keywords.gperf" - {"static", TK_STATIC}, -#line 148 "keywords.gperf" - {"__sentinel__", TK_SENTINEL}, -#line 143 "keywords.gperf" - {"__pure__", TK_PURE}, -#line 118 "keywords.gperf" - {"__format_arg__", TK_FORMAT_ARG}, -#line 130 "keywords.gperf" - {"__no_sanitize__", TK_NO_SANITIZE}, -#line 141 "keywords.gperf" - {"__nothrow__", TK_NOTHROW}, -#line 142 "keywords.gperf" - {"__optimize__", TK_OPTIMIZE}, -#line 149 "keywords.gperf" - {"__simd__", TK_SIMD}, -#line 129 "keywords.gperf" - {"__no_reorder__", TK_NO_REORDER}, -#line 94 "keywords.gperf" - {"__strong__", TK_STRONG}, -#line 88 "keywords.gperf" - {"__pointer__", TK_POINTER}, -#line 133 "keywords.gperf" - {"__no_sanitize_thread__", TK_NO_SANITIZE_THREAD}, -#line 131 "keywords.gperf" - {"__no_sanitize_address__", TK_NO_SANITIZE_ADDRESS}, -#line 138 "keywords.gperf" - {"__noipa__", TK_NOIPA}, -#line 134 "keywords.gperf" - {"__no_sanitize_undefined__", TK_NO_SANITIZE_UNDEFINED}, -#line 92 "keywords.gperf" - {"__strfmon__", TK_STRFMON}, -#line 76 "keywords.gperf" - {"__force_align_arg_pointer__", TK_FORCE_ALIGN_ARG_POINTER}, -#line 26 "keywords.gperf" - {"for", TK_FOR}, - {""}, {""}, -#line 139 "keywords.gperf" - {"__nonnull__", TK_NONNULL}, -#line 41 "keywords.gperf" - {"typedef", TK_TYPEDEF}, - {""}, {""}, -#line 158 "keywords.gperf" - {"__ms_abi__", TK_MS_ABI}, -#line 24 "keywords.gperf" - {"extern", TK_EXTERN}, -#line 93 "keywords.gperf" - {"__strftime__", TK_STRFTIME}, -#line 135 "keywords.gperf" - {"__no_split_stack__", TK_NO_SPLIT_STACK}, -#line 128 "keywords.gperf" - {"__no_profile_instrument_function__", TK_NO_PROFILE_INSTRUMENT_FUNCTION}, - {""}, -#line 81 "keywords.gperf" - {"__auto_type", TK_AUTO_TYPE}, -#line 75 "keywords.gperf" - {"__noinline__", TK_LABEL}, -#line 85 "keywords.gperf" - {"__may_alias__", TK_MAY_ALIAS}, - {""}, {""}, -#line 61 "keywords.gperf" - {"define", TK_DEFINE}, -#line 80 "keywords.gperf" - {"__asm__", TK_ASM}, -#line 51 "keywords.gperf" - {"_Complex", TK_COMPLEX}, -#line 123 "keywords.gperf" - {"__no_caller_saved_registers__", TK_NO_CALLER_SAVED_REGISTERS}, -#line 95 "keywords.gperf" - {"__target__", TK_TARGET}, - {""}, {""}, {""}, -#line 99 "keywords.gperf" - {"__alias__", TK_ALIAS}, - {""}, -#line 100 "keywords.gperf" - {"__aligned__", TK_ALIGNED}, -#line 150 "keywords.gperf" - {"__target_clones__", TK_TARGET_CLONES}, - {""}, -#line 103 "keywords.gperf" - {"__artificial__", TK_ARTIFICIAL}, - {""}, -#line 79 "keywords.gperf" - {"__alignof__", TK_ALIGNOF}, -#line 86 "keywords.gperf" - {"__noreturn__", TK_NORETURN}, -#line 155 "keywords.gperf" - {"__params_nonnull__", TK_PARAMS_NONNULL}, -#line 102 "keywords.gperf" - {"__alloc_size__", TK_ALLOC_SIZE}, -#line 101 "keywords.gperf" - {"__alloc_align__", TK_ALLOC_ALIGN}, -#line 127 "keywords.gperf" - {"__no_instrument_function__", TK_NO_INSTRUMENT_FUNCTION}, - {""}, -#line 121 "keywords.gperf" - {"__interrupt__", TK_INTERRUPT}, -#line 110 "keywords.gperf" - {"__error__", TK_ERROR}, - {""}, {""}, -#line 112 "keywords.gperf" - {"__externally_visible__", TK_EXTERNALLY_VISIBLE}, -#line 72 "keywords.gperf" - {"__inline", TK_INLINE}, -#line 27 "keywords.gperf" - {"goto", TK_GOTO}, -#line 17 "keywords.gperf" - {"const", TK_CONST}, -#line 122 "keywords.gperf" - {"__interrupt_handler__", TK_INTERRUPT_HANDLER}, -#line 97 "keywords.gperf" - {"__volatile__", TK_VOLATILE}, -#line 159 "keywords.gperf" - {"__mode__", TK_MODE}, -#line 140 "keywords.gperf" - {"__noplt__", TK_NOPLT}, -#line 25 "keywords.gperf" - {"float", TK_FLOAT}, - {""}, {""}, {""}, {""}, {""}, -#line 66 "keywords.gperf" - {"pragma", TK_PRAGMA}, -#line 19 "keywords.gperf" - {"default", TK_DEFAULT}, -#line 104 "keywords.gperf" - {"__assume_aligned__", TK_ASSUME_ALIGNED}, -#line 31 "keywords.gperf" - {"long", TK_LONG}, -#line 132 "keywords.gperf" - {"__no_address_safety_analysis__", TK_NO_ADDRESS_SAFETY_ANALYSIS}, -#line 137 "keywords.gperf" - {"__noclone__", TK_NOCLONE}, - {""}, -#line 18 "keywords.gperf" - {"continue", TK_CONTINUE}, -#line 120 "keywords.gperf" - {"__ifunc__", TK_IFUNC}, -#line 53 "keywords.gperf" - {"_Imaginary", TK_IMAGINARY}, -#line 147 "keywords.gperf" - {"__section__", TK_SECTION}, - {""}, -#line 52 "keywords.gperf" - {"_Generic", TK_GENERIC}, -#line 153 "keywords.gperf" - {"__visibility__", TK_VISIBILITY}, -#line 151 "keywords.gperf" - {"__unused__", TK_UNUSED}, -#line 36 "keywords.gperf" - {"signed", TK_SIGNED}, - {""}, {""}, -#line 16 "keywords.gperf" - {"char", TK_CHAR}, -#line 46 "keywords.gperf" - {"while", TK_WHILE}, - {""}, -#line 77 "keywords.gperf" - {"__always_inline__", TK_ALWAYS_INLINE}, - {""}, {""}, {""}, -#line 161 "keywords.gperf" - {"__nodebug__", TK_NODEBUG}, - {""}, -#line 33 "keywords.gperf" - {"restrict", TK_RESTRICT}, -#line 15 "keywords.gperf" - {"case", TK_CASE}, - {""}, {""}, {""}, -#line 82 "keywords.gperf" - {"__byte__", TK_BYTE}, - {""}, -#line 125 "keywords.gperf" - {"__malloc__", TK_MALLOC}, -#line 113 "keywords.gperf" - {"__flatten__", TK_FLATTEN}, - {""}, -#line 45 "keywords.gperf" - {"volatile", TK_VOLATILE}, - {""}, -#line 62 "keywords.gperf" - {"undef", TK_UNDEF}, - {""}, {""}, {""}, -#line 91 "keywords.gperf" - {"__scanf__", TK_SCANF}, - {""}, {""}, -#line 146 "keywords.gperf" - {"__returns_twice__", TK_RETURNS_TWICE}, - {""}, -#line 145 "keywords.gperf" - {"__returns_nonnull__", TK_RETURNS_NONNULL}, -#line 157 "keywords.gperf" - {"__vector_size__", TK_VECTOR_SIZE}, - {""}, {""}, -#line 136 "keywords.gperf" - {"__no_stack_limit__", TK_NO_STACK_LIMIT}, - {""}, -#line 126 "keywords.gperf" - {"__no_icf__", TK_NO_ICF}, -#line 34 "keywords.gperf" - {"return", TK_RETURN}, - {""}, -#line 144 "keywords.gperf" - {"__patchable_function_entry__", TK_PATCHABLE_FUNCTION_ENTRY}, -#line 64 "keywords.gperf" - {"line", TK_LINE}, -#line 87 "keywords.gperf" - {"__packed__", TK_PACKED}, -#line 29 "keywords.gperf" - {"inline", TK_INLINE}, - {""}, {""}, -#line 22 "keywords.gperf" - {"else", TK_ELSE}, -#line 89 "keywords.gperf" - {"__printf__", TK_PRINTF}, - {""}, {""}, -#line 98 "keywords.gperf" - {"__word__", TK_WORD}, - {""}, {""}, -#line 111 "keywords.gperf" - {"__warning__", TK_WARNING}, - {""}, {""}, -#line 73 "keywords.gperf" - {"__const__", TK_CONST}, - {""}, -#line 39 "keywords.gperf" - {"struct", TK_STRUCT}, - {""}, {""}, -#line 107 "keywords.gperf" - {"__destructor__", TK_DESTRUCTOR}, - {""}, {""}, {""}, -#line 47 "keywords.gperf" - {"_Alignas", TK_ALIGNAS}, - {""}, -#line 59 "keywords.gperf" - {"ifdef", TK_IFDEF}, -#line 83 "keywords.gperf" - {"__complex__", TK_COMPLEX}, -#line 63 "keywords.gperf" - {"include", TK_INCLUDE}, -#line 84 "keywords.gperf" - {"__imag__", TK_IMAG}, -#line 78 "keywords.gperf" - {"__gnu_inline__", TK_GNU_INLINE}, -#line 106 "keywords.gperf" - {"__constructor__", TK_CONSTRUCTOR}, - {""}, {""}, -#line 105 "keywords.gperf" - {"__cold__", TK_COLD}, -#line 115 "keywords.gperf" - {"__gnu_format__", TK_GNU_FORMAT}, - {""}, {""}, -#line 69 "keywords.gperf" - {"__restrict__", TK_RESTRICT}, - {""}, -#line 116 "keywords.gperf" - {"__gnu_printf__", TK_GNU_PRINTF}, -#line 58 "keywords.gperf" - {"endif", TK_ENDIF}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 57 "keywords.gperf" - {"elif", TK_ELIF}, - {""}, -#line 40 "keywords.gperf" - {"switch", TK_SWITCH}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 68 "keywords.gperf" - {"__attribute__", TK_ATTRIBUTE}, - {""}, {""}, {""}, -#line 154 "keywords.gperf" - {"__warn_unused_result__", TK_WARN_UNUSED_RESULT}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 65 "keywords.gperf" - {"error", TK_ERROR}, - {""}, {""}, -#line 108 "keywords.gperf" - {"__copy__", TK_COPY}, - {""}, {""}, {""}, {""}, {""}, -#line 109 "keywords.gperf" - {"__deprecated__", TK_DEPRECATED}, - {""}, {""}, {""}, -#line 71 "keywords.gperf" - {"__typeof", TK_TYPEOF}, - {""}, -#line 70 "keywords.gperf" - {"__typeof__", TK_TYPEOF}, -#line 96 "keywords.gperf" - {"__transparent_union__", TK_TRANSPARENT_UNION}, - {""}, -#line 90 "keywords.gperf" - {"__real__", TK_REAL}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 117 "keywords.gperf" - {"__gnu_scanf__", TK_GNU_SCANF}, - {""}, {""}, {""}, {""}, -#line 48 "keywords.gperf" - {"_Alignof", TK_ALIGNOF}, - {""}, {""}, {""}, {""}, -#line 156 "keywords.gperf" - {"__weak__", TK_WEAK}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 32 "keywords.gperf" - {"register", TK_REGISTER}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 124 "keywords.gperf" - {"__leaf__", TK_LEAF}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, -#line 74 "keywords.gperf" - {"__label__", TK_LABEL}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, -#line 14 "keywords.gperf" - {"break", TK_BREAK} - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register unsigned int key = hash (str, len); - - if (key <= MAX_HASH_VALUE) - { - register const char *s = wordlist[key].name; - - if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') - return &wordlist[key]; - } - } - return 0; -} diff --git a/tool/tags/tags.c b/tool/tags/tags.c deleted file mode 100644 index 9efa0246..00000000 --- a/tool/tags/tags.c +++ /dev/null @@ -1,343 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/bits.h" -#include "libc/bits/safemacros.internal.h" -#include "libc/calls/calls.h" -#include "libc/conv/conv.h" -#include "libc/errno.h" -#include "libc/log/log.h" -#include "libc/macros.h" -#include "libc/mem/mem.h" -#include "libc/nexgen32e/bsf.h" -#include "libc/nexgen32e/bsr.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/o.h" -#include "libc/time/time.h" -#include "libc/x/x.h" -#include "o/tool/tags/tags.c.inc" -#include "o/tool/tags/tags.h.inc" -#include "tool/tags/tags.h" - -static jmp_buf jb; -static int g_line; -static int g_column; -static const char *g_file; -static yyParser g_parser[1]; - -noreturn static void Error(const char *msg) { - fprintf(stderr, "%s:%d:%d: %s\n", g_file, g_line, g_column, msg); - longjmp(jb, 1); -} - -noreturn static void SyntaxError(void) { - Error("SYNTAX ERROR"); -} - -noreturn static void LexError(void) { - Error("LEX ERROR"); -} - -noreturn static void MissingArgumentError(void) { - Error("MISSING ARGUMENT"); -} - -noreturn static void MissingFunctionError(void) { - Error("MISSING FUNCTION"); -} - -noreturn static void SyscallError(const char *name) { - fprintf(stderr, "ERROR: %s[%s]: %d\n", name, g_file, errno); - exit(1); -} - -static void ExprsFree(struct Exprs *n) { - if (n) { - ExprsFree(n->n); - free(n); - } -} - -static struct Exprs *ExprsAppend(struct Exprs *n, long double x) { - struct Exprs *a; - a = malloc(sizeof(struct Exprs)); - a->n = n; - a->x = x; - return a; -} - -static long double ParseExpr(struct Token t) { - char *ep; - ep = t.s + t.n; - if (t.s[0] == '0') { - return strtoumax(t.s, &ep, 0); - } else { - return strtod(t.s, &ep); - } -} - -static long double CallFunction(struct Token fn, struct Exprs *args) { - return 0; -} - -static void Tokenize(const char *s, size_t size) { - int kw; - size_t n; - char *se; - for (se = s + size; s < se; s += n, ++g_column) { - n = 1; - switch (*s & 0xff) { - case ' ': - case '\t': - case '\v': - case '\r': - case 0x0C: - break; - case '\n': - ++g_line; - g_column = 0; - break; - case 'A' ... 'Z': - case 'a' ... 'z': - n = strspn(s, "$" - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"); - if ((kw = GetKeyword(s, n)) != -1) { - Parse(g_parser, kw, (struct Token){s, n}); - } else { - Parse(g_parser, TK_SYMBOL, (struct Token){s, n}); - } - break; - case '0': - n = strspn(s, "xXbB0123456789abcdefABCDEF"); - Parse(g_parser, TK_I_CONSTANT, (struct Token){s, n}); - n += strspn(s + n, "LUlu"); - break; - case '1' ... '9': - n = strspn(s, "0123456789."); - if (s[n] == 'e' || s[n] == 'E') { - ++n; - if (s[n] == '+' || s[n] == '-') ++n; - n += strspn(s + n, "0123456789"); - } - Parse(g_parser, memchr(s, '.', n) ? TK_F_CONSTANT : TK_I_CONSTANT, - (struct Token){s, n}); - n += strspn(s + n, "LUlu"); - break; - case ';': - Parse(g_parser, TK_SEMI, (struct Token){0, 0}); - break; - case '(': - Parse(g_parser, TK_LP, (struct Token){0, 0}); - break; - case ')': - Parse(g_parser, TK_RP, (struct Token){0, 0}); - break; - case '[': - Parse(g_parser, TK_LSB, (struct Token){0, 0}); - break; - case ']': - Parse(g_parser, TK_RSB, (struct Token){0, 0}); - break; - case '{': - Parse(g_parser, TK_LCB, (struct Token){0, 0}); - break; - case '}': - Parse(g_parser, TK_RCB, (struct Token){0, 0}); - break; - case '?': - Parse(g_parser, TK_QUESTION, (struct Token){0, 0}); - break; - case ':': - Parse(g_parser, TK_COLON, (struct Token){0, 0}); - break; - case ',': - Parse(g_parser, TK_COMMA, (struct Token){0, 0}); - break; - case '^': - if (s[1] == '=') { - Parse(g_parser, TK_XOR_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_XOR, (struct Token){0, 0}); - } - break; - case '%': - if (s[1] == '=') { - Parse(g_parser, TK_REM_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_REM, (struct Token){0, 0}); - } - break; - case '.': - Parse(g_parser, TK_DOT, (struct Token){0, 0}); - break; - case '+': - if (s[1] == '=') { - Parse(g_parser, TK_ADD_ASSIGN, (struct Token){0, 0}); - ++n; - } else if (s[1] == '+') { - Parse(g_parser, TK_INC, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_ADD, (struct Token){0, 0}); - } - break; - case '-': - if (s[1] == '=') { - Parse(g_parser, TK_SUB_ASSIGN, (struct Token){0, 0}); - ++n; - } else if (s[1] == '-') { - Parse(g_parser, TK_DEC, (struct Token){0, 0}); - ++n; - } else if (s[1] == '>') { - Parse(g_parser, TK_ARROW, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_SUB, (struct Token){0, 0}); - } - break; - case '~': - Parse(g_parser, TK_TILDE, (struct Token){0, 0}); - break; - case '/': - if (s[1] == '=') { - Parse(g_parser, TK_DIV_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_DIV, (struct Token){0, 0}); - } - break; - case '*': - if (s[1] == '=') { - Parse(g_parser, TK_MUL_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_STAR, (struct Token){0, 0}); - } - break; - case '|': - if (s[1] == '|') { - Parse(g_parser, TK_OR_LOGICAL, (struct Token){0, 0}); - ++n; - } else if (s[1] == '=') { - Parse(g_parser, TK_OR_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_OR, (struct Token){0, 0}); - } - break; - case '&': - if (s[1] == '&') { - Parse(g_parser, TK_AND_LOGICAL, (struct Token){0, 0}); - ++n; - } else if (s[1] == '=') { - Parse(g_parser, TK_AND_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_AND, (struct Token){0, 0}); - } - break; - case '!': - if (s[1] == '=') { - Parse(g_parser, TK_NOTEQUAL, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_EXCLAIM, (struct Token){0, 0}); - } - break; - case '=': - if (s[1] == '=') { - Parse(g_parser, TK_EQUAL, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_EQ, (struct Token){0, 0}); - } - break; - case '>': - if (s[1] == '=') { - Parse(g_parser, TK_GE, (struct Token){0, 0}); - ++n; - } else if (s[1] == '>') { - if (s[2] == '=') { - Parse(g_parser, TK_SHR_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_SHR, (struct Token){0, 0}); - } - ++n; - } else { - Parse(g_parser, TK_GT, (struct Token){0, 0}); - } - break; - case '<': - if (s[1] == '=') { - Parse(g_parser, TK_LE, (struct Token){0, 0}); - ++n; - } else if (s[1] == '<') { - if (s[2] == '=') { - Parse(g_parser, TK_SHL_ASSIGN, (struct Token){0, 0}); - ++n; - } else { - Parse(g_parser, TK_SHL, (struct Token){0, 0}); - } - ++n; - } else { - Parse(g_parser, TK_LT, (struct Token){0, 0}); - } - break; - default: - LexError(); - } - } -} - -int main(int argc, char *argv[]) { - int i; - int ec; - int fd; - size_t n; - char *buf; - ssize_t rc; - size_t bufcap; - bufcap = BIGPAGESIZE; - buf = malloc(bufcap); - if (!(ec = setjmp(jb))) { - for (i = 1; i < argc; ++i) { - g_file = argv[i]; - g_line = 0; - g_column = 0; - n = 0; /* wut */ - if ((fd = open(g_file, O_RDONLY)) == -1) SyscallError("open"); - ParseInit(g_parser); - for (;;) { - if ((rc = read(fd, buf, bufcap)) == -1) SyscallError("read"); - if (!(n = rc)) break; - Tokenize(buf, n); - } - close(fd); - Parse(g_parser, 0, (struct Token){0, 0}); - ParseFinalize(g_parser); - } - } - free(buf); - return ec; -} diff --git a/tool/tags/tags.h b/tool/tags/tags.h deleted file mode 100644 index bc5f7cca..00000000 --- a/tool/tags/tags.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef COSMOPOLITAN_TOOL_TAGS_TAGS_H_ -#define COSMOPOLITAN_TOOL_TAGS_TAGS_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -struct Token { - const char *s; - size_t n; -}; - -struct Exprs { - struct Exprs *n; - long double x; -}; - -static void SyntaxError(void) noreturn; -static long double ParseExpr(struct Token); -static void ExprsFree(struct Exprs *); -static struct Exprs *ExprsAppend(struct Exprs *, long double); -static long double CallFunction(struct Token, struct Exprs *); -int GetKeyword(const char *, size_t); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_TOOL_TAGS_TAGS_H_ */ diff --git a/tool/tags/tags.mk b/tool/tags/tags.mk deleted file mode 100644 index d02e1b22..00000000 --- a/tool/tags/tags.mk +++ /dev/null @@ -1,74 +0,0 @@ -#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ -#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ - -PKGS += TOOL_TAGS - -TOOL_TAGS = $(TOOL_LIB_A_DEPS) $(TOOL_LIB_A) -TOOL_TAGS_A = o/$(MODE)/tool/tags/tags.a -TOOL_TAGS_FILES := $(wildcard tool/tags/*) -TOOL_TAGS_COMS = $(TOOL_TAGS_OBJS:%.o=%.com) -TOOL_TAGS_SRCS = $(filter %.c,$(TOOL_TAGS_FILES)) -TOOL_TAGS_HDRS = $(filter %.h,$(TOOL_TAGS_FILES)) - -TOOL_TAGS_OBJS = \ - $(TOOL_TAGS_SRCS:%=o/$(MODE)/%.zip.o) \ - $(TOOL_TAGS_SRCS:%.c=o/$(MODE)/%.o) - -TOOL_TAGS_COMS = \ - $(TOOL_TAGS_SRCS:%.c=o/$(MODE)/%.com) - -TOOL_TAGS_BINS = \ - $(TOOL_TAGS_COMS) \ - $(TOOL_TAGS_COMS:%=%.dbg) - -TOOL_TAGS_CHECKS = \ - $(TOOL_TAGS_HDRS:%=o/$(MODE)/%.ok) - -TOOL_TAGS_DIRECTDEPS = \ - LIBC_BITS \ - LIBC_CALLS \ - LIBC_CONV \ - LIBC_LOG \ - LIBC_FMT \ - LIBC_MEM \ - LIBC_NEXGEN32E \ - LIBC_RUNTIME \ - LIBC_STDIO \ - LIBC_STUBS \ - LIBC_STR \ - LIBC_SYSV \ - LIBC_TINYMATH \ - LIBC_X \ - THIRD_PARTY_COMPILER_RT \ - THIRD_PARTY_DTOA - -TOOL_TAGS_DEPS := \ - $(call uniq,$(foreach x,$(TOOL_TAGS_DIRECTDEPS),$($(x)))) - -$(TOOL_TAGS_A): \ - tool/tags/ \ - $(TOOL_TAGS_A).pkg \ - $(TOOL_TAGS_OBJS) - -$(TOOL_TAGS_A).pkg: \ - $(TOOL_TAGS_OBJS) \ - $(foreach x,$(TOOL_TAGS_DIRECTDEPS),$($(x)_A).pkg) - -o/tool/tags/tags.h.inc: o/tool/tags/tags.c.inc -o/tool/tags/tags.c.inc: \ - tool/tags/tags.y \ - $(THIRD_PARTY_LEMON) - @$(LEMON) -l -d$(@D) $< - -o/$(MODE)/tool/tags/%.com.dbg: \ - $(TOOL_TAGS_DEPS) \ - $(TOOL_TAGS_A) \ - o/$(MODE)/tool/tags/%.o \ - $(TOOL_TAGS_A).pkg \ - $(CRT) \ - $(APE) - @$(APELINK) - -.PHONY: o/$(MODE)/tool/tags -o/$(MODE)/tool/tags: -# TODO: Why isn't tags.h.inc being generated? diff --git a/tool/tags/tags.y b/tool/tags/tags.y deleted file mode 100644 index 5869a5ae..00000000 --- a/tool/tags/tags.y +++ /dev/null @@ -1,436 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -%include { -#include "libc/stdio/stdio.h" -#include "tool/tags/tags.h" -#include "libc/calls/calls.h" -#include "libc/str/str.h" -#include "third_party/dtoa/dtoa.h" -#include "libc/x/x.h" -#include "libc/runtime/gc.h" -#include "libc/math.h" -} - -/** - * C parser. - * - * “The grammar of C seems remarkably well-behaved. It is almost - * LALR(1). More precisely, the automaton built for C by an LALR(1) - * parser generator exhibits only two conflicts: (1) a shift/reduce - * conflict caused by dangling else ambiguity and (2) a shift/reduce - * conflict caused by the _Atomic( ambiguity. In both cases, the - * desired behavior can be obtained by instructing the parser to - * prefer shifting.” Quoth Jacques-Henri Jourdan & François Pottier - * - */ - -%token_prefix TK_ -%token_type {struct Token} -%default_type {struct Token} -%syntax_error { SyntaxError(); } - -%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM EXTERN. -%token FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT RETURN SHORT SIGNED. -%token SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE WHILE. -%token ALIGNAS ALIGNOF ATOMIC BOOL COMPLEX GENERIC IMAGINARY NORETURN INCLUDE. -%token STATIC_ASSERT THREAD_LOCAL ELIF ENDIF IFDEF IFNDEF DEFINE UNDEF PRAGMA. -%token LINE ERROR SYMBOL ATTRIBUTE RESTRICT TYPEOF TYPEOF INLINE CONST LABEL. -%token FORCE_ALIGN_ARG_POINTER ALWAYS_INLINE GNU_INLINE ALIGNOF ASM AUTO_TYPE. -%token BYTE COMPLEX IMAG MAY_ALIAS NORETURN PACKED POINTER PRINTF REAL SCANF. -%token STRFMON STRFTIME STRONG TARGET TRANSPARENT_UNION VOLATILE WORD ALIAS. -%token ALIGNED ALLOC_ALIGN ALLOC_SIZE ARTIFICIAL ASSUME_ALIGNED COLD. -%token CONSTRUCTOR DESTRUCTOR COPY DEPRECATED ERROR WARNING EXTERNALLY_VISIBLE. -%token FLATTEN FORMAT GNU_FORMAT GNU_PRINTF GNU_SCANF FORMAT_ARG HOT IFUNC. -%token INTERRUPT INTERRUPT_HANDLER NO_CALLER_SAVED_REGISTERS LEAF MALLOC NO_ICF. -%token NO_INSTRUMENT_FUNCTION NO_PROFILE_INSTRUMENT_FUNCTION NO_REORDER. -%token NO_SANITIZE NO_SANITIZE_ADDRESS NO_ADDRESS_SAFETY_ANALYSIS. -%token NO_SANITIZE_THREAD NO_SANITIZE_UNDEFINED NO_SPLIT_STACK NO_STACK_LIMIT. -%token NOCLONE NOIPA NONNULL NOPLT NOTHROW OPTIMIZE PURE. -%token PATCHABLE_FUNCTION_ENTRY RETURNS_NONNULL RETURNS_TWICE SECTION SENTINEL. -%token SIMD TARGET_CLONES UNUSED USED VISIBILITY WARN_UNUSED_RESULT. -%token PARAMS_NONNULL WEAK VECTOR_SIZE MS_ABI MODE OPTNONE NODEBUG. - -%left IF. -%left ELSE. -%right COMMA. -%right EQ ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN REM_ASSIGN. -%right SHL_ASSIGN SHR_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN. -%right QUESTION COLON. -%left OR_LOGICAL. -%left AND_LOGICAL. -%left OR. -%left XOR. -%left AND. -%left EQUAL NOTEQUAL. -%left LT LE GT GE. -%left SHL SHR. -%left ADD SUB. -%left STAR DIV REM. -%right TILDE EXCLAIM INC DEC AMP SIZEOF ALIGNOF. -%left DOT ARROW LP RP RSB LSB. - -program ::= translation_unit. - -translation_unit ::= external_declaration. -translation_unit ::= translation_unit external_declaration. - -external_declaration ::= function_definition. -external_declaration ::= declaration. - -function_definition ::= declaration_specifiers declarator declaration_list compound_statement. -function_definition ::= declaration_specifiers declarator compound_statement. - -declaration_list ::= declaration. -declaration_list ::= declaration_list declaration. - -jump_statement ::= GOTO IDENTIFIER SEMI. -jump_statement ::= CONTINUE SEMI. -jump_statement ::= BREAK SEMI. -jump_statement ::= RETURN SEMI. -jump_statement ::= RETURN expression SEMI. - -iteration_statement ::= WHILE LP expression RP statement. -iteration_statement ::= DO statement WHILE LP expression RP SEMI. -iteration_statement ::= FOR LP expression_statement expression_statement RP statement. -iteration_statement ::= FOR LP expression_statement expression_statement expression RP statement. -iteration_statement ::= FOR LP declaration expression_statement RP statement. -iteration_statement ::= FOR LP declaration expression_statement expression RP statement. - -selection_statement ::= IF LP expression RP statement ELSE statement. -selection_statement ::= IF LP expression RP statement. -selection_statement ::= SWITCH LP expression RP statement. - -expression_statement ::= SEMI. -expression_statement ::= expression SEMI. - -block_item ::= declaration. -block_item ::= statement. - -block_item_list ::= block_item. -block_item_list ::= block_item_list block_item. - -compound_statement ::= LCB RCB. -compound_statement ::= LCB block_item_list RCB. - -labeled_statement ::= IDENTIFIER COLON statement. -labeled_statement ::= CASE constant_expression COLON statement. -labeled_statement ::= DEFAULT COLON statement. - -statement ::= labeled_statement. -statement ::= compound_statement. -statement ::= expression_statement. -statement ::= selection_statement. -statement ::= iteration_statement. -statement ::= jump_statement. - -static_assert_declaration ::= STATIC_ASSERT LP constant_expression COMMA STRING_LITERAL RP SEMI. - -designator ::= LSB constant_expression RSB. -designator ::= DOT IDENTIFIER. - -designator_list ::= designator. -designator_list ::= designator_list designator. - -designation ::= designator_list EQ. - -initializer_list ::= designation initializer. -initializer_list ::= initializer. -initializer_list ::= initializer_list COMMA designation initializer. -initializer_list ::= initializer_list COMMA initializer. - -initializer ::= LCB initializer_list RCB. -initializer ::= LCB initializer_list COMMA RCB. -initializer ::= assignment_expression. - -direct_abstract_declarator ::= LP abstract_declarator RP. -direct_abstract_declarator ::= LSB RSB. -direct_abstract_declarator ::= LSB STAR RSB. -direct_abstract_declarator ::= LSB STATIC type_qualifier_list assignment_expression RSB. -direct_abstract_declarator ::= LSB STATIC assignment_expression RSB. -direct_abstract_declarator ::= LSB type_qualifier_list STATIC assignment_expression RSB. -direct_abstract_declarator ::= LSB type_qualifier_list assignment_expression RSB. -direct_abstract_declarator ::= LSB type_qualifier_list RSB. -direct_abstract_declarator ::= LSB assignment_expression RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB STAR RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB STATIC type_qualifier_list assignment_expression RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB STATIC assignment_expression RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB type_qualifier_list assignment_expression RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB type_qualifier_list STATIC assignment_expression RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB type_qualifier_list RSB. -direct_abstract_declarator ::= direct_abstract_declarator LSB assignment_expression RSB. -direct_abstract_declarator ::= LP RP. -direct_abstract_declarator ::= LP parameter_type_list RP. -direct_abstract_declarator ::= direct_abstract_declarator LP RP. -direct_abstract_declarator ::= direct_abstract_declarator LP parameter_type_list RP. - -abstract_declarator ::= pointer direct_abstract_declarator. -abstract_declarator ::= pointer. -abstract_declarator ::= direct_abstract_declarator. - -type_name ::= specifier_qualifier_list abstract_declarator. -type_name ::= specifier_qualifier_list. - -primary_expression ::= IDENTIFIER. -primary_expression ::= constant. -primary_expression ::= string. -primary_expression ::= LP expression RP. -primary_expression ::= generic_selection. - -constant ::= I_CONSTANT. -constant ::= F_CONSTANT. -constant ::= ENUMERATION_CONSTANT. - -enumeration_constant ::= IDENTIFIER. - -string ::= STRING_LITERAL. -string ::= FUNC_NAME. - -generic_selection ::= GENERIC LP assignment_expression COMMA generic_assoc_list RP. - -generic_assoc_list ::= generic_association. -generic_assoc_list ::= generic_assoc_list COMMA generic_association. - -generic_association ::= type_name COLON assignment_expression. -generic_association ::= DEFAULT COLON assignment_expression. - -postfix_expression ::= primary_expression. -postfix_expression ::= postfix_expression LSB expression RSB. -postfix_expression ::= postfix_expression LP RP. -postfix_expression ::= postfix_expression LP argument_expression_list RP. -postfix_expression ::= postfix_expression DOT IDENTIFIER. -postfix_expression ::= postfix_expression ARROW IDENTIFIER. -postfix_expression ::= postfix_expression INC. -postfix_expression ::= postfix_expression DEC. -postfix_expression ::= LP type_name RP LCB initializer_list RCB. -postfix_expression ::= LP type_name RP LCB initializer_list COMMA RCB. - -argument_expression_list ::= assignment_expression. -argument_expression_list ::= argument_expression_list COMMA assignment_expression. - -unary_expression ::= postfix_expression. -unary_expression ::= INC unary_expression. -unary_expression ::= DEC unary_expression. -unary_expression ::= unary_operator cast_expression. -unary_expression ::= SIZEOF unary_expression. -unary_expression ::= SIZEOF LP type_name RP. -unary_expression ::= ALIGNOF LP type_name RP. - -unary_operator ::= AMP. -unary_operator ::= STAR. -unary_operator ::= ADD. -unary_operator ::= SUB. -unary_operator ::= TILDE. -unary_operator ::= EXCLAIM. - -cast_expression ::= unary_expression. -cast_expression ::= LP type_name RP cast_expression. - -multiplicative_expression ::= cast_expression. -multiplicative_expression ::= multiplicative_expression STAR cast_expression. -multiplicative_expression ::= multiplicative_expression DIV cast_expression. -multiplicative_expression ::= multiplicative_expression REM cast_expression. - -additive_expression ::= multiplicative_expression. -additive_expression ::= additive_expression ADD multiplicative_expression. -additive_expression ::= additive_expression SUB multiplicative_expression. - -shift_expression ::= additive_expression. -shift_expression ::= shift_expression SHL additive_expression. -shift_expression ::= shift_expression SHR additive_expression. - -relational_expression ::= shift_expression. -relational_expression ::= relational_expression LT shift_expression. -relational_expression ::= relational_expression GT shift_expression. -relational_expression ::= relational_expression LE shift_expression. -relational_expression ::= relational_expression GE shift_expression. - -equality_expression ::= relational_expression. -equality_expression ::= equality_expression EQUAL relational_expression. -equality_expression ::= equality_expression NOTEQUAL relational_expression. - -and_expression ::= equality_expression. -and_expression ::= and_expression AMP equality_expression. - -exclusive_or_expression ::= and_expression. -exclusive_or_expression ::= exclusive_or_expression XOR and_expression. -inclusive_or_expression ::= exclusive_or_expression. -inclusive_or_expression ::= inclusive_or_expression OR exclusive_or_expression. - -logical_and_expression ::= inclusive_or_expression. -logical_and_expression ::= logical_and_expression AND_LOGICAL inclusive_or_expression. - -logical_or_expression ::= logical_and_expression. -logical_or_expression ::= logical_or_expression OR_LOGICAL logical_and_expression. - -conditional_expression ::= logical_or_expression. -conditional_expression ::= logical_or_expression QUESTION expression COLON conditional_expression. - -assignment_expression ::= conditional_expression. -assignment_expression ::= unary_expression assignment_operator assignment_expression. - -assignment_operator ::= EQ. -assignment_operator ::= MUL_ASSIGN. -assignment_operator ::= DIV_ASSIGN. -assignment_operator ::= REM_ASSIGN. -assignment_operator ::= ADD_ASSIGN. -assignment_operator ::= SUB_ASSIGN. -assignment_operator ::= SHL_ASSIGN. -assignment_operator ::= SHR_ASSIGN. -assignment_operator ::= AND_ASSIGN. -assignment_operator ::= XOR_ASSIGN. -assignment_operator ::= OR_ASSIGN. - -expression ::= assignment_expression. -expression ::= expression COMMA assignment_expression. - -constant_expression ::= conditional_expression. /* with constraints */ - -declaration ::= declaration_specifiers SEMI. -declaration ::= declaration_specifiers init_declarator_list SEMI. -declaration ::= static_assert_declaration. - -declaration_specifiers ::= storage_class_specifier declaration_specifiers. -declaration_specifiers ::= storage_class_specifier. -declaration_specifiers ::= type_specifier declaration_specifiers. -declaration_specifiers ::= type_specifier. -declaration_specifiers ::= type_qualifier declaration_specifiers. -declaration_specifiers ::= type_qualifier. -declaration_specifiers ::= function_specifier declaration_specifiers. -declaration_specifiers ::= function_specifier. -declaration_specifiers ::= alignment_specifier declaration_specifiers. -declaration_specifiers ::= alignment_specifier. - -init_declarator_list ::= init_declarator. -init_declarator_list ::= init_declarator_list COMMA init_declarator. - -init_declarator ::= declarator EQ initializer. -init_declarator ::= declarator. - -storage_class_specifier ::= TYPEDEF. /* identifiers must be flagged as TYPEDEF_NAME */ -storage_class_specifier ::= EXTERN. -storage_class_specifier ::= STATIC. -storage_class_specifier ::= THREAD_LOCAL. -storage_class_specifier ::= AUTO. -storage_class_specifier ::= REGISTER. - -type_specifier ::= VOID. -type_specifier ::= CHAR. -type_specifier ::= SHORT. -type_specifier ::= INT. -type_specifier ::= LONG. -type_specifier ::= FLOAT. -type_specifier ::= DOUBLE. -type_specifier ::= SIGNED. -type_specifier ::= UNSIGNED. -type_specifier ::= BOOL. -type_specifier ::= COMPLEX. -type_specifier ::= IMAGINARY. /* non-mandated extension */ -type_specifier ::= struct_or_union_specifier. -type_specifier ::= enum_specifier. -type_specifier ::= TYPEDEF_NAME. /* after it has been defined as such */ - -struct_or_union_specifier ::= struct_or_union LCB struct_declaration_list RCB. -struct_or_union_specifier ::= struct_or_union IDENTIFIER LCB struct_declaration_list RCB. -struct_or_union_specifier ::= struct_or_union IDENTIFIER. - -struct_or_union ::= STRUCT. -struct_or_union ::= UNION. - -struct_declaration_list ::= struct_declaration. -struct_declaration_list ::= struct_declaration_list struct_declaration. - -struct_declaration ::= specifier_qualifier_list SEMI. /* for anonymous struct/union */ -struct_declaration ::= specifier_qualifier_list struct_declarator_list SEMI. -struct_declaration ::= static_assert_declaration. - -specifier_qualifier_list ::= type_specifier specifier_qualifier_list. -specifier_qualifier_list ::= type_specifier. -specifier_qualifier_list ::= type_qualifier specifier_qualifier_list. -specifier_qualifier_list ::= type_qualifier. - -struct_declarator_list ::= struct_declarator. -struct_declarator_list ::= struct_declarator_list COMMA struct_declarator. - -struct_declarator ::= COLON constant_expression. -struct_declarator ::= declarator COLON constant_expression. -struct_declarator ::= declarator. - -enum_specifier ::= ENUM LCB enumerator_list RCB. -enum_specifier ::= ENUM LCB enumerator_list COMMA RCB. -enum_specifier ::= ENUM IDENTIFIER LCB enumerator_list RCB. -enum_specifier ::= ENUM IDENTIFIER LCB enumerator_list COMMA RCB. -enum_specifier ::= ENUM IDENTIFIER. - -enumerator_list ::= enumerator. -enumerator_list ::= enumerator_list COMMA enumerator. - -enumerator ::= enumeration_constant EQ constant_expression. -enumerator ::= enumeration_constant. - -type_qualifier ::= CONST. -type_qualifier ::= RESTRICT. -type_qualifier ::= VOLATILE. -type_qualifier ::= ATOMIC. - -function_specifier ::= INLINE. -function_specifier ::= NORETURN. - -alignment_specifier ::= ALIGNAS LP type_name RP. -alignment_specifier ::= ALIGNAS LP constant_expression RP. - -declarator ::= pointer direct_declarator. -declarator ::= direct_declarator. - -direct_declarator ::= IDENTIFIER. -direct_declarator ::= LP declarator RP. -direct_declarator ::= direct_declarator LSB RSB. -direct_declarator ::= direct_declarator LSB STAR RSB. -direct_declarator ::= direct_declarator LSB STATIC type_qualifier_list assignment_expression RSB. -direct_declarator ::= direct_declarator LSB STATIC assignment_expression RSB. -direct_declarator ::= direct_declarator LSB type_qualifier_list STAR RSB. -direct_declarator ::= direct_declarator LSB type_qualifier_list STATIC assignment_expression RSB. -direct_declarator ::= direct_declarator LSB type_qualifier_list assignment_expression RSB. -direct_declarator ::= direct_declarator LSB type_qualifier_list RSB. -direct_declarator ::= direct_declarator LSB assignment_expression RSB. -direct_declarator ::= direct_declarator LP parameter_type_list RP. -direct_declarator ::= direct_declarator LP RP. -direct_declarator ::= direct_declarator LP identifier_list RP. - -pointer ::= STAR type_qualifier_list pointer. -pointer ::= STAR type_qualifier_list. -pointer ::= STAR pointer. -pointer ::= STAR. - -type_qualifier_list ::= type_qualifier. -type_qualifier_list ::= type_qualifier_list type_qualifier. - -parameter_type_list ::= parameter_list COMMA ELLIPSIS. -parameter_type_list ::= parameter_list. - -parameter_list ::= parameter_declaration. -parameter_list ::= parameter_list COMMA parameter_declaration. - -parameter_declaration ::= declaration_specifiers declarator. -parameter_declaration ::= declaration_specifiers abstract_declarator. -parameter_declaration ::= declaration_specifiers. - -identifier_list ::= IDENTIFIER. -identifier_list ::= identifier_list COMMA IDENTIFIER. diff --git a/tool/tool.mk b/tool/tool.mk index 3b050a26..317215e3 100644 --- a/tool/tool.mk +++ b/tool/tool.mk @@ -8,6 +8,4 @@ o/$(MODE)/tool: \ o/$(MODE)/tool/decode \ o/$(MODE)/tool/hash \ o/$(MODE)/tool/net \ - o/$(MODE)/tool/tags \ - o/$(MODE)/tool/viz \ - o/$(MODE)/tool/cc + o/$(MODE)/tool/viz diff --git a/tool/viz/bing.c b/tool/viz/bing.c index cdcce33b..27f34252 100644 --- a/tool/viz/bing.c +++ b/tool/viz/bing.c @@ -35,7 +35,7 @@ int ispipe_; int newlines_; -noreturn void ShowUsage(FILE *f, int rc) { +wontreturn void ShowUsage(FILE *f, int rc) { fputs(program_invocation_name, f); fputs(": [-p] [-n] [FILE...]\n", f); exit(rc); diff --git a/tool/viz/derasterize.c b/tool/viz/derasterize.c index b9a70ef7..f7aa07d7 100644 --- a/tool/viz/derasterize.c +++ b/tool/viz/derasterize.c @@ -398,8 +398,8 @@ static struct Cell derasterize(unsigned char block[CN][YS * XS]) { static char *RenderImage(char *v, unsigned yn, unsigned xn, const unsigned char srgb[yn][YS][xn][XS][CN]) { unsigned y, x, i, j, k; - unsigned char copy[YS][XS][CN] aligned(32); - unsigned char block[CN][YS * XS] aligned(32); + unsigned char copy[YS][XS][CN] forcealign(32); + unsigned char block[CN][YS * XS] forcealign(32); DCHECK_ALIGNED(32, v); DCHECK_ALIGNED(32, srgb); for (y = 0; y < yn; ++y) { diff --git a/tool/viz/double2int.c b/tool/viz/double2int.c index b5d22361..29ae3c0d 100644 --- a/tool/viz/double2int.c +++ b/tool/viz/double2int.c @@ -24,7 +24,7 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" void double2int(const char *s) { double b64; diff --git a/tool/viz/fold.c b/tool/viz/fold.c index 0590ccdb..d86cb5fc 100644 --- a/tool/viz/fold.c +++ b/tool/viz/fold.c @@ -29,7 +29,7 @@ int column_; -noreturn void usage(int rc, FILE *f) { +wontreturn void usage(int rc, FILE *f) { fputs("Usage: ", f); fputs(program_invocation_name, f); fputs(" [-w COLS] [FILE...]\n", f); diff --git a/tool/viz/generatematrix.c b/tool/viz/generatematrix.c index 0250e4ee..77bb2745 100644 --- a/tool/viz/generatematrix.c +++ b/tool/viz/generatematrix.c @@ -35,7 +35,7 @@ #include "libc/sysv/consts/ex.h" #include "libc/sysv/consts/exit.h" #include "libc/x/x.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" #include "third_party/getopt/getopt.h" #include "tool/viz/lib/formatstringtable.h" @@ -59,7 +59,7 @@ struct Range r1_ = {LONG_MIN, LONG_MAX}; struct Range r2_ = {0, 1}; StringTableFormatter *formatter_ = FormatStringTableAsCode; -static noreturn void PrintUsage(int rc, FILE *f) { +static wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "Usage: %s%s", program_invocation_name, "\ [FLAGS] [FILE]\n\ \n\ @@ -95,8 +95,8 @@ static bool StringEquals(const char *a, const char *b) { return strcasecmp(a, b) == 0; } -static noreturn void ShowInvalidArg(const char *name, const char *s, - const char *type) { +static wontreturn void ShowInvalidArg(const char *name, const char *s, + const char *type) { fprintf(stderr, "error: invalid %s %s: %s\n", type, name, s); exit(EXIT_FAILURE); } diff --git a/tool/viz/invertblocks.c b/tool/viz/invertblocks.c index 5c0dc19f..d4231c18 100644 --- a/tool/viz/invertblocks.c +++ b/tool/viz/invertblocks.c @@ -27,7 +27,7 @@ static FILE *fi_, *fo_; static char *inpath_, *outpath_; -noreturn void usage(int rc, FILE *f) { +wontreturn void usage(int rc, FILE *f) { fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, " [-o FILE] [FILE...]\n"); exit(rc); diff --git a/tool/viz/lib/formatmatrix-double.c b/tool/viz/lib/formatmatrix-double.c index ffc58a15..53e9d600 100644 --- a/tool/viz/lib/formatmatrix-double.c +++ b/tool/viz/lib/formatmatrix-double.c @@ -19,10 +19,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/conv/conv.h" +#include "libc/log/check.h" #include "libc/math.h" #include "libc/mem/mem.h" #include "libc/runtime/gc.h" #include "libc/x/x.h" +#include "third_party/gdtoa/gdtoa.h" #include "tool/viz/lib/formatstringtable.h" #include "tool/viz/lib/stringbuilder.h" @@ -34,7 +36,9 @@ void *ConvertMatrixToStringTable(long yn, long xn, char *T[yn][xn], assert(yn && xn && !T[0][0]); for (y = 0; y < yn; ++y) { for (x = 0; x < xn; ++x) { - T[y][x] = xdtoa(RoundDecimalPlaces(M[y][x], digs, rounder)); + T[y][x] = xmalloc(40); + T[y][x][0] = '\0'; + g_dfmt_p(T[y][x], &M[y][x], digs, 40, 0); } } return T; diff --git a/tool/viz/lib/vizlib.mk b/tool/viz/lib/vizlib.mk index 000c4446..8b6acbda 100644 --- a/tool/viz/lib/vizlib.mk +++ b/tool/viz/lib/vizlib.mk @@ -48,7 +48,7 @@ TOOL_VIZ_LIB_A_DIRECTDEPS = \ LIBC_STR \ LIBC_X \ THIRD_PARTY_AVIR \ - THIRD_PARTY_DTOA \ + THIRD_PARTY_GDTOA \ THIRD_PARTY_DLMALLOC TOOL_VIZ_LIB_A_DEPS := \ diff --git a/tool/viz/life.c b/tool/viz/life.c index 0252446b..6dd2cec2 100644 --- a/tool/viz/life.c +++ b/tool/viz/life.c @@ -668,7 +668,7 @@ static int Write(const char *s) { return write(out, s, strlen(s)); } -static noreturn void PrintUsage(int rc) { +static wontreturn void PrintUsage(int rc) { Write("SYNOPSIS\n\n "); Write(program_invocation_name); Write(USAGE); diff --git a/tool/viz/magikarp.c b/tool/viz/magikarp.c index 630d0e84..4591fa8c 100644 --- a/tool/viz/magikarp.c +++ b/tool/viz/magikarp.c @@ -43,7 +43,7 @@ #include "libc/x/x.h" #include "third_party/avir/lanczos1b.h" #include "third_party/avir/lanczos1f.h" -#include "third_party/dtoa/dtoa.h" +#include "third_party/gdtoa/gdtoa.h" #include "third_party/getopt/getopt.h" #include "third_party/stb/stb_image.h" #include "tool/viz/lib/bilinearscale.h" diff --git a/tool/viz/memzoom.c b/tool/viz/memzoom.c index 1dc8b414..5c0ed4b0 100644 --- a/tool/viz/memzoom.c +++ b/tool/viz/memzoom.c @@ -241,7 +241,7 @@ static void Setup(void) { sigaction(SIGWINCH, &(struct sigaction){.sa_sigaction = OnSigWinch}, NULL); } -static noreturn void FailPath(const char *s, int rc) { +static wontreturn void FailPath(const char *s, int rc) { Write("error: "); Write(s); Write(": "); @@ -861,7 +861,7 @@ static void MemZoom(void) { } while (!(action & INTERRUPTED)); } -static noreturn void PrintUsage(int rc) { +static wontreturn void PrintUsage(int rc) { Write("SYNOPSIS\n\n "); Write(program_invocation_name); Write(USAGE); diff --git a/tool/viz/printimage.c b/tool/viz/printimage.c index 31c6dfe3..021e4648 100644 --- a/tool/viz/printimage.c +++ b/tool/viz/printimage.c @@ -69,7 +69,7 @@ static struct Flags { enum TtyQuantizationAlgorithm quant; } g_flags; -static noreturn void PrintUsage(int rc, FILE *f) { +static wontreturn void PrintUsage(int rc, FILE *f) { fprintf(f, "Usage: %s%s", program_invocation_name, "\ [FLAGS] [PATH]\n\ \n\ diff --git a/tool/viz/printpixel.c b/tool/viz/printpixel.c index 2fec922a..b0cf0588 100644 --- a/tool/viz/printpixel.c +++ b/tool/viz/printpixel.c @@ -24,7 +24,6 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/ex.h" -#include "third_party/dtoa/dtoa.h" int main(int argc, char *argv[]) { int i; diff --git a/tool/viz/printvideo.c b/tool/viz/printvideo.c index 58a06501..6494ff4b 100644 --- a/tool/viz/printvideo.c +++ b/tool/viz/printvideo.c @@ -298,9 +298,9 @@ static struct Graphic graphic_[2], *g1_, *g2_; static bool yes_, stats_, dither_, ttymode_, istango_; static long double deadline_, dura_, skip_, starttime_; static long double decode_start_, f1_start_, f2_start_; -static bool fullclear_, historyclear_, tuned_, yonly_, gotvideo_; +static int16_t pcm_[PLM_AUDIO_SAMPLES_PER_FRAME * 2 / 8][8]; static int16_t pcmscale_[PLM_AUDIO_SAMPLES_PER_FRAME * 2 / 8][8]; -static int16_t pcm_[PLM_AUDIO_SAMPLES_PER_FRAME * 2 / 8][8] aligned(PAGESIZE); +static bool fullclear_, historyclear_, tuned_, yonly_, gotvideo_; static int homerow_, lastrow_, playfd_, infd_, outfd_, nullfd_, speakerfails_; static char host_[DNS_NAME_MAX + 1], port_[8], path_[PATH_MAX], status_[7][200], logpath_[PATH_MAX], fifopath_[PATH_MAX], chansstr_[16], sratestr_[16]; diff --git a/tool/viz/rgbtoxterm.c b/tool/viz/rgbtoxterm.c index d14b470c..6fa0f21e 100644 --- a/tool/viz/rgbtoxterm.c +++ b/tool/viz/rgbtoxterm.c @@ -54,7 +54,7 @@ static size_t linecap_; static char *outpath_, *line_; static bool rawmode_, background_, emphasis_, cleanup_; -noreturn void usage(int rc, FILE *f) { +wontreturn void usage(int rc, FILE *f) { fprintf(f, kUsage, program_invocation_name); exit(rc); } diff --git a/tool/viz/tabalign.c b/tool/viz/tabalign.c index 53668bab..6c33eb1e 100644 --- a/tool/viz/tabalign.c +++ b/tool/viz/tabalign.c @@ -55,7 +55,7 @@ static struct Lines lines_; static size_t mincol_, col_, maxcol_, linecap_; static char *inpath_, *outpath_, *delim_, *line_; -noreturn void usage(int rc, FILE *f) { +wontreturn void usage(int rc, FILE *f) { fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, " [-c] [-m MINCOL] [-M MAXCOL] [-F DELIM] [-o FILE] [FILE...]\n" "\n" diff --git a/tool/viz/viz.mk b/tool/viz/viz.mk index 31870c9d..5f7dc959 100644 --- a/tool/viz/viz.mk +++ b/tool/viz/viz.mk @@ -54,7 +54,7 @@ TOOL_VIZ_DIRECTDEPS = \ THIRD_PARTY_GETOPT \ THIRD_PARTY_AVIR \ THIRD_PARTY_DLMALLOC \ - THIRD_PARTY_DTOA \ + THIRD_PARTY_GDTOA \ THIRD_PARTY_STB \ THIRD_PARTY_XED \ THIRD_PARTY_ZLIB