diff --git a/build/config.mk b/build/config.mk index e7988b7f..07c7446b 100644 --- a/build/config.mk +++ b/build/config.mk @@ -104,7 +104,7 @@ CONFIG_COPTS += \ -ftrapv TARGET_ARCH ?= \ - -march=k8-sse3 + -msse3 OVERRIDE_CCFLAGS += \ -fno-pie @@ -177,6 +177,6 @@ ifeq ($(MODE), ansi) CONFIG_CFLAGS += -std=c11 #CONFIG_CPPFLAGS += -ansi CONFIG_CXXFLAGS += -std=c++11 -TARGET_ARCH ?= -march=k8-sse3 +TARGET_ARCH ?= -msse3 endif diff --git a/build/getccname b/build/getccname index 2d9fb168..00640525 100755 --- a/build/getccname +++ b/build/getccname @@ -22,6 +22,11 @@ set -e SPECIAL_TEXT=$( $1 --version | sed -n ' + /chibicc/ { + i\ +chibicc + q + } /Free Software/ { i\ gcc diff --git a/libc/bits/bits.h b/libc/bits/bits.h index 979c6862..b883bb44 100644 --- a/libc/bits/bits.h +++ b/libc/bits/bits.h @@ -229,12 +229,12 @@ unsigned long hamming(unsigned long, unsigned long) pureconst; * @see Intel Six-Thousand Page Manual Manual V.3A ยง8.2.3.1 * @see atomic_load() */ -#define atomic_store(MEM, VAL) \ - ({ \ - autotype(VAL) Val = (VAL); \ - typeof(&Val) Mem = (MEM); \ - asm("mov%z1\t%1,%0" : "=m,m"(*Mem) : "i,r"(Val)); \ - Val; \ +#define atomic_store(MEM, VAL) \ + ({ \ + autotype(VAL) Val = (VAL); \ + typeof(&Val) Mem = (MEM); \ + asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \ + Val; \ }) #define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */ diff --git a/libc/bits/bits.mk b/libc/bits/bits.mk index 8946028f..8b284e99 100644 --- a/libc/bits/bits.mk +++ b/libc/bits/bits.mk @@ -39,9 +39,6 @@ $(LIBC_BITS_A).pkg: \ $(LIBC_BITS_A_OBJS) \ $(foreach x,$(LIBC_BITS_A_DIRECTDEPS),$($(x)_A).pkg) -#o/$(MODE)/libc/bits/bsf.o: CC = clang-10 -#o/$(MODE)/libc/bits/bsf.o: CC = /opt/cross9cc/bin/x86_64-linux-musl-cc - LIBC_BITS_LIBS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x))) LIBC_BITS_SRCS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x)_SRCS)) LIBC_BITS_HDRS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/fmt/bing.internal.h b/libc/fmt/bing.internal.h index a3cf5ccd..1b0b989f 100644 --- a/libc/fmt/bing.internal.h +++ b/libc/fmt/bing.internal.h @@ -1,7 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_FMT_BING_H_ #define COSMOPOLITAN_LIBC_FMT_BING_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) -#ifndef __cplusplus int bing(int, int) nosideeffect; int unbing(int) nosideeffect; @@ -9,8 +8,6 @@ void *unbingbuf(void *, size_t, const char16_t *, int); void *unbingstr(const char16_t *) paramsnonnull() mallocesque; void *unhexbuf(void *, size_t, const char *); void *unhexstr(const char *) mallocesque; -short *bingblit(int ys, int xs, unsigned char[ys][xs], int, int); -#endif /* __cplusplus */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_FMT_BING_H_ */ diff --git a/libc/fmt/pflink.h b/libc/fmt/pflink.h index fa5392ec..d92a33c2 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) -#if !defined(__STRICT_ANSI__) && !defined(__chibicc__) +#ifndef __STRICT_ANSI__ /** * @fileoverview builtin+preprocessor+linker tricks for printf/scanf. diff --git a/libc/integral/c.inc b/libc/integral/c.inc index e45a64f6..7a0520dc 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -10,7 +10,7 @@ #define COSMOPOLITAN_CXX_USING_ #endif -#if defined(__STRICT_ANSI__) && __STDC_VERSION__ + 0 < 201112 +#ifdef __STRICT_ANSI__ #define asm __asm__ #endif @@ -773,8 +773,9 @@ typedef uint64_t uintmax_t; */ #if __cplusplus + 0 >= 201103L #define autotype(x) auto -#elif (__has_builtin(auto_type) || defined(__llvm__) || \ - (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) +#elif ((__has_builtin(auto_type) || defined(__llvm__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) && \ + !defined(__chibicc__)) #define autotype(x) __auto_type #else #define autotype(x) typeof(x) diff --git a/libc/intrin/palignr.h b/libc/intrin/palignr.h index 9ece960a..638ac166 100644 --- a/libc/intrin/palignr.h +++ b/libc/intrin/palignr.h @@ -7,7 +7,7 @@ COSMOPOLITAN_C_START_ void palignr(void *, const void *, const void *, unsigned long); -#ifndef __STRICT_ANSI__ +#if !defined(__STRICT_ANSI__) && !defined(__chibicc__) __intrin_xmm_t __palignrs(__intrin_xmm_t, __intrin_xmm_t); #define palignr(C, B, A, I) \ do { \ diff --git a/libc/intrin/pand.c b/libc/intrin/pand.c index 3017343b..9860afcc 100644 --- a/libc/intrin/pand.c +++ b/libc/intrin/pand.c @@ -20,7 +20,7 @@ #include "libc/intrin/pand.h" /** - * Nands 128-bit integers. + * Ands 128-bit integers. * * @param ๐‘Ž [w/o] receives result * @param ๐‘ [r/o] supplies first input vector diff --git a/libc/nexgen32e/cescapec.S b/libc/nexgen32e/cescapec.S index 39bf5b73..dc8250b2 100644 --- a/libc/nexgen32e/cescapec.S +++ b/libc/nexgen32e/cescapec.S @@ -59,10 +59,7 @@ cescapec: #ifdef __STRICT_ANSI__ .LQM: mov $'?',%ah ret -.LESC: -#elif defined(__GNUC__) -.LESC: mov $'e',%ah - ret +#else .LQM: #endif 1: mov %edi,%eax @@ -91,9 +88,7 @@ cescapectab.ro: .byte 1,.LVT-.Lanchorpoint .byte 1,.LFF-.Lanchorpoint .byte 1,.LCR-.Lanchorpoint - .byte 0x1b-'\r-1,1b-.Lanchorpoint - .byte 1,.LESC-.Lanchorpoint - .byte '\"-0x1b-1,1b-.Lanchorpoint + .byte '\"-'\r-1,1b-.Lanchorpoint .byte 1,.LDQ-.Lanchorpoint .byte '\'-'\"-1,1b-.Lanchorpoint .byte 1,.LSQ-.Lanchorpoint diff --git a/libc/str/strcmp8to16i.internal.h b/libc/str/strcmp8to16i.internal.h index c202c58a..8c27f3fe 100644 --- a/libc/str/strcmp8to16i.internal.h +++ b/libc/str/strcmp8to16i.internal.h @@ -1,6 +1,7 @@ #ifndef COSMOPOLITAN_LIBC_STR_STRCMP8TO16I_H_ #define COSMOPOLITAN_LIBC_STR_STRCMP8TO16I_H_ #include "libc/conv/conv.h" +#include "libc/macros.h" #include "libc/str/oldutf16.internal.h" #include "libc/str/str.h" #include "libc/str/tpdecode.internal.h" @@ -12,9 +13,12 @@ forceinline int strcmp8to16i(const char *s1, const char16_t *s2, size_t n, int res = 0; if (n) { do { + unsigned i, j; wint_t wc1, wc2; - s1 += abs(tpdecode(s1, &wc1)); - s2 += abs(getutf16(s2, &wc2)); + i = tpdecode(s1, &wc1); + j = getutf16(s2, &wc2); + s1 += ABS(i); + s2 += ABS(j); if ((res = xlat(wc1) - xlat(wc2)) || !wc1) break; } while (n == -1ul || --n); } diff --git a/test/dsp/scale/magikarp_test.c b/test/dsp/scale/magikarp_test.c index 1769892b..487ccd64 100644 --- a/test/dsp/scale/magikarp_test.c +++ b/test/dsp/scale/magikarp_test.c @@ -32,6 +32,8 @@ #include "libc/x/x.h" #include "tool/viz/lib/formatstringtable-testlib.h" +short *bingblit(int ys, int xs, unsigned char[ys][xs], int, int); + TEST(magikarp, testConvolve) { signed char K[8] = {-1, -3, 3, 17, 17, 3, -3, -1}; EXPECT_BINEQ( diff --git a/test/dsp/scale/scale_test.c b/test/dsp/scale/scale_test.c index 4e06098d..b2045079 100644 --- a/test/dsp/scale/scale_test.c +++ b/test/dsp/scale/scale_test.c @@ -32,6 +32,8 @@ #include "libc/x/x.h" #include "tool/viz/lib/formatstringtable-testlib.h" +short *bingblit(int ys, int xs, unsigned char[ys][xs], int, int); + void *AbsoluteDifference(int yn, int xn, unsigned char C[yn][xn], int ays, int axs, const unsigned char A[ays][axs], int bys, int bxs, const unsigned char B[bys][bxs]) { diff --git a/test/libc/calls/access_test.c b/test/libc/calls/access_test.c index 7f78b440..7ad96956 100644 --- a/test/libc/calls/access_test.c +++ b/test/libc/calls/access_test.c @@ -17,9 +17,9 @@ โ”‚ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA โ”‚ โ”‚ 02110-1301 USA โ”‚ โ•šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€*/ +#include "libc/calls/calls.h" #include "libc/errno.h" #include "libc/runtime/runtime.h" -#include "libc/calls/calls.h" #include "libc/sysv/consts/ok.h" #include "libc/testlib/testlib.h" @@ -29,7 +29,9 @@ textstartup static void init(void) { } const void *const ctors[] initarray = {init}; -TEST(access, readDirectory) { ASSERT_EQ(0, access("test/libc/", F_OK)); } +TEST(access, readDirectory) { + ASSERT_EQ(0, access("test/libc/", F_OK)); +} TEST(access, readThisCode) { ASSERT_EQ(0, access("test/libc/access_test.c", R_OK)); diff --git a/test/libc/nexgen32e/cescapec_test.c b/test/libc/nexgen32e/cescapec_test.c index 08538322..34f30fe6 100644 --- a/test/libc/nexgen32e/cescapec_test.c +++ b/test/libc/nexgen32e/cescapec_test.c @@ -26,6 +26,7 @@ TEST(cescapec, test) { EXPECT_EQ('\\' | 'r' << 8, cescapec('\r')); EXPECT_EQ('\\' | 'n' << 8, cescapec('\n')); EXPECT_EQ('\\' | '0' << 8 | '0' << 16 | '0' << 24, cescapec(0)); + EXPECT_EQ('\\' | '0' << 8 | '3' << 16 | '3' << 24, cescapec('\e')); EXPECT_EQ('\\' | '1' << 8 | '7' << 16 | '7' << 24, cescapec(0x7F)); EXPECT_EQ('\\' | '3' << 8 | '7' << 16 | '7' << 24, cescapec(0xFF)); EXPECT_EQ('\\' | '3' << 8 | '7' << 16 | '7' << 24, cescapec(0xFFFF)); diff --git a/test/libc/time/clock_gettime_test.c b/test/libc/time/clock_gettime_test.c index 9e38f86e..317d14ca 100644 --- a/test/libc/time/clock_gettime_test.c +++ b/test/libc/time/clock_gettime_test.c @@ -17,13 +17,14 @@ โ”‚ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA โ”‚ โ”‚ 02110-1301 USA โ”‚ โ•šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€*/ +#include "libc/calls/struct/timespec.h" #include "libc/conv/conv.h" +#include "libc/macros.h" #include "libc/runtime/gc.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/clock.h" #include "libc/testlib/testlib.h" #include "libc/time/time.h" -#include "libc/calls/struct/timespec.h" #include "libc/x/x.h" TEST(clock_gettime, testClockRealtime) { @@ -31,5 +32,5 @@ TEST(clock_gettime, testClockRealtime) { struct timespec ts; EXPECT_NE(-1, gettimeofday(&tv, NULL)); EXPECT_NE(-1, clock_gettime(CLOCK_REALTIME, &ts)); - EXPECT_LT((unsigned)abs(ts.tv_sec - tv.tv_sec), 5u); + EXPECT_LT((unsigned)ABS(ts.tv_sec - tv.tv_sec), 5u); } diff --git a/third_party/chibicc/README.cosmo b/third_party/chibicc/README.cosmo index c0498641..ab1115f0 100644 --- a/third_party/chibicc/README.cosmo +++ b/third_party/chibicc/README.cosmo @@ -6,21 +6,30 @@ which is great, considering it's a 220kb ฮฑcฯ„ยตฮฑlly pฮดrฯ„ฮฑblฮต ฮตxฮตcยตฯ„ฮฑb local enhancements -- support __asm__ +- support dce +- support gnu asm - support __int128 +- support _Static_assert - support __vector_size__ -- support __builtin_memcpy +- support __builtin_add_overflow, etc. +- support __builtin_memcpy, strlen, strpbrk, etc. - 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. +- support __constructor__, __section__, __cold__, -ffunction-sections, etc. +- support building -x assembler-with-cpp a.k.a. .S files +- support profiling w/ -mcount / -mfentry / -mnop-mcount - 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 +- allow casted values to be lvalues +- permit parentheses around string-initializer - fix 64-bit bug in generated code for struct bitfields +- fix bug where last statement in statement expression couldn't have label +- print_tokens (chibicc -E) now works in the case of adjacent string literals local changes diff --git a/third_party/chibicc/asm.c b/third_party/chibicc/asm.c index a461276c..320a7f61 100644 --- a/third_party/chibicc/asm.c +++ b/third_party/chibicc/asm.c @@ -40,7 +40,7 @@ static void DecodeAsmConstraints(AsmOperand *op) { switch ((c = op->str[i++])) { case '\0': case ',': // alternative group - return; + return; // todo: read combos case '0': case '1': case '2': @@ -180,13 +180,17 @@ static bool IsLvalue(AsmOperand *op) { } } -static bool CanUseReg(Node *n) { - return is_integer(n->ty) || n->ty->kind == TY_PTR; +static bool CanUseReg(Node **n) { + if ((*n)->ty->kind == TY_ARRAY) { + *n = new_cast(*n, pointer_to((*n)->ty->base)); + return true; + } + 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 || + return n->ty->vector_size == 16 || n->ty->kind == TY_FLOAT || + n->ty->kind == TY_DOUBLE || n->ty->kind == TY_PTR || (n->ty->kind == TY_ARRAY && n->ty->size == 16); } @@ -201,7 +205,7 @@ static int PickAsmReferenceType(AsmOperand *op, AsmOperand *ref) { case kAsmMem: error_tok(op->tok, "bad reference"); case kAsmReg: - if (!CanUseReg(op->node)) { + if (!CanUseReg(&op->node)) { error_tok(op->tok, "expected integral expression"); } op->regmask = 0; @@ -235,7 +239,7 @@ static int PickAsmOperandType(Asm *a, AsmOperand *op) { 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 & kAsmReg) && CanUseReg(&op->node)) return kAsmReg; if (op->type & kAsmFlag) return kAsmFlag; if (op->type & kAsmRaw) return kAsmRaw; error_tok(op->tok, "constraint mismatch"); @@ -245,7 +249,7 @@ static Token *ParseAsmOperand(Asm *a, AsmOperand *op, Token *tok) { int i; op->tok = tok; op->str = ConsumeStringLiteral(&tok, tok); - tok = skip(tok, "("); + tok = skip(tok, '('); op->node = expr(&tok, tok); add_type(op->node); DecodeAsmConstraints(op); @@ -255,7 +259,7 @@ static Token *ParseAsmOperand(Asm *a, AsmOperand *op, Token *tok) { } else { op->type = PickAsmOperandType(a, op); } - return skip(tok, ")"); + return skip(tok, ')'); } static Token *ParseAsmOperands(Asm *a, Token *tok) { @@ -267,7 +271,7 @@ static Token *ParseAsmOperands(Asm *a, Token *tok) { tok = ParseAsmOperand(a, &a->ops[a->n], tok); ++a->n; if (!EQUAL(tok, ",")) break; - tok = skip(tok, ","); + tok = skip(tok, ','); } return tok; } @@ -315,10 +319,6 @@ static void PickAsmRegisters(Asm *a) { } } } - for (i = 0; i < a->n; ++i) { - assert(!a->ops[i].regmask); - assert(!a->ops[i].x87mask); - } } static void MarkUsedAsmOperands(Asm *a) { @@ -378,11 +378,13 @@ static Token *ParseAsmClobbers(Asm *a, Token *tok) { i = s[3] - '0'; i &= 7; a->x87clob |= 1 << i; + } else if (!strcmp(s, "memory")) { + /* do nothing */ } else { error_tok(stok, "unknown clobber register"); } if (!EQUAL(tok, ",")) break; - tok = skip(tok, ","); + tok = skip(tok, ','); } return tok; } @@ -402,25 +404,25 @@ 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, "("); + tok = skip(tok, '('); a->tok = tok; a->str = ConsumeStringLiteral(&tok, tok); if (!EQUAL(tok, ")")) { a->isgnu = true; - tok = skip(tok, ":"); + tok = skip(tok, ':'); tok = ParseAsmOperands(a, tok); if (!EQUAL(tok, ")")) { - tok = skip(tok, ":"); + tok = skip(tok, ':'); tok = ParseAsmOperands(a, tok); if (!EQUAL(tok, ")")) { - tok = skip(tok, ":"); + tok = skip(tok, ':'); tok = ParseAsmClobbers(a, tok); } } } PickAsmRegisters(a); MarkUsedAsmOperands(a); - *rest = skip(tok, ")"); + *rest = skip(tok, ')'); return a; } @@ -541,24 +543,26 @@ static char *HandleAsmSpecifier(Asm *a, char *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; + if (*a->str) { + 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); } - } else { - println("\t%s", a->str); } } @@ -668,9 +672,9 @@ static void StoreAsmOutputs(Asm *a) { println("\tset%s\t(%%rax)", a->ops[i].str + a->ops[i].predicate); break; case kAsmReg: + z = bsr(a->ops[i].node->ty->size); 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 { @@ -678,7 +682,7 @@ static void StoreAsmOutputs(Asm *a) { push(); pop("%rbx"); gen_addr(a->ops[i].node); - println("\tmov\t%%rbx,(%%rax)"); + println("\tmov\t%%%s,(%%rax)", kGreg[z][3]); println("\tpop\t%%rbx"); } break; diff --git a/third_party/chibicc/cast.c b/third_party/chibicc/cast.c index ab2afc48..0ddb9010 100644 --- a/third_party/chibicc/cast.c +++ b/third_party/chibicc/cast.c @@ -150,8 +150,9 @@ static int getTypeId(Type *ty) { return F64; case TY_LDOUBLE: return F80; + default: + return U64; } - return U64; } void gen_cast(Type *from, Type *to) { diff --git a/third_party/chibicc/chibicc.c b/third_party/chibicc/chibicc.c index f8da0a66..3428af16 100644 --- a/third_party/chibicc/chibicc.c +++ b/third_party/chibicc/chibicc.c @@ -16,15 +16,21 @@ typedef enum { FILE_DSO, } FileType; -bool opt_fcommon = true; -bool opt_fpic; -bool opt_verbose; -bool opt_mpopcnt; +bool opt_common = true; +bool opt_data_sections; +bool opt_fentry; +bool opt_function_sections; +bool opt_no_builtin; +bool opt_nop_mcount; bool opt_pg; -bool opt_mfentry; -bool opt_mnop_mcount; -bool opt_mrecord_mcount; +bool opt_pic; +bool opt_popcnt; +bool opt_record_mcount; +bool opt_sse3; +bool opt_sse4; +bool opt_verbose; +static bool opt_A; static bool opt_E; static bool opt_M; static bool opt_MD; @@ -56,6 +62,14 @@ static void usage(int status) { exit(status); } +static void version(void) { + printf("\ +chibicc (cosmopolitan) 9.0.0\n\ +copyright 2019 rui ueyama\n\ +copyright 2020 justine alexandra roberts tunney\n"); + exit(0); +} + static bool take_arg(char *arg) { char *x[] = {"-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker"}; @@ -130,231 +144,171 @@ static void PrintMemoryUsage(void) { fprintf(stderr, "allocated %,ld bytes of memory\n", mi.arena); } +static void strarray_push_comma(StringArray *a, char *s) { + char *p; + for (; *s++ == ','; s = p) { + p = strchrnul(s, ','); + strarray_push(a, strndup(s, p - s)); + } +} + 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); + 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")) { + } else if (!strcmp(argv[i], "-cc1")) { opt_cc1 = true; - continue; - } - if (!strcmp(argv[i], "--help")) usage(0); - if (!strcmp(argv[i], "-v")) { + } else if (!strcmp(argv[i], "--help")) { + usage(0); + } else if (!strcmp(argv[i], "--version")) { + version(); + } else if (!strcmp(argv[i], "-v")) { opt_verbose = true; atexit(PrintMemoryUsage); - continue; - } - if (!strcmp(argv[i], "-o")) { + } else if (!strcmp(argv[i], "-o")) { opt_o = argv[++i]; - continue; - } - if (!strncmp(argv[i], "-o", 2)) { + } else if (startswith(argv[i], "-o")) { opt_o = argv[i] + 2; - continue; - } - if (!strcmp(argv[i], "-S")) { + } else 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")) { + } else if (!strcmp(argv[i], "-fcommon")) { + opt_common = true; + } else if (!strcmp(argv[i], "-fno-common")) { + opt_common = false; + } else if (!strcmp(argv[i], "-fno-builtin")) { + opt_no_builtin = true; + } else if (!strcmp(argv[i], "-c")) { opt_c = true; - continue; - } - if (!strcmp(argv[i], "-E")) { + } else if (!strcmp(argv[i], "-E")) { opt_E = true; - continue; - } - if (!strncmp(argv[i], "-I", 2)) { + } else if (!strcmp(argv[i], "-A")) { + opt_A = true; + } else if (!strcmp(argv[i], "-I")) { + strarray_push(&include_paths, argv[++i]); + } else if (startswith(argv[i], "-I")) { strarray_push(&include_paths, argv[i] + 2); - continue; - } - if (!strcmp(argv[i], "-D")) { + } else if (!strcmp(argv[i], "-iquote")) { + strarray_push(&include_paths, argv[++i]); + } else if (startswith(argv[i], "-iquote")) { + strarray_push(&include_paths, argv[i] + strlen("-iquote")); + } else if (!strcmp(argv[i], "-isystem")) { + strarray_push(&include_paths, argv[++i]); + } else if (startswith(argv[i], "-isystem")) { + strarray_push(&include_paths, argv[i] + strlen("-isystem")); + } else if (!strcmp(argv[i], "-D")) { define(argv[++i]); - continue; - } - if (!strncmp(argv[i], "-D", 2)) { + } else if (startswith(argv[i], "-D")) { define(argv[i] + 2); - continue; - } - if (!strcmp(argv[i], "-U")) { + } else if (!strcmp(argv[i], "-U")) { undef_macro(argv[++i]); - continue; - } - if (!strncmp(argv[i], "-U", 2)) { + } else if (!strncmp(argv[i], "-U", 2)) { undef_macro(argv[i] + 2); - continue; - } - if (!strcmp(argv[i], "-include")) { + } else if (!strcmp(argv[i], "-include")) { strarray_push(&opt_include, argv[++i]); - continue; - } - if (!strcmp(argv[i], "-x")) { + } else if (!strcmp(argv[i], "-x")) { opt_x = parse_opt_x(argv[++i]); - continue; - } - if (!strncmp(argv[i], "-x", 2)) { + } else 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")) { + } else if (startswith(argv[i], "-Wa")) { + strarray_push_comma(&as_extra_args, argv[i]); + } else if (startswith(argv[i], "-Wl")) { + strarray_push_comma(&ld_extra_args, argv[i]); + } else if (!strcmp(argv[i], "-Xassembler")) { strarray_push(&as_extra_args, argv[++i]); - continue; - } - if (!strcmp(argv[i], "-Xlinker")) { + } else if (!strcmp(argv[i], "-Xlinker")) { strarray_push(&ld_extra_args, argv[++i]); - continue; - } - if (!strcmp(argv[i], "-s")) { + } else if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) { + strarray_push(&input_paths, argv[i]); + } else if (!strcmp(argv[i], "-s")) { strarray_push(&ld_extra_args, "-s"); - continue; - } - if (!strcmp(argv[i], "-M")) { + } else if (!strcmp(argv[i], "-M")) { opt_M = true; - continue; - } - if (!strcmp(argv[i], "-MF")) { + } else if (!strcmp(argv[i], "-MF")) { opt_MF = argv[++i]; - continue; - } - if (!strcmp(argv[i], "-MP")) { + } else if (!strcmp(argv[i], "-MP")) { opt_MP = true; - continue; - } - if (!strcmp(argv[i], "-MT")) { - if (opt_MT == NULL) + } else if (!strcmp(argv[i], "-MT")) { + if (!opt_MT) { opt_MT = argv[++i]; - else + } else { opt_MT = xasprintf("%s %s", opt_MT, argv[++i]); - continue; - } - if (!strcmp(argv[i], "-MD")) { + } + } else if (!strcmp(argv[i], "-MD")) { opt_MD = true; - continue; - } - if (!strcmp(argv[i], "-MQ")) { - if (opt_MT == NULL) + } else if (!strcmp(argv[i], "-MQ")) { + if (!opt_MT) { opt_MT = quote_makefile(argv[++i]); - else + } else { opt_MT = xasprintf("%s %s", opt_MT, quote_makefile(argv[++i])); - continue; - } - if (!strcmp(argv[i], "-MMD")) { + } + } else if (!strcmp(argv[i], "-MMD")) { opt_MD = opt_MMD = true; - continue; - } - if (!strcmp(argv[i], "-fpie") || !strcmp(argv[i], "-fpic") || - !strcmp(argv[i], "-fPIC")) { - opt_fpic = true; - continue; - } - if (!strcmp(argv[i], "-pg")) { + } else if (!strcmp(argv[i], "-fpie") || !strcmp(argv[i], "-fpic") || + !strcmp(argv[i], "-fPIC")) { + opt_pic = true; + } else 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")) { + } else if (!strcmp(argv[i], "-mfentry")) { + opt_fentry = true; + } else if (!strcmp(argv[i], "-ffunction-sections")) { + opt_function_sections = true; + } else if (!strcmp(argv[i], "-fdata-sections")) { + opt_data_sections = true; + } else if (!strcmp(argv[i], "-mrecord-mcount")) { + opt_record_mcount = true; + } else if (!strcmp(argv[i], "-mnop-mcount")) { + opt_nop_mcount = true; + } else if (!strcmp(argv[i], "-msse3")) { + opt_sse3 = true; + } else if (!strcmp(argv[i], "-msse4") || !strcmp(argv[i], "-msse4.2") || + !strcmp(argv[i], "-msse4.1")) { + opt_sse4 = true; + } else if (!strcmp(argv[i], "-mpopcnt")) { + opt_popcnt = true; + } else if (!strcmp(argv[i], "-cc1-input")) { base_file = argv[++i]; - continue; - } - if (!strcmp(argv[i], "-cc1-output")) { + } else if (!strcmp(argv[i], "-cc1-output")) { output_file = argv[++i]; - continue; - } - if (!strcmp(argv[i], "-idirafter")) { + } else if (!strcmp(argv[i], "-idirafter")) { strarray_push(&idirafter, argv[i++]); - continue; - } - if (!strcmp(argv[i], "-static")) { + } else if (!strcmp(argv[i], "-static")) { opt_static = true; strarray_push(&ld_extra_args, "-static"); - continue; - } - if (!strcmp(argv[i], "-shared")) { - fprintf(stderr, "error: -shared not supported\n"); - exit(1); - } - if (!strcmp(argv[i], "-L")) { + } else if (!strcmp(argv[i], "-shared")) { + error("-shared not supported"); + } else 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)) { + } else if (startswith(argv[i], "-L")) { strarray_push(&ld_extra_args, "-L"); strarray_push(&ld_extra_args, argv[i] + 2); - continue; + } else { + if (argv[i][0] == '-' && argv[i][1]) { + /* compiler should not whine about the flags race */ + if (opt_verbose) { + fprintf(stderr, "unknown argument: %s\n", argv[i]); + } + } else { + strarray_push(&input_paths, argv[i]); + } } -#if 0 - if (!strcmp(argv[i], "-hashmap-test")) { - hashmap_test(); - exit(0); - } -#endif - // These options are ignored for now. - 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")) { - 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++) + for (int i = 0; i < idirafter.len; i++) { strarray_push(&include_paths, idirafter.data[i]); - if (input_paths.len == 0) error("no input files"); + } + if (!input_paths.len) { + error("no input files"); + } // -E implies that the input is the C macro language. if (opt_E) opt_x = FILE_C; } @@ -439,13 +393,36 @@ static void run_cc1(int argc, char **argv, char *input, char *output) { run_subprocess(args); } +static void print_token(FILE *out, Token *tok) { + switch (tok->kind) { + case TK_STR: + switch (tok->ty->base->size) { + case 1: + fprintf(out, "%`'.*s", tok->ty->array_len - 1, tok->str); + break; + case 2: + fprintf(out, "%`'.*hs", tok->ty->array_len - 1, tok->str); + break; + case 4: + fprintf(out, "%`'.*ls", tok->ty->array_len - 1, tok->str); + break; + default: + UNREACHABLE(); + } + break; + default: + fprintf(out, "%.*s", tok->len, tok->loc); + break; + } +} + 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"); if (tok->has_space && !tok->at_bol) fprintf(out, " "); - fprintf(out, "%.*s", tok->len, tok->loc); + print_token(out, tok); line++; } fprintf(out, "\n"); @@ -547,7 +524,10 @@ static void cc1(void) { return; } Obj *prog = parse(tok); - // Traverse the AST to emit assembly. + if (opt_A) { + print_ast(stdout, prog); + return; + } FILE *out = open_file(output_file); codegen(prog, out); fclose(out); @@ -582,7 +562,7 @@ static void run_linker(StringArray *inputs, char *output) { strarray_push(&arr, "elf_x86_64"); strarray_push(&arr, "-z"); strarray_push(&arr, "max-page-size=0x1000"); - strarray_push(&arr, "-mnostdlib"); + strarray_push(&arr, "-nostdlib"); strarray_push(&arr, "--gc-sections"); strarray_push(&arr, "--build-id=none"); strarray_push(&arr, "--no-dynamic-linker"); @@ -611,8 +591,9 @@ int main(int argc, char **argv) { cc1(); return 0; } - if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E)) + 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]; @@ -650,7 +631,7 @@ int main(int argc, char **argv) { } continue; } - assert(type == FILE_C); + assert(type == FILE_C || type == FILE_ASM_CPP); // Just preprocess if (opt_E || opt_M) { run_cc1(argc, argv, input, NULL); diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index a34bd8c3..916af0c4 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -114,7 +114,7 @@ void warn_tok(Token *, char *, ...) File **get_input_files(void); File *new_file(char *, int, char *); -Token *skip(Token *, char *); +Token *skip(Token *, char); Token *tokenize(File *); Token *tokenize_file(char *); Token *tokenize_string_literal(Token *, Type *); @@ -269,10 +269,10 @@ typedef enum { ND_MUL, // * ND_DIV, // / ND_NEG, // unary - - ND_MOD, // % - ND_BITAND, // & - ND_BITOR, // | - ND_BITXOR, // ^ + ND_REM, // % + ND_BINAND, // & + ND_BINOR, // | + ND_BINXOR, // ^ ND_SHL, // << ND_SHR, // >> ND_EQ, // == @@ -329,61 +329,44 @@ struct Node { Node *inc; // Block or statement expression Node *body; - 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; - }; - }; + // Function call + Type *func_ty; + Node *args; + Obj *ret_buffer; + bool pass_by_stack; + bool realign_stack; + // 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 member access + Member *member; + // Assembly + Asm *azm; + // 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; + // Arithmetic + Node *overflow; + // Numeric literal + int64_t val; + long double fval; + FpClassify *fpc; }; Node *expr(Token **, Token *); @@ -396,6 +379,12 @@ int64_t const_expr(Token **, Token *); int64_t eval(Node *); int64_t eval2(Node *, char ***); +// +// debug.c +// + +void print_ast(FILE *, Obj *); + // // type.c // @@ -560,15 +549,20 @@ void hashmap_test(void); // extern StringArray include_paths; -extern bool opt_fcommon; -extern bool opt_fpic; -extern bool opt_verbose; -extern bool opt_mpopcnt; -extern char *base_file; +extern bool opt_common; +extern bool opt_data_sections; +extern bool opt_fentry; +extern bool opt_function_sections; +extern bool opt_no_builtin; +extern bool opt_nop_mcount; extern bool opt_pg; -extern bool opt_mfentry; -extern bool opt_mnop_mcount; -extern bool opt_mrecord_mcount; +extern bool opt_pic; +extern bool opt_popcnt; +extern bool opt_record_mcount; +extern bool opt_sse3; +extern bool opt_sse4; +extern bool opt_verbose; +extern char *base_file; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index cd013f41..05e5f37a 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -55,6 +55,7 @@ THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \ LIBC_TIME \ LIBC_UNICODE \ LIBC_X \ + THIRD_PARTY_COMPILER_RT \ THIRD_PARTY_DLMALLOC \ THIRD_PARTY_GDTOA @@ -73,10 +74,10 @@ $(THIRD_PARTY_CHIBICC_A).pkg: \ 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 \ + $(APE) \ $(CRT) \ - $(APE) + o/$(MODE)/third_party/chibicc/chibicc.o \ + $(THIRD_PARTY_CHIBICC_A).pkg @$(APELINK) o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \ @@ -93,16 +94,16 @@ o/$(MODE)/third_party/chibicc/chibicc.o: \ -DAPE=\"o/$(MODE)/ape/ape.o\" \ -DLDS=\"o/$(MODE)/ape/ape.lds\" -o/$(MODE)/third_party/chibicc/chibicc.chibicc.s: \ +o/$(MODE)/third_party/chibicc/chibicc.chibicc.o: \ 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 $@ $< +o/$(MODE)/%.chibicc.o: %.c o/$(MODE)/third_party/chibicc/chibicc.com.dbg + @ACTION=CHIBICC TARGET=$@ build/do $(CHIBICC) $(CHIBICC_FLAGS) -c -o $@ $< +o/$(MODE)/%.chibicc2.o: %.c o/$(MODE)/third_party/chibicc/chibicc2.com.dbg + @ACTION=CHIBICC2 TARGET=$@ build/do $(CHIBICC2) $(CHIBICC_FLAGS) -c -o $@ $< THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x))) THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS)) @@ -115,5 +116,4 @@ $(THIRD_PARTY_CHIBICC_OBJS): $(BUILD_FILES) third_party/chibicc/chibicc.mk 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) + $(THIRD_PARTY_CHIBICC_CHECKS) diff --git a/third_party/chibicc/codegen.c b/third_party/chibicc/codegen.c index 31667814..c73be830 100644 --- a/third_party/chibicc/codegen.c +++ b/third_party/chibicc/codegen.c @@ -4,10 +4,10 @@ #define FP_MAX 8 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 char argreg8[][5] = {"%dil", "%sil", "%dl", "%cl", "%r8b", "%r9b"}; +static char argreg16[][5] = {"%di", "%si", "%dx", "%cx", "%r8w", "%r9w"}; +static char argreg32[][5] = {"%edi", "%esi", "%edx", "%ecx", "%r8d", "%r9d"}; +static char argreg64[][5] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; static Obj *current_fn; static char *lastline; @@ -21,7 +21,7 @@ void flushln(void) { lastline = NULL; } -static void emitln(char *nextline) { +static void processln(char *nextline) { if (lastline) { // unsophisticated optimization pass to reduce asm noise a little bit if ((!strcmp(lastline, "\txor\t%eax,%eax") && @@ -60,11 +60,15 @@ static void emitln(char *nextline) { } } +static void emitlin(char *nextline) { + processln(strdup(nextline)); +} + void println(char *fmt, ...) { va_list ap; char *nextline; va_start(ap, fmt); - emitln(xvasprintf(fmt, ap)); + emitlin(xvasprintf(fmt, ap)); va_end(ap); } @@ -74,18 +78,20 @@ int count(void) { } void push(void) { - println("\tpush\t%%rax"); + emitlin("\tpush\t%rax"); depth++; } void pop(char *arg) { println("\tpop\t%s", arg); depth--; + fflush(output_stream); + DCHECK_GE(depth, 0); } void push2(void) { - println("\tpush\t%%rdx"); - println("\tpush\t%%rax"); + emitlin("\tpush\t%rdx"); + emitlin("\tpush\t%rax"); depth++; depth++; } @@ -95,6 +101,7 @@ void pop2(char *a, char *b) { println("\tpop\t%s", b); depth--; depth--; + DCHECK_GE(depth, 0); } void pushreg(char *arg) { @@ -105,6 +112,7 @@ void pushreg(char *arg) { void popreg(char *arg) { println("\tpop\t%%%s", arg); depth--; + DCHECK_GE(depth, 0); } static const char *nameof(Obj *obj) { @@ -115,32 +123,43 @@ static const char *nameof(Obj *obj) { } } +static void pushx(void) { + emitlin("\tsub\t$16,%rsp"); + emitlin("\tmovdqu\t%xmm0,(%rsp)"); + depth += 2; +} + +static void popx(int reg) { + println("\tmovdqu\t(%%rsp),%%xmm%d", reg); + emitlin("\tadd\t$16,%rsp"); + depth -= 2; + DCHECK_GE(depth, 0); +} + static void pushf(Type *ty) { if (ty->vector_size == 16) { - println("\tsub\t$16,%%rsp"); - println("\tmovdqu\t%%xmm0,(%%rsp)"); - depth++; - depth++; + pushx(); } else { - println("\tpush\t%%rax"); - println("\tmovsd\t%%xmm0,(%%rsp)"); + emitlin("\tpush\t%rax"); + emitlin("\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--; + popx(reg); } else { println("\tmovsd\t(%%rsp),%%xmm%d", reg); - println("\tadd\t$8,%%rsp"); + emitlin("\tadd\t$8,%rsp"); depth--; } } +static void print_profiling_nop(void) { + emitlin("\t.byte\t0x0f,0x1f,0x44,0x00,0x00"); +} + static void print_visibility(Obj *obj) { if (obj->visibility) { if (!strcmp(obj->visibility, "hidden")) { @@ -174,7 +193,7 @@ void print_loc(int64_t file, int64_t line) { p += int64toarray_radix10(file, p); *p++ = ' '; int64toarray_radix10(line, p); - emitln(locbuf); + emitlin(locbuf); lastfile = file; lastline = line; } @@ -242,7 +261,7 @@ 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. -// asm() requires this not clobber flags or regs other than rax +// asm() wants this to not clobber flags or regs other than rax. void gen_addr(Node *node) { switch (node->kind) { case ND_VAR: @@ -256,7 +275,7 @@ void gen_addr(Node *node) { println("\tlea\t%d(%%rbp),%%rax", node->var->offset); return; } - if (opt_fpic) { + if (opt_pic) { if (node->var->is_tls) { // Dynamic thread-local variable println("\tmov\t%%fs:0,%%rax"); @@ -296,7 +315,7 @@ void gen_addr(Node *node) { // Global Offset Table using `@GOTPCREL(%rip)` notation. // Function if (node->ty->kind == TY_FUNC) { - if (!opt_fpic) { + if (!opt_pic) { println("\tmov\t$%s,%%eax", nameof(node->var)); } else if (node->var->is_definition) { println("\tlea\t%s(%%rip),%%rax", nameof(node->var)); @@ -306,12 +325,16 @@ void gen_addr(Node *node) { return; } // Global variable - if (opt_fpic) { + if (opt_pic) { println("\tlea\t%s(%%rip),%%rax", nameof(node->var)); } else { println("\tmov\t$%s,%%eax", nameof(node->var)); } return; + case ND_CAST: + gen_expr(node->lhs); + gen_cast(node->lhs->ty, node->ty); + return; case ND_DEREF: gen_expr(node->lhs); return; @@ -334,8 +357,10 @@ void gen_addr(Node *node) { case ND_VLA_PTR: println("\tlea\t%d(%%rbp),%%rax", node->var->offset); return; + default: + DCHECK(0); + error_tok(node->tok, "not an lvalue %d", node->kind); } - error_tok(node->tok, "not an lvalue"); } // Load a value from where %rax is pointing to. @@ -355,24 +380,32 @@ static void load(Type *ty) { return; case TY_FLOAT: if (ty->vector_size == 16) { - println("\tmovdqu\t(%%rax),%%xmm0"); + if (ty->align >= 16) { + emitlin("\tmovaps\t(%rax),%xmm0"); + } else { + emitlin("\tmovdqu\t(%rax),%xmm0"); + } } else { - println("\tmovss\t(%%rax),%%xmm0"); + emitlin("\tmovss\t(%rax),%xmm0"); return; } case TY_DOUBLE: if (ty->vector_size == 16) { - println("\tmovdqu\t(%%rax),%%xmm0"); + if (ty->align >= 16) { + emitlin("\tmovapd\t(%rax),%xmm0"); + } else { + emitlin("\tmovdqu\t(%rax),%xmm0"); + } } else { - println("\tmovsd\t(%%rax),%%xmm0"); + emitlin("\tmovsd\t(%rax),%xmm0"); } return; case TY_LDOUBLE: - println("\tfldt\t(%%rax)"); + emitlin("\tfldt\t(%rax)"); return; case TY_INT128: - println("\tmov\t8(%%rax),%%rdx"); - println("\tmov\t(%%rax),%%rax"); + emitlin("\tmov\t8(%rax),%rdx"); + emitlin("\tmov\t(%rax),%rax"); return; default: break; @@ -388,9 +421,9 @@ static void load(Type *ty) { } else if (ty->size == 2) { println("\t%swl\t(%%rax),%%eax", insn); } else if (ty->size == 4) { - println("\tmovslq\t(%%rax),%%rax"); + emitlin("\tmovslq\t(%rax),%rax"); } else { - println("\tmov\t(%%rax),%%rax"); + emitlin("\tmov\t(%rax),%rax"); } } @@ -399,53 +432,53 @@ static void gen_memcpy(size_t size) { case 0: break; case 1: - println("\tmov\t(%%rax),%%r8b"); - println("\tmov\t%%r8b,(%%rdi)"); + emitlin("\tmov\t(%rax),%r8b"); + emitlin("\tmov\t%r8b,(%rdi)"); break; case 2: - println("\tmov\t(%%rax),%%r8w"); - println("\tmov\t%%r8w,(%%rdi)"); + emitlin("\tmov\t(%rax),%r8w"); + emitlin("\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)"); + emitlin("\tmov\t(%rax),%r8w"); + emitlin("\tmov\t%r8w,(%rdi)"); + emitlin("\tmov\t2(%rax),%r8b"); + emitlin("\tmov\t%r8b,2(%rdi)"); break; case 4: - println("\tmov\t(%%rax),%%r8d"); - println("\tmov\t%%r8d,(%%rdi)"); + emitlin("\tmov\t(%rax),%r8d"); + emitlin("\tmov\t%r8d,(%rdi)"); break; case 5 ... 7: - println("\tmov\t(%%rax),%%r8d"); + emitlin("\tmov\t(%rax),%r8d"); println("\tmov\t%d(%%rax),%%r9d", size - 4); - println("\tmov\t%%r8d,(%%rdi)"); + emitlin("\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)"); + emitlin("\tmov\t(%rax),%r8"); + emitlin("\tmov\t%r8,(%rdi)"); break; case 9 ... 15: - println("\tmov\t(%%rax),%%r8"); + emitlin("\tmov\t(%rax),%r8"); println("\tmov\t%d(%%rax),%%r9", size - 8); - println("\tmov\t%%r8,(%%rdi)"); + emitlin("\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)"); + emitlin("\tmovdqu\t(%rax),%xmm2"); + emitlin("\tmovdqu\t%xmm2,(%rdi)"); break; case 17 ... 32: - println("\tmovdqu\t(%%rax),%%xmm2"); + emitlin("\tmovdqu\t(%rax),%xmm2"); println("\tmovdqu\t%d(%%rax),%%xmm3", size - 16); - println("\tmovdqu\t%%xmm2,(%%rdi)"); + emitlin("\tmovdqu\t%xmm2,(%rdi)"); println("\tmovdqu\t%%xmm3,%d(%%rdi)", size - 16); break; default: - println("\tmov\t%%rax,%%rsi"); + emitlin("\tmov\t%rax,%rsi"); print_mov_imm(size, "%rcx", "%ecx"); - println("\trep movsb"); + emitlin("\trep movsb"); break; } } @@ -460,61 +493,76 @@ static void store(Type *ty) { return; case TY_FLOAT: if (ty->vector_size == 16) { - println("\tmovdqu\t%%xmm0,(%%rdi)"); + if (ty->align >= 16) { + emitlin("\tmovaps\t%xmm0,(%rdi)"); + } else { + emitlin("\tmovdqu\t%xmm0,(%rdi)"); + } } else { - println("\tmovss\t%%xmm0,(%%rdi)"); + emitlin("\tmovss\t%xmm0,(%rdi)"); } return; case TY_DOUBLE: if (ty->vector_size == 16) { - println("\tmovdqu\t%%xmm0,(%%rdi)"); + if (ty->align >= 16) { + emitlin("\tmovapd\t%xmm0,(%rdi)"); + } else { + emitlin("\tmovdqu\t%xmm0,(%rdi)"); + } } else { - println("\tmovsd\t%%xmm0,(%%rdi)"); + emitlin("\tmovsd\t%xmm0,(%rdi)"); } return; case TY_LDOUBLE: - println("\tfstpt\t(%%rdi)"); + emitlin("\tfstpt\t(%rdi)"); return; case TY_INT128: - println("\tmov\t%%rax,(%%rdi)"); - println("\tmov\t%%rdx,8(%%rdi)"); + emitlin("\tmov\t%rax,(%rdi)"); + emitlin("\tmov\t%rdx,8(%rdi)"); return; } + if (ty->vector_size == 16) { + if (ty->align >= 16) { + emitlin("\tmovdqa\t%xmm0,(%rdi)"); + } else { + emitlin("\tmovdqu\t%xmm0,(%rdi)"); + } + } if (ty->size == 1) { - println("\tmov\t%%al,(%%rdi)"); + emitlin("\tmov\t%al,(%rdi)"); } else if (ty->size == 2) { - println("\tmov\t%%ax,(%%rdi)"); + emitlin("\tmov\t%ax,(%rdi)"); } else if (ty->size == 4) { - println("\tmov\t%%eax,(%%rdi)"); + emitlin("\tmov\t%eax,(%rdi)"); } else { - println("\tmov\t%%rax,(%%rdi)"); + emitlin("\tmov\t%rax,(%rdi)"); } } void cmp_zero(Type *ty) { switch (ty->kind) { case TY_FLOAT: - println("\txorps\t%%xmm1,%%xmm1"); - println("\tucomiss\t%%xmm1,%%xmm0"); + emitlin("\txorps\t%xmm1,%xmm1"); + emitlin("\tucomiss\t%xmm1,%xmm0"); return; case TY_DOUBLE: - println("\txorpd\t%%xmm1,%%xmm1"); - println("\tucomisd\t%%xmm1,%%xmm0"); + emitlin("\txorpd\t%xmm1,%xmm1"); + emitlin("\tucomisd\t%xmm1,%xmm0"); return; case TY_LDOUBLE: - println("\tfldz"); - println("\tfucomip"); - println("\tfstp\t%%st"); + emitlin("\tfldz"); + emitlin("\tfucomip"); + emitlin("\tfstp\t%st"); return; case TY_INT128: - println("mov\t%%rax,%%r11"); - println("or\t%%edx,%%r11"); + emitlin("\tmov\t%rax,%r11"); + emitlin("\tor\t%rdx,%r11"); return; } if (is_integer(ty) && ty->size <= 4) { - println("\ttest\t%%eax,%%eax"); + emitlin("\ttest\t%eax,%eax"); } else { - println("\ttest\t%%rax,%%rax"); + emitlin("\ttest\t%rax,%rax"); } } @@ -532,14 +580,19 @@ void cmp_zero(Type *ty) { // members in its byte range [lo, hi). static bool has_flonum(Type *ty, int lo, int hi, int offset) { if (ty->kind == TY_STRUCT || ty->kind == TY_UNION) { - for (Member *mem = ty->members; mem; mem = mem->next) - if (!has_flonum(mem->ty, lo, hi, offset + mem->offset)) return false; + for (Member *mem = ty->members; mem; mem = mem->next) { + 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)) + 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 || @@ -582,8 +635,8 @@ static void push_args2(Node *args, bool first_pass) { pushf(args->ty); break; case TY_LDOUBLE: - println("\tsub\t$16,%%rsp"); - println("\tfstpt\t(%%rsp)"); + emitlin("\tsub\t$16,%rsp"); + emitlin("\tfstpt\t(%rsp)"); depth += 2; break; case TY_INT128: @@ -592,6 +645,9 @@ static void push_args2(Node *args, bool first_pass) { default: push(); } + if (args->realign_stack) { + pushreg("rbx"); + } } // Load function call arguments. Arguments are already evaluated and @@ -642,8 +698,12 @@ static int push_args(Node *node) { case TY_FLOAT: case TY_DOUBLE: if (fp++ >= FP_MAX) { + if ((stack & 1) && arg->ty->vector_size == 16) { + arg->realign_stack = true; + ++stack; + } arg->pass_by_stack = true; - stack++; + ++stack; } break; case TY_LDOUBLE: @@ -651,11 +711,15 @@ static int push_args(Node *node) { stack += 2; break; case TY_INT128: - gp++; - if (gp++ >= GP_MAX) { + if (gp + 1 >= GP_MAX) { + if (stack & 1) { + arg->realign_stack = true; + ++stack; + } arg->pass_by_stack = true; - stack++; - stack++; + stack += 2; + } else { + gp += 2; } break; default: @@ -667,7 +731,7 @@ static int push_args(Node *node) { } } if ((depth + stack) % 2 == 1) { - println("\tsub\t$8,%%rsp"); + emitlin("\tsub\t$8,%rsp"); depth++; stack++; } @@ -697,7 +761,7 @@ static void copy_ret_buffer(Obj *var) { } else { for (int i = 0; i < MIN(8, ty->size); i++) { println("\tmov\t%%al,%d(%%rbp)", var->offset + i); - println("\tshr\t$8,%%rax"); + emitlin("\tshr\t$8,%rax"); } gp++; } @@ -724,21 +788,21 @@ static void copy_struct_reg(void) { /* todo(jart): wat */ Type *ty = current_fn->ty->return_ty; int gp = 0, fp = 0; - println("\tmov\t%%rax,%%rdi"); + emitlin("\tmov\t%rax,%rdi"); if (has_flonum(ty, 0, 8, 0)) { assert(ty->size == 4 || 8 <= ty->size); if (ty->size == 4) { - println("\tmovss\t(%%rdi),%%xmm0"); + emitlin("\tmovss\t(%rdi),%xmm0"); } else if (ty->size == 8) { - println("\tmovsd\t(%%rdi),%%xmm0"); + emitlin("\tmovsd\t(%rdi),%xmm0"); } else { - println("\tmovdqu\t(%%rdi),%%xmm0"); + emitlin("\tmovdqu\t(%rdi),%xmm0"); } fp++; } else { - println("\txor\t%%eax,%%eax"); + emitlin("\txor\t%eax,%eax"); for (int i = MIN(8, ty->size) - 1; i >= 0; i--) { - println("\tshl\t$8,%%rax"); + emitlin("\tshl\t$8,%rax"); println("\tmov\t%d(%%rdi),%%al", i); } gp++; @@ -776,28 +840,28 @@ static void copy_struct_mem(void) { static void builtin_alloca(void) { // Align size to 16 bytes. - println("\tadd\t$15,%%rdi"); - println("\tand\t$-16,%%rdi"); + emitlin("\tadd\t$15,%rdi"); + emitlin("\tand\t$-16,%rdi"); // Shift the temporary area by %rdi. 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\ + emitlin("\ +\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\ +\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\ +\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("\tmov\t%d(%%rbp),%%rax", current_fn->alloca_bottom->offset); - println("\tsub\t%%rdi,%%rax"); + emitlin("\tsub\t%rdi,%rax"); println("\tmov\t%%rax,%d(%%rbp)", current_fn->alloca_bottom->offset); } @@ -811,76 +875,88 @@ static void gen_comis(Node *node, const char *op, int a, int b, } else { gen_expr(node->args); } - println("\txor\t%%eax,%%eax"); + emitlin("\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"); + if (!strcmp(name, "alloca")) { + gen_expr(node->args); + emitlin("\tmov\t%rax,%rdi"); + builtin_alloca(); + return true; + } else if (!strcmp(name, "trap")) { + emitlin("\tint3"); return true; } else if (!strcmp(name, "unreachable")) { - println("\tud2"); + emitlin("\tud2"); + return true; + } else if (!strcmp(name, "frame_address")) { + if (is_const_expr(node->args) && !eval(node->args)) { + emitlin("\tmov\t%rbp,%rax"); + } else { + error_tok(node->args->tok, "must be 0"); + } return true; } else if (!strcmp(name, "ctz")) { gen_expr(node->args); - println("\tbsf\t%%eax,%%eax"); + emitlin("\tbsf\t%eax,%eax"); return true; } else if (!strcmp(name, "ctzl") || !strcmp(name, "ctzll")) { gen_expr(node->args); - println("\tbsf\t%%rax,%%rax"); + emitlin("\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"); + emitlin("\ +\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"); + emitlin("\ +\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"); + emitlin("\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"); + emitlin("\tcmovz\t%edi,%eax"); + emitlin("\tinc\t%eax"); return true; } else if (!strcmp(name, "bswap16")) { gen_expr(node->args); - println("\txchg\t%%al,%%ah"); + emitlin("\txchg\t%al,%ah"); return true; } else if (!strcmp(name, "bswap32")) { gen_expr(node->args); - println("\tbswap\t%%eax"); + emitlin("\tbswap\t%eax"); return true; } else if (!strcmp(name, "bswap64")) { gen_expr(node->args); - println("\tbswap\t%%rax"); + emitlin("\tbswap\t%rax"); return true; } else if (!strcmp(name, "popcount")) { gen_expr(node->args); - if (opt_mpopcnt) { - println("\tpopcnt\t%%eax,%%eax"); + if (opt_popcnt) { + emitlin("\tpopcnt\t%eax,%eax"); } else { - println("\tmov\t%%rax,%%rdi"); - println("\tcall\t__popcountsi2"); + emitlin("\tmov\t%eax,%edi"); + emitlin("\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"); + if (opt_popcnt) { + emitlin("\tpopcnt\t%rax,%rax"); } else { - println("\tmov\t%%rax,%%rdi"); - println("\tcall\t__popcountdi2"); + emitlin("\tmov\t%rax,%rdi"); + emitlin("\tcall\t__popcountdi2"); } return true; } else if (!strcmp(name, "memcpy")) { @@ -888,7 +964,7 @@ static bool gen_builtin_funcall(Node *node, const char *name) { gen_expr(node->args); push(); gen_expr(node->args->next); - println("\tmov\t(%%rsp),%%rdi"); + emitlin("\tmov\t(%rsp),%rdi"); gen_memcpy(eval(node->args->next->next)); pop("%rax"); return true; @@ -915,89 +991,113 @@ static bool gen_builtin_funcall(Node *node, const char *name) { gen_comis(node, "ucomisd", 0, 0, "p"); return true; } else if (!strcmp(name, "nanf")) { - println("\ -\tmov\t$0x7fc00000,%%eax\n\ -\tmovd\t%%eax,%%xmm0"); + emitlin("\ +\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"); + emitlin("\ +\tmov\t$0x7fffffffffffffff,%rax\n\ +\tmovq\t%rax,%xmm0"); return true; } else if (!strcmp(name, "nanl")) { - println("\ + emitlin("\ \tpush\t$0x7fc00000\n\ -\tflds\t(%%rsp)\n\ -\tpop\t%%rax"); +\tflds\t(%rsp)\n\ +\tpop\t%rax"); return true; } else if (!strcmp(name, "inff")) { - println("\ -\tmov\t$0x7f800000,%%eax\n\ -\tmovd\t%%eax,%%xmm0"); + emitlin("\ +\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"); + emitlin("\ +\tmov\t$0x7ff0000000000000,%rax\n\ +\tmovq\t%rax,%xmm0"); return true; } else if (!strcmp(name, "infl")) { - println("\ + emitlin("\ \tpush\t$0x7f800000\n\ -\tflds\t(%%rsp)\n\ -\tpop\t%%rax"); +\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"); + emitlin("\ +\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"); + emitlin("\ +\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"); + emitlin("\ +\tmovd\t%xmm0,%eax\n\ +\tand\t$-2147483648,%eax"); return true; } else if (!strcmp(name, "signbit")) { gen_expr(node->args); - println("\ -\tmovmskpd\t%%xmm0,%%eax\n\ -\tand\t$1,%%eax"); + emitlin("\ +\tmovmskpd\t%xmm0,%eax\n\ +\tand\t$1,%eax"); return true; } else if (!strcmp(name, "signbitl")) { gen_expr(node->args); - println("\ + emitlin("\ \tfxam\n\ -\tfnstsw\t%%ax\n\ -\tfstp\t%%st\n\ -\tand\t$0x200,%%eax"); +\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; } +static int GetSseIntSuffix(Type *ty) { + switch (ty->kind) { + case TY_CHAR: + return 'b'; + case TY_SHORT: + return 'w'; + case TY_INT: + return 'd'; + case TY_LONG: + return 'q'; + default: + UNREACHABLE(); + } +} + +static bool IsOverflowArithmetic(Node *node) { + return (node->kind == ND_ADD || node->kind == ND_SUB || + node->kind == ND_MUL || node->kind == ND_NEG) && + node->overflow; +} + +static void HandleOverflow(const char *ax) { + pop("%rdi"); + println("\tmov\t%s,(%%rdi)", ax); + emitlin("\tseto\t%al"); + emitlin("\tmovzbl\t%al,%eax"); +} + // Generate code for a given node. void gen_expr(Node *node) { char fbuf[32]; @@ -1014,7 +1114,7 @@ void gen_expr(Node *node) { } u = {node->fval}; 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"); + emitlin("\tmovq\t%rax,%xmm0"); return; } case TY_DOUBLE: { @@ -1024,7 +1124,7 @@ void gen_expr(Node *node) { } u = {node->fval}; 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"); + emitlin("\tmovq\t%rax,%xmm0"); return; } case TY_LDOUBLE: { @@ -1036,18 +1136,18 @@ void gen_expr(Node *node) { u.f80 = node->fval; 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)"); + emitlin("\tmov\t%rax,-16(%rsp)"); println("\tmov\t$%lu,%%rax", u.u64[1]); - println("\tmov\t%%rax,-8(%%rsp)"); - println("\tfldt\t-16(%%rsp)"); + emitlin("\tmov\t%rax,-8(%rsp)"); + emitlin("\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"); + emitlin("\txor\t%edx,%edx"); } else { - println("\tcqto"); + emitlin("\tcqto"); } return; default: @@ -1056,35 +1156,48 @@ void gen_expr(Node *node) { } } case ND_NEG: + if (IsOverflowArithmetic(node)) { + gen_expr(node->overflow); + push(); + } gen_expr(node->lhs); switch (node->ty->kind) { case TY_FLOAT: - println("\tmov\t$0x80000000,%%eax"); - println("\tmovq\t%%rax,%%xmm1"); + emitlin("\tmov\t$-2147483648,%eax"); + emitlin("\tmovd\t%eax,%xmm1"); if (node->ty->vector_size == 16) { - println("\tpshufd\t$0,%%xmm1"); + emitlin("\tpshufd\t$0,%xmm1"); } - println("\txorps\t%%xmm1,%%xmm0"); + emitlin("\txorps\t%xmm1,%xmm0"); return; case TY_DOUBLE: - println("\tmov\t$1,%%eax"); - println("\tror\t%%rax"); - println("\tmovq\t%%rax,%%xmm1"); + emitlin("\tmov\t$1,%eax"); + emitlin("\tror\t%rax"); + emitlin("\tmovq\t%rax,%xmm1"); if (node->ty->vector_size == 16) { - println("\tpshufd\t$0b01000100,%%xmm1"); + emitlin("\tpshufd\t$0b01000100,%xmm1"); } - println("\txorpd\t%%xmm1,%%xmm0"); + emitlin("\txorpd\t%xmm1,%xmm0"); return; case TY_LDOUBLE: - println("\tfchs"); + emitlin("\tfchs"); return; case TY_INT128: - println("\tneg\t%%rax"); - println("\tadc\t$0,%%rdx"); - println("\tneg\t%%rdx"); + emitlin("\tneg\t%rax"); + emitlin("\tadc\t$0,%rdx"); + emitlin("\tneg\t%rdx"); return; } - println("\tneg\t%%rax"); + char *ax; + if (node->lhs->ty->kind == TY_LONG || node->lhs->ty->base) { + ax = "%rax"; + } else { + ax = "%eax"; + } + println("\tneg\t%s", ax); + if (IsOverflowArithmetic(node)) { + HandleOverflow(ax); + } return; case ND_VAR: gen_addr(node); @@ -1118,19 +1231,19 @@ void gen_expr(Node *node) { if (node->lhs->kind == ND_MEMBER && node->lhs->member->is_bitfield) { // 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"); + emitlin("\tmov\t%rax,%r8"); Member *mem = node->lhs->member; - println("\tmov\t%%rax,%%rdi"); + emitlin("\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"); + emitlin("\tmov\t(%rsp),%rax"); load(mem->ty); 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"); + emitlin("\tand\t%r9,%rax"); + emitlin("\tor\t%rdi,%rax"); store(node->ty); - println("\tmov\t%%r8,%%rax"); + emitlin("\tmov\t%r8,%rax"); return; } store(node->ty); @@ -1161,7 +1274,7 @@ void gen_expr(Node *node) { println("\tmovq\t$0,%d(%%rbp)", node->var->offset); break; case 9 ... 16: - println("\txor\t%%eax,%%eax"); + emitlin("\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)); @@ -1170,8 +1283,8 @@ void gen_expr(Node *node) { // `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"); + emitlin("\txor\t%eax,%eax"); + emitlin("\trep stosb"); break; } return; @@ -1190,16 +1303,19 @@ void gen_expr(Node *node) { case ND_NOT: gen_expr(node->lhs); cmp_zero(node->lhs->ty); - println("\tsete\t%%al"); - println("\tmovzbl\t%%al,%%rax"); + emitlin("\tsete\t%al"); + emitlin("\tmovzbl\t%al,%rax"); return; case ND_BITNOT: gen_expr(node->lhs); if (node->lhs->ty->kind == TY_INT128) { - println("\tnot\t%%rax"); - println("\tnot\t%%rdx"); + emitlin("\tnot\t%rax"); + emitlin("\tnot\t%rdx"); + } else if (node->lhs->ty->vector_size == 16) { + emitlin("\tpcmpeqd\t%xmm1,%xmm1"); + emitlin("\tpxor\t%xmm1,%xmm0"); } else { - println("\tnot\t%%rax"); + emitlin("\tnot\t%rax"); } return; case ND_LOGAND: { @@ -1210,10 +1326,10 @@ void gen_expr(Node *node) { gen_expr(node->rhs); cmp_zero(node->rhs->ty); println("\tje\t.L.false.%d", c); - println("\tmov\t$1,%%eax"); + emitlin("\tmov\t$1,%eax"); println("\tjmp\t.L.end.%d", c); println(".L.false.%d:", c); - println("\txor\t%%eax,%%eax"); + emitlin("\txor\t%eax,%eax"); println(".L.end.%d:", c); return; } @@ -1225,33 +1341,32 @@ void gen_expr(Node *node) { gen_expr(node->rhs); cmp_zero(node->rhs->ty); println("\tjne\t.L.true.%d", c); - println("\txor\t%%eax,%%eax"); + emitlin("\txor\t%eax,%eax"); println("\tjmp\t.L.end.%d", c); println(".L.true.%d:", c); - println("\tmov\t$1,%%eax"); + emitlin("\tmov\t$1,%eax"); println(".L.end.%d:", c); return; } case ND_FUNCALL: { 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_")) { + if (startswith(nameof(node->lhs->var), "__builtin_")) { funcname = nameof(node->lhs->var) + 10; if (gen_builtin_funcall(node, funcname)) { return; } + } else if (!opt_no_builtin) { + if (gen_builtin_funcall(node, nameof(node->lhs->var))) { + return; + } } } int stack_args = push_args(node); 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) { + if (!opt_pic || node->lhs->var->is_definition) { funcname = nameof(node->lhs->var); } else { funcname = xasprintf("%s@gotpcrel(%%rip)", nameof(node->lhs->var)); @@ -1276,10 +1391,11 @@ void gen_expr(Node *node) { bool fp1 = has_flonum1(ty); bool fp2 = has_flonum2(ty); if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) { - if (fp1) + if (fp1) { popf(ty, fp++); - else + } else { pop(argreg64[gp++]); + } if (ty->size > 8) { if (fp2) { popf(ty, fp++); @@ -1291,7 +1407,9 @@ void gen_expr(Node *node) { break; case TY_FLOAT: case TY_DOUBLE: - if (fp < FP_MAX) popf(ty, fp++); + if (fp < FP_MAX) { + popf(ty, fp++); + } break; case TY_LDOUBLE: break; @@ -1316,11 +1434,11 @@ void gen_expr(Node *node) { println("\tcall\t%s", funcname); } else { if (!node->lhs->ty->is_variadic) { - println("\tcall\t*%%rax"); + emitlin("\tcall\t*%rax"); } else { - println("\tmov\t%%rax,%%r10"); + emitlin("\tmov\t%rax,%r10"); print_mov_imm(fp, "%rax", "%eax"); - println("\tcall\t*%%r10"); + emitlin("\tcall\t*%r10"); } } if (stack_args) { @@ -1332,20 +1450,20 @@ void gen_expr(Node *node) { // respectively. We clear the upper bits here. switch (node->ty->kind) { case TY_BOOL: - println("\tmovzbl\t%%al,%%eax"); + emitlin("\tmovzbl\t%al,%eax"); return; case TY_CHAR: if (node->ty->is_unsigned) { - println("\tmovzbl\t%%al,%%eax"); + emitlin("\tmovzbl\t%al,%eax"); } else { - println("\tmovsbl\t%%al,%%eax"); + emitlin("\tmovsbl\t%al,%eax"); } return; case TY_SHORT: if (node->ty->is_unsigned) { - println("\tmovzwl\t%%ax,%%eax"); + emitlin("\tmovzwl\t%ax,%eax"); } else { - println("\tcwtl"); + emitlin("\tcwtl"); } return; } @@ -1358,7 +1476,7 @@ void gen_expr(Node *node) { return; } case ND_LABEL_VAL: - if (opt_fpic) { + if (opt_pic) { println("\tlea\t%s(%%rip),%%rax", node->unique_label); } else { println("\tmov\t$%s,%%eax", node->unique_label); @@ -1370,17 +1488,17 @@ void gen_expr(Node *node) { gen_expr(node->cas_new); push(); gen_expr(node->cas_old); - println("\tmov\t%%rax,%%r8"); + emitlin("\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("\tlock cmpxchg %s,(%%rdi)", reg_dx(sz)); - println("\tsete\t%%cl"); - println("\tje\t1f"); + emitlin("\tsete\t%cl"); + emitlin("\tje\t1f"); println("\tmov\t%s,(%%r8)", reg_ax(sz)); - println("1:"); - println("\tmovzbl\t%%cl,%%eax"); + emitlin("1:"); + emitlin("\tmovzbl\t%cl,%eax"); return; } case ND_EXCH: { @@ -1424,22 +1542,22 @@ void gen_expr(Node *node) { case ND_LE: println("\tucomis%c\t%%xmm0,%%xmm1", sd); if (node->kind == ND_EQ) { - println("\ -\tsete\t%%al\n\ -\tsetnp\t%%dl\n\ -\tand\t%%dl,%%al"); + emitlin("\ +\tsete\t%al\n\ +\tsetnp\t%dl\n\ +\tand\t%dl,%al"); } else if (node->kind == ND_NE) { - println("\ -\tsetne\t%%al\n\ -\tsetp\t%%dl\n\ -\tor\t%%dl,%%al"); + emitlin("\ +\tsetne\t%al\n\ +\tsetp\t%dl\n\ +\tor\t%dl,%al"); } else if (node->kind == ND_LT) { - println("\tseta\t%%al"); + emitlin("\tseta\t%al"); } else { - println("\tsetae\t%%al"); + emitlin("\tsetae\t%al"); } - println("\tand\t$1,%%al"); - println("\tmovzbl\t%%al,%%eax"); + emitlin("\tand\t$1,%al"); + emitlin("\tmovzbl\t%al,%eax"); return; } error_tok(node->tok, "invalid expression"); @@ -1449,43 +1567,52 @@ void gen_expr(Node *node) { gen_expr(node->rhs); switch (node->kind) { case ND_ADD: - println("\tfaddp"); + emitlin("\tfaddp"); return; case ND_SUB: - println("\tfsubrp"); + emitlin("\tfsubrp"); return; case ND_MUL: - println("\tfmulp"); + emitlin("\tfmulp"); return; case ND_DIV: - println("\tfdivrp"); + emitlin("\tfdivrp"); return; case ND_EQ: case ND_NE: case ND_LT: case ND_LE: - println("\tfcomip"); - println("\tfstp\t%%st"); + emitlin("\tfcomip"); + emitlin("\tfstp\t%st"); if (node->kind == ND_EQ) - println("\tsete\t%%al"); + emitlin("\tsete\t%al"); else if (node->kind == ND_NE) - println("\tsetne\t%%al"); + emitlin("\tsetne\t%al"); else if (node->kind == ND_LT) - println("\tseta\t%%al"); + emitlin("\tseta\t%al"); else - println("\tsetae\t%%al"); - println("\tmovzbl\t%%al,%%eax"); + emitlin("\tsetae\t%al"); + emitlin("\tmovzbl\t%al,%eax"); return; } error_tok(node->tok, "invalid expression"); } } - if (node->rhs->ty->kind == TY_INT128) { + if (IsOverflowArithmetic(node)) { + gen_expr(node->overflow); + push(); + } + if (node->lhs->ty->vector_size == 16) { + gen_expr(node->rhs); + pushx(); + gen_expr(node->lhs); + popx(1); + } else 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)) { + } else if (!opt_pic && is_const_expr(node->rhs)) { /* shortcut path for immediates */ char **label = NULL; uint64_t val = eval2(node->rhs, &label); @@ -1514,103 +1641,170 @@ void gen_expr(Node *node) { switch (node->kind) { case ND_ADD: if (node->lhs->ty->kind == TY_INT128) { - println("\tadd\t%%rdi,%%rax"); - println("\tadc\t%%rsi,%%rdx"); + emitlin("\tadd\t%rdi,%rax"); + emitlin("\tadc\t%rsi,%rdx"); + } else if (node->lhs->ty->vector_size == 16) { + println("\tpadd%c\t%%xmm1,%%xmm0", GetSseIntSuffix(node->lhs->ty)); } else { println("\tadd\t%s,%s", di, ax); } - return; + break; case ND_SUB: if (node->lhs->ty->kind == TY_INT128) { - println("\tsub\t%%rdi,%%rax"); - println("\tsbb\t%%rsi,%%rdx"); + emitlin("\tsub\t%rdi,%rax"); + emitlin("\tsbb\t%rsi,%rdx"); + } else if (node->lhs->ty->vector_size == 16) { + println("\tpsub%c\t%%xmm1,%%xmm0", GetSseIntSuffix(node->lhs->ty)); } else { println("\tsub\t%s,%s", di, ax); } - return; + break; case ND_MUL: 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"); + emitlin("\ +\timul\t%rdi,%rdx\n\ +\timul\t%rax,%rsi\n\ +\tadd\t%rdx,%rsi\n\ +\tmul\t%rdi\n\ +\tadd\t%rsi,%rdx"); + } else if (node->lhs->ty->vector_size == 16) { + switch (node->lhs->ty->kind) { + case TY_CHAR: + emitlin("\ +\tmovaps\t%xmm1,%xmm2\n\ +\tmovaps\t%xmm0,%xmm3\n\ +\tpunpcklbw %xmm0,%xmm3\n\ +\tpunpcklbw %xmm1,%xmm2\n\ +\tpmullw\t%xmm3,%xmm2\n\ +\tpunpckhbw %xmm0,%xmm0\n\ +\tpcmpeqd\t%xmm3,%xmm3\n\ +\tpunpckhbw %xmm1,%xmm1\n\ +\tpmullw\t%xmm0,%xmm1\n\ +\tandps\t%xmm3,%xmm2\n\ +\tmovaps\t%xmm2,%xmm0\n\ +\tandps\t%xmm3,%xmm1\n\ +\tpackuswb %xmm1,%xmm0"); + break; + case TY_SHORT: + emitlin("\tpmullw\t%xmm1,%xmm0"); + break; + case TY_INT: + if (opt_sse4) { + emitlin("\tpmulld\t%xmm1,%xmm0"); + } else { + emitlin("\ +\tmovaps\t%xmm0,%xmm2\n\ +\tpsrlq\t$32,%xmm0\n\ +\tpmuludq\t%xmm1,%xmm2\n\ +\tpsrlq\t$32,%xmm1\n\ +\tpmuludq\t%xmm1,%xmm0\n\ +\tpshufd\t$8,%xmm2,%xmm2\n\ +\tpshufd\t$8,%xmm0,%xmm1\n\ +\tpunpckldq %xmm1,%xmm2\n\ +\tmovaps\t%xmm2,%xmm0"); + } + case TY_LONG: + emitlin("\ +\tmovaps\t%xmm1,%xmm2\n\ +\tmovaps\t%xmm0,%xmm3\n\ +\tpmuludq\t%xmm1,%xmm3\n\ +\tmovaps\t%xmm2,%xmm4\n\ +\tmovaps\t%xmm0,%xmm1\n\ +\tpsrlq\t$32,%xmm4\n\ +\tpsrlq\t$32,%xmm1\n\ +\tpmuludq\t%xmm4,%xmm0\n\ +\tpmuludq\t%xmm2,%xmm1\n\ +\tpaddq\t%xmm0,%xmm1\n\ +\tpsllq\t$32,%xmm1\n\ +\tpaddq\t%xmm1,%xmm3\n\ +\tmovaps\t%xmm3,%xmm0"); + break; + default: + UNREACHABLE(); + } } else { println("\timul\t%s,%s", di, ax); } - return; + break; case ND_DIV: - case ND_MOD: + case ND_REM: if (node->lhs->ty->kind == TY_INT128) { bool skew; if ((skew = (depth & 1))) { - println("\tsub\t$8,%%rsp"); + emitlin("\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"); + emitlin("\ +\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"); + emitlin("\tcall\t__udivti3"); } else { - println("\tcall\t__divti3"); + emitlin("\tcall\t__divti3"); } } else { if (node->ty->is_unsigned) { - println("\tcall\t__umodti3"); + emitlin("\tcall\t__umodti3"); } else { - println("\tcall\t__modti3"); + emitlin("\tcall\t__modti3"); } } if (skew) { - println("\tadd\t$8,%%rsp"); + emitlin("\tadd\t$8,%rsp"); depth--; } + } else if (node->lhs->ty->vector_size == 16) { + error_tok(node->tok, "no div/rem sse instruction"); } else { if (node->ty->is_unsigned) { - println("\txor\t%%edx,%%edx"); + emitlin("\txor\t%edx,%edx"); println("\tdiv\t%s", di); } else { if (node->lhs->ty->size == 8) { - println("\tcqo"); + emitlin("\tcqo"); } else { - println("\tcdq"); + emitlin("\tcdq"); } println("\tidiv\t%s", di); } - if (node->kind == ND_MOD) { - println("\tmov\t%%rdx,%%rax"); + if (node->kind == ND_REM) { + emitlin("\tmov\t%rdx,%rax"); } } - return; - case ND_BITAND: + break; + case ND_BINAND: if (node->lhs->ty->kind == TY_INT128) { - println("\tand\t%%rdi,%%rax"); - println("\tand\t%%rsi,%%rdx"); + emitlin("\tand\t%rdi,%rax"); + emitlin("\tand\t%rsi,%rdx"); + } else if (node->lhs->ty->vector_size == 16) { + emitlin("\tpand\t%xmm1,%xmm0"); } else { println("\tand\t%s,%s", di, ax); } - return; - case ND_BITOR: + break; + case ND_BINOR: if (node->lhs->ty->kind == TY_INT128) { - println("\tor\t%%rdi,%%rax"); - println("\tor\t%%rsi,%%rdx"); + emitlin("\tor\t%rdi,%rax"); + emitlin("\tor\t%rsi,%rdx"); + } else if (node->lhs->ty->vector_size == 16) { + emitlin("\tpor\t%xmm1,%xmm0"); } else { println("\tor\t%s,%s", di, ax); } - return; - case ND_BITXOR: + break; + case ND_BINXOR: if (node->lhs->ty->kind == TY_INT128) { - println("\txor\t%%rdi,%%rax"); - println("\txor\t%%rsi,%%rdx"); + emitlin("\txor\t%rdi,%rax"); + emitlin("\txor\t%rsi,%rdx"); + } else if (node->lhs->ty->vector_size == 16) { + emitlin("\tpxor\t%xmm1,%xmm0"); } else { println("\txor\t%s,%s", di, ax); } - return; + break; case ND_EQ: case ND_NE: case ND_LT: @@ -1618,115 +1812,226 @@ void gen_expr(Node *node) { 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"); + emitlin("\ +\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"); + emitlin("\ +\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"); + emitlin("\ +\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"); + emitlin("\ +\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"); + emitlin("\ +\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"); + emitlin("\ +\tcmp\t%rax,%rdi\n\ +\tsbb\t%rdx,%rsi\n\ +\tsetge\t%al"); + } + break; + } + } else if (node->lhs->ty->vector_size == 16) { + switch (node->kind) { + case ND_EQ: + switch (node->lhs->ty->kind) { + case TY_CHAR: + case TY_SHORT: + case TY_INT: + println("\tpcmpeq%c\t%%xmm1,%%xmm0", + GetSseIntSuffix(node->lhs->ty)); + break; + default: + error_tok(node->tok, "todo sse eq"); + } + break; + case ND_NE: + switch (node->lhs->ty->kind) { + case TY_CHAR: + case TY_SHORT: + case TY_INT: + println("\tpcmpeq%c\t%%xmm1,%%xmm0", + GetSseIntSuffix(node->lhs->ty)); + emitlin("\tpcmpeqd\t%xmm1,%xmm1\n" + "\tandnps\t%xmm1,%xmm0"); + break; + default: + error_tok(node->tok, "todo sse ne"); + } + break; + case ND_LT: + if (node->lhs->ty->is_unsigned) { + switch (node->lhs->ty->kind) { + case TY_CHAR: + case TY_SHORT: + println("\tpsubus%c\t%%xmm0,%%xmm1", + GetSseIntSuffix(node->lhs->ty)); + emitlin("\tmovaps\t%xmm1,%xmm0\n" + "\txorps\t%xmm1,%xmm1"); + println("\tpcmpeq%c\t%%xmm1,%%xmm0", + GetSseIntSuffix(node->lhs->ty)); + emitlin("\tpcmpeqd\t%xmm1,%xmm1\n" + "\tandnps\t%xmm1,%xmm0"); + break; + default: + error_tok(node->tok, "todo sse ltu"); + } + } else { + switch (node->lhs->ty->kind) { + case TY_CHAR: + case TY_SHORT: + case TY_INT: + println("\tpcmpgt%c\t%%xmm0,%%xmm1", + GetSseIntSuffix(node->lhs->ty)); + emitlin("\tmovaps\t%xmm1,%xmm0"); + break; + default: + error_tok(node->tok, "todo sse lt"); + } + } + break; + case ND_LE: + if (node->lhs->ty->is_unsigned) { + switch (node->lhs->ty->kind) { + case TY_CHAR: + emitlin("\tpminub\t%xmm0,%xmm1\n" + "\tpcmpeqb\t%xmm1,%xmm0"); + break; + case TY_SHORT: + emitlin("\tpsubusw\t%xmm1,%xmm0\n" + "\txorps\t%xmm1,%xmm1\n" + "\tpcmpeqw\t%xmm1,%xmm0"); + break; + case TY_INT: + emitlin("\tmov\t$-2147483648,%eax\n" + "\tmovd\t%eax,%xmm2\n" + "\tpshufd\t$0,%xmm2"); + emitlin("\tpcmpgtd\t%xmm1,%xmm0"); + emitlin("\tpcmpeqd\t%xmm1,%xmm1\n" + "\tandnps\t%xmm1,%xmm0"); + break; + default: + error_tok(node->tok, "todo sse leu"); + } + } else { + switch (node->lhs->ty->kind) { + case TY_SHORT: + emitlin("\tpminsw\t%xmm0,%xmm1\n" + "\tpcmpeqw\t%xmm1,%xmm0"); + break; + case TY_CHAR: + case TY_INT: + println("\tpcmpgt%c\t%%xmm1,%%xmm0", + GetSseIntSuffix(node->lhs->ty)); + emitlin("\tpcmpeqd\t%xmm1,%xmm1\n" + "\tandnps\t%xmm1,%xmm0"); + break; + default: + error_tok(node->tok, "todo sse le"); + } } break; } } else { println("\tcmp\t%s,%s", di, ax); if (node->kind == ND_EQ) { - println("\tsete\t%%al"); + emitlin("\tsete\t%al"); } else if (node->kind == ND_NE) { - println("\tsetne\t%%al"); + emitlin("\tsetne\t%al"); } else if (node->kind == ND_LT) { if (node->lhs->ty->is_unsigned) { - println("\tsetb\t%%al"); + emitlin("\tsetb\t%al"); } else { - println("\tsetl\t%%al"); + emitlin("\tsetl\t%al"); } } else if (node->kind == ND_LE) { if (node->lhs->ty->is_unsigned) { - println("\tsetbe\t%%al"); + emitlin("\tsetbe\t%al"); } else { - println("\tsetle\t%%al"); + emitlin("\tsetle\t%al"); } } } - println("\tmovzbl\t%%al,%%eax"); - return; + emitlin("\tmovzbl\t%al,%eax"); + break; case ND_SHL: - println("\tmov\t%%edi,%%ecx"); + emitlin("\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"); + emitlin("\ +\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 if (node->lhs->ty->vector_size == 16) { + error_tok(node->tok, "todo sse shl"); } else { println("\tshl\t%%cl,%s", ax); } - return; + break; case ND_SHR: - println("\tmov\t%%edi,%%ecx"); + emitlin("\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"); + emitlin("\ +\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 if (node->lhs->ty->vector_size == 16) { + error_tok(node->tok, "todo sse shr"); } 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"); + emitlin("\ +\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 if (node->lhs->ty->vector_size == 16) { + error_tok(node->tok, "todo sse sar"); } else { println("\tsar\t%%cl,%s", ax); } } - return; + break; + default: + error_tok(node->tok, "invalid expression"); + } + if (IsOverflowArithmetic(node)) { + HandleOverflow(ax); } - error_tok(node->tok, "invalid expression"); } void gen_stmt(Node *node) { @@ -1806,7 +2111,7 @@ void gen_stmt(Node *node) { return; case ND_GOTO_EXPR: gen_expr(node->lhs); - println("\tjmp\t*%%rax"); + emitlin("\tjmp\t*%rax"); return; case ND_LABEL: println("%s:", node->unique_label); @@ -1908,11 +2213,12 @@ static void emit_data(Obj *prog) { int align = (var->ty->kind == TY_ARRAY && var->ty->size >= 16) ? MAX(16, var->align) : var->align; - if (opt_fcommon && var->is_tentative && !var->is_tls) { + if (opt_common && var->is_tentative && !var->is_tls) { println("\t.comm\t%s,%d,%d", nameof(var), var->ty->size, align); } else { if (var->section) { - println("\t.section %s", var->section); + println("\t.section %s,\"aw\",@%s", var->section, + var->init_data ? "progbits" : "nobits"); } else if (var->is_tls) { println("\t.section .t%s,\"awT\",@%s", var->init_data ? "progbits" : "nobits", @@ -1921,6 +2227,9 @@ static void emit_data(Obj *prog) { } else if (align <= 1 && var->is_string_literal) { println("\t.section .rodata.str1.1,\"aSM\",@progbits,1"); #endif + } else if (opt_data_sections) { + println("\tsection .%s.%s", var->init_data ? "data" : "bss", + nameof(var)); } else { println("\t.%s", var->init_data ? "data" : "bss"); } @@ -1999,9 +2308,11 @@ static void emit_text(Obj *prog) { flushln(); fputc('\n', output_stream); if (fn->section) { - println("\t.section %s", fn->section); + println("\t.section %s,\"a\",@progbits", fn->section); + } else if (opt_function_sections) { + println("\tsection .text.%s", nameof(fn)); } else { - println("\t.text"); + emitlin("\t.text"); } print_visibility(fn); print_align(fn->align); @@ -2009,14 +2320,16 @@ static void emit_text(Obj *prog) { println("%s:", nameof(fn)); current_fn = fn; // Prologue - 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)"); + emitlin("\tpush\t%rbp"); + emitlin("\tmov\t%rsp,%rbp"); + if (opt_nop_mcount) { + print_profiling_nop(); + } else if (opt_fentry) { + emitlin("\tcall\t__fentry__@gotpcrel(%rip)"); + } else if (opt_pg) { + emitlin("\tcall\tmcount@gotpcrel(%rip)"); + } else { + print_profiling_nop(); } println("\tsub\t$%d,%%rsp", fn->stack_size); println("\tmov\t%%rsp,%d(%%rbp)", fn->alloca_bottom->offset); @@ -2096,25 +2409,25 @@ static void emit_text(Obj *prog) { // returning 0, even though the behavior is undefined for the // other functions. See C11 5.1.2.2.3. if (strcmp(nameof(fn), "main") == 0) { - println("\txor\t%%eax,%%eax"); + emitlin("\txor\t%eax,%eax"); } // Epilogue println(".L.return.%s:", nameof(fn)); if (fn->is_noreturn) { - println("\tud2"); + emitlin("\tud2"); } else { - println("\tleave"); - println("\tret"); + emitlin("\tleave"); + emitlin("\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"); + emitlin("\t.section .ctors,\"aw\",@progbits"); + emitlin("\t.align\t8"); println("\t.quad\t%s", nameof(fn)); } if (fn->is_destructor) { - println("\t.section .dtors,\"aw\",@progbits"); - println("\t.align\t8"); + emitlin("\t.section .dtors,\"aw\",@progbits"); + emitlin("\t.align\t8"); println("\t.quad\t%s", nameof(fn)); } } diff --git a/third_party/chibicc/hashmap.c b/third_party/chibicc/hashmap.c index a4ddad97..8406732e 100644 --- a/third_party/chibicc/hashmap.c +++ b/third_party/chibicc/hashmap.c @@ -18,8 +18,11 @@ static uint64_t fnv_hash(char *s, int len) { static void rehash(HashMap *map) { // Compute the size of the new hashmap. int nkeys = 0; - for (int i = 0; i < map->capacity; i++) - if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) nkeys++; + for (int i = 0; i < map->capacity; i++) { + if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) { + nkeys++; + } + } size_t cap = map->capacity; while ((nkeys * 100) / cap >= 50) cap = cap * 2; // Create a new hashmap and copy all key-values. @@ -101,32 +104,3 @@ void hashmap_delete2(HashMap *map, char *key, int keylen) { HashEntry *ent = get_entry(map, key, 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, 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, xasprintf("key %d", i), (void *)(size_t)i); - for (int i = 6000; i < 7000; 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, 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, 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, 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, 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 8c912efb..11a8327b 100644 --- a/third_party/chibicc/parse.c +++ b/third_party/chibicc/parse.c @@ -126,11 +126,11 @@ static Obj *builtin_alloca; static Initializer *initializer(Token **, Token *, Type *, Type **); static Member *get_struct_member(Type *, Token *); -static Node * bitor (Token **, Token *); +static Node *binor(Token **, Token *); static Node *add(Token **, Token *); static Node *assign(Token **, Token *); -static Node *bitand(Token **, Token *); -static Node *bitxor(Token **, Token *); +static Node *binand(Token **, Token *); +static Node *binxor(Token **, Token *); static Node *cast(Token **, Token *); static Node *compound_stmt(Token **, Token *); static Node *conditional(Token **, Token *); @@ -277,8 +277,9 @@ static Initializer *new_initializer(Type *ty, bool is_flexible) { return init; } init->children = calloc(ty->array_len, sizeof(Initializer *)); - for (int i = 0; i < ty->array_len; i++) + 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) { @@ -383,15 +384,15 @@ static bool consume_attribute(Token **rest, Token *tok, char *name) { static Token *attribute_list(Token *tok, void *arg, Token *(*f)(Token *, void *)) { while (CONSUME(&tok, tok, "__attribute__")) { - tok = skip(tok, "("); - tok = skip(tok, "("); + tok = skip(tok, '('); + tok = skip(tok, '('); bool first = true; while (!CONSUME(&tok, tok, ")")) { - if (!first) tok = skip(tok, ","); + if (!first) tok = skip(tok, ','); first = false; tok = f(tok, arg); } - tok = skip(tok, ")"); + tok = skip(tok, ')'); } return tok; } @@ -408,14 +409,14 @@ static Token *type_attributes(Token *tok, void *arg) { Token *altok = tok; ty->align = const_expr(&tok, tok); if (popcnt(ty->align) != 1) error_tok(altok, "must be two power"); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } else { ty->align = 16; /* biggest alignment */ } return tok; } if (consume_attribute(&tok, tok, "vector_size")) { - tok = skip(tok, "("); + tok = skip(tok, '('); int vs = const_expr(&tok, tok); if (vs != 16) { error_tok(tok, "only vector_size 16 supported"); @@ -427,12 +428,12 @@ static Token *type_attributes(Token *tok, void *arg) { /* ty->base = ty; */ /* ty->array_len = vs / ty->size; */ } - return skip(tok, ")"); + return skip(tok, ')'); } if (consume_attribute(&tok, tok, "warn_if_not_aligned")) { - tok = skip(tok, "("); + tok = skip(tok, '('); const_expr(&tok, tok); - return skip(tok, ")"); + return skip(tok, ')'); } if (consume_attribute(&tok, tok, "deprecated") || consume_attribute(&tok, tok, "may_alias") || @@ -443,7 +444,7 @@ static Token *type_attributes(Token *tok, void *arg) { consume_attribute(&tok, tok, "alloc_align")) { if (CONSUME(&tok, tok, "(")) { const_expr(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } return tok; } @@ -465,9 +466,9 @@ static Token *thing_attributes(Token *tok, void *arg) { return tok; } if (consume_attribute(&tok, tok, "section")) { - tok = skip(tok, "("); + tok = skip(tok, '('); attr->section = ConsumeStringLiteral(&tok, tok); - return skip(tok, ")"); + return skip(tok, ')'); } if (consume_attribute(&tok, tok, "noreturn")) { attr->is_noreturn = true; @@ -478,9 +479,9 @@ static Token *thing_attributes(Token *tok, void *arg) { return tok; } if (consume_attribute(&tok, tok, "visibility")) { - tok = skip(tok, "("); + tok = skip(tok, '('); attr->visibility = ConsumeStringLiteral(&tok, tok); - return skip(tok, ")"); + return skip(tok, ')'); } if (consume_attribute(&tok, tok, "externally_visible")) { attr->is_externally_visible = true; @@ -490,7 +491,7 @@ static Token *thing_attributes(Token *tok, void *arg) { attr->is_constructor = true; if (CONSUME(&tok, tok, "(")) { const_expr(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } return tok; } @@ -498,7 +499,7 @@ static Token *thing_attributes(Token *tok, void *arg) { attr->is_destructor = true; if (CONSUME(&tok, tok, "(")) { const_expr(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } return tok; } @@ -508,22 +509,22 @@ static Token *thing_attributes(Token *tok, void *arg) { Token *altok = tok; attr->align = const_expr(&tok, tok); if (popcnt(attr->align) != 1) error_tok(altok, "must be two power"); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } else { attr->align = 16; /* biggest alignment */ } return tok; } if (consume_attribute(&tok, tok, "warn_if_not_aligned")) { - tok = skip(tok, "("); + tok = skip(tok, '('); const_expr(&tok, tok); - return skip(tok, ")"); + return skip(tok, ')'); } if (consume_attribute(&tok, tok, "error") || consume_attribute(&tok, tok, "warning")) { - tok = skip(tok, "("); + tok = skip(tok, '('); ConsumeStringLiteral(&tok, tok); - return skip(tok, ")"); + return skip(tok, ')'); } if (consume_attribute(&tok, tok, "noinline") || consume_attribute(&tok, tok, "const") || @@ -570,13 +571,13 @@ static Token *thing_attributes(Token *tok, void *arg) { for (;;) { const_expr(&tok, tok); if (CONSUME(&tok, tok, ")")) break; - tok = skip(tok, ","); + tok = skip(tok, ','); } } return tok; } if (consume_attribute(&tok, tok, "format")) { - tok = skip(tok, "("); + tok = skip(tok, '('); consume_attribute(&tok, tok, "printf"); consume_attribute(&tok, tok, "scanf"); consume_attribute(&tok, tok, "strftime"); @@ -584,16 +585,16 @@ static Token *thing_attributes(Token *tok, void *arg) { consume_attribute(&tok, tok, "gnu_printf"); consume_attribute(&tok, tok, "gnu_scanf"); consume_attribute(&tok, tok, "gnu_strftime"); - tok = skip(tok, ","); + tok = skip(tok, ','); const_expr(&tok, tok); - tok = skip(tok, ","); + tok = skip(tok, ','); const_expr(&tok, tok); - return skip(tok, ")"); + return skip(tok, ')'); } if (consume_attribute(&tok, tok, "format_arg")) { - tok = skip(tok, "("); + tok = skip(tok, '('); const_expr(&tok, tok); - return skip(tok, ")"); + return skip(tok, ')'); } error_tok(tok, "unknown function attribute"); } @@ -649,7 +650,7 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { attr->is_static = true; } else if (EQUAL(tok, "extern")) { attr->is_extern = true; - } else if (EQUAL(tok, "inline")) { + } else if (EQUAL(tok, "inline") || EQUAL(tok, "__inline")) { attr->is_inline = true; } else { attr->is_tls = true; @@ -682,14 +683,14 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { tok = tok->next; if (EQUAL(tok, "(")) { ty = typename(&tok, tok->next); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } is_atomic = true; goto Continue; } if (EQUAL(tok, "_Alignas")) { if (!attr) error_tok(tok, "_Alignas is not allowed in this context"); - tok = skip(tok->next, "("); + tok = skip(tok->next, '('); if (is_typename(tok)) { attr->align = typename(&tok, tok)->align; } else { @@ -699,13 +700,13 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { error_tok(altok, "_Alignas needs two power"); } } - tok = skip(tok, ")"); + tok = skip(tok, ')'); 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) { + EQUAL(tok, "typeof") || EQUAL(tok, "__typeof") || ty2) { if (counter) break; if (EQUAL(tok, "struct")) { ty = struct_decl(&tok, tok->next); @@ -713,7 +714,7 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { ty = union_decl(&tok, tok->next); } else if (EQUAL(tok, "enum")) { ty = enum_specifier(&tok, tok->next); - } else if (EQUAL(tok, "typeof")) { + } else if (EQUAL(tok, "typeof") || EQUAL(tok, "__typeof")) { ty = typeof_specifier(&tok, tok->next); } else { ty = ty2; @@ -831,6 +832,24 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { return ty; } +static Token *static_assertion(Token *tok) { + char *msg; + Token *start = tok; + tok = skip(tok->next, '('); + int64_t cond = const_expr(&tok, tok); + if (CONSUME(&tok, tok, ",")) { + msg = ConsumeStringLiteral(&tok, tok); + } else { + msg = "assertion failed"; + } + tok = skip(tok, ')'); + tok = skip(tok, ';'); + if (!cond) { + error_tok(start, "%s", msg); + } + return tok; +} + // func-params = ("void" | param ("," param)* ("," "...")?)? ")" // param = typespec declarator static Type *func_params(Token **rest, Token *tok, Type *ty) { @@ -842,11 +861,11 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) { Type *cur = &head; bool is_variadic = false; while (!EQUAL(tok, ")")) { - if (cur != &head) tok = skip(tok, ","); + if (cur != &head) tok = skip(tok, ','); if (EQUAL(tok, "...")) { is_variadic = true; tok = tok->next; - skip(tok, ")"); + skip(tok, ')'); break; } Type *ty2 = typespec(&tok, tok, NULL); @@ -881,7 +900,7 @@ static Type *array_dimensions(Token **rest, Token *tok, Type *ty) { return array_of(ty, -1); } Node *expr = conditional(&tok, tok); - tok = skip(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)); @@ -891,14 +910,9 @@ 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, "(")) { - 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; - } + if (EQUAL(tok, "(")) return func_params(rest, tok->next, ty); + if (EQUAL(tok, "[")) return array_dimensions(rest, tok->next, ty); + *rest = tok; return ty; } @@ -923,10 +937,9 @@ static Type *declarator(Token **rest, Token *tok, Type *ty) { Token *start = tok; Type ignore = {}; declarator(&tok, tok->next, &ignore); - tok = skip(tok, ")"); + tok = skip(tok, ')'); ty = type_suffix(rest, tok, ty); ty = declarator(&tok, start->next, ty); - /* *rest = attribute_list(tok, ty, type_attributes); */ return ty; } Token *name = NULL; @@ -938,7 +951,6 @@ static Type *declarator(Token **rest, Token *tok, Type *ty) { ty = type_suffix(rest, tok, ty); ty->name = name; ty->name_pos = name_pos; - /* *rest = attribute_list(tok, ty, type_attributes); */ return ty; } @@ -949,7 +961,7 @@ static Type *abstract_declarator(Token **rest, Token *tok, Type *ty) { Token *start = tok; Type ignore = {}; abstract_declarator(&tok, tok->next, &ignore); - tok = skip(tok, ")"); + tok = skip(tok, ')'); ty = type_suffix(rest, tok, ty); return abstract_declarator(&tok, start->next, ty); } @@ -997,12 +1009,12 @@ static Type *enum_specifier(Token **rest, Token *tok) { *rest = tok; return sc->ty; } - tok = skip(tok, "{"); + tok = skip(tok, '{'); // Read an enum-list. int i = 0; int val = 0; while (!consume_end(rest, tok)) { - if (i++ > 0) tok = skip(tok, ","); + if (i++ > 0) tok = skip(tok, ','); char *name = get_ident(tok); tok = tok->next; if (EQUAL(tok, "=")) val = const_expr(&tok, tok->next); @@ -1016,7 +1028,7 @@ static Type *enum_specifier(Token **rest, Token *tok) { // typeof-specifier = "(" (expr | typename) ")" static Type *typeof_specifier(Token **rest, Token *tok) { - tok = skip(tok, "("); + tok = skip(tok, '('); Type *ty; if (is_typename(tok)) { ty = typename(&tok, tok); @@ -1025,15 +1037,16 @@ static Type *typeof_specifier(Token **rest, Token *tok) { add_type(node); ty = node->ty; } - *rest = skip(tok, ")"); + *rest = skip(tok, ')'); return ty; } // Generate code for computing a VLA size. static Node *compute_vla_size(Type *ty, Token *tok) { Node *node = new_node(ND_NULL_EXPR, tok); - if (ty->base) + 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) { @@ -1048,8 +1061,8 @@ static Node *compute_vla_size(Type *ty, Token *tok) { } static Node *new_alloca(Node *sz) { - Node *node = - new_unary(ND_FUNCALL, new_var_node(builtin_alloca, sz->tok), sz->tok); + Node *node; + node = new_unary(ND_FUNCALL, new_var_node(builtin_alloca, sz->tok), sz->tok); node->func_ty = builtin_alloca->ty; node->ty = builtin_alloca->ty->return_ty; node->args = sz; @@ -1065,7 +1078,7 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, Node *cur = &head; int i = 0; while (!EQUAL(tok, ";")) { - if (i++ > 0) tok = skip(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"); @@ -1111,7 +1124,7 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, static Token *skip_excess_element(Token *tok) { if (EQUAL(tok, "{")) { tok = skip_excess_element(tok->next); - return skip(tok, "}"); + return skip(tok, '}'); } assign(&tok, tok); return tok; @@ -1188,13 +1201,13 @@ static void array_designator(Token **rest, Token *tok, Type *ty, int *begin, } else { *end = *begin; } - *rest = skip(tok, "]"); + *rest = skip(tok, ']'); } // struct-designator = "." ident static Member *struct_designator(Token **rest, Token *tok, Type *ty) { Token *start = tok; - tok = skip(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 @@ -1256,12 +1269,12 @@ static int count_array_init_elements(Token *tok, Type *ty) { Initializer *dummy = new_initializer(ty->base, true); int i = 0, max = 0; while (!consume_end(&tok, tok)) { - if (!first) tok = skip(tok, ","); + if (!first) tok = skip(tok, ','); first = false; if (EQUAL(tok, "[")) { i = const_expr(&tok, tok->next); if (EQUAL(tok, "...")) i = const_expr(&tok, tok->next); - tok = skip(tok, "]"); + tok = skip(tok, ']'); designation(&tok, tok, dummy); } else { initializer2(&tok, tok, dummy); @@ -1274,7 +1287,7 @@ 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, "{"); + 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); @@ -1285,7 +1298,7 @@ static void array_initializer1(Token **rest, Token *tok, Initializer *init) { *init = *new_initializer(array_of(init->ty->base, len), false); } for (int i = 0; !consume_end(rest, tok); i++) { - if (!first) tok = skip(tok, ","); + if (!first) tok = skip(tok, ','); first = false; if (EQUAL(tok, "[")) { int begin, end; @@ -1305,7 +1318,7 @@ static void array_initializer1(Token **rest, Token *tok, Initializer *init) { } } -// array-initializer2 = initializer ("," initializer)* +// array-initializer2 = initializer (',' initializer)* static void array_initializer2(Token **rest, Token *tok, Initializer *init, int i) { if (init->is_flexible) { @@ -1314,7 +1327,7 @@ static void array_initializer2(Token **rest, Token *tok, Initializer *init, } for (; i < init->ty->array_len && !is_end(tok); i++) { Token *start = tok; - if (i > 0) tok = skip(tok, ","); + if (i > 0) tok = skip(tok, ','); if (EQUAL(tok, "[") || EQUAL(tok, ".")) { *rest = start; return; @@ -1326,11 +1339,11 @@ 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, "{"); + tok = skip(tok, '{'); Member *mem = init->ty->members; bool first = true; while (!consume_end(rest, tok)) { - if (!first) tok = skip(tok, ","); + if (!first) tok = skip(tok, ','); first = false; if (EQUAL(tok, ".")) { mem = struct_designator(&tok, tok, init->ty); @@ -1352,7 +1365,7 @@ static void struct_initializer2(Token **rest, Token *tok, Initializer *init, Member *mem) { for (; mem && !is_end(tok); mem = mem->next) { Token *start = tok; - if (mem != init->ty->members) tok = skip(tok, ","); + if (mem != init->ty->members) tok = skip(tok, ','); if (EQUAL(tok, "[") || EQUAL(tok, ".")) { *rest = start; return; @@ -1370,13 +1383,13 @@ static void union_initializer(Token **rest, Token *tok, Initializer *init) { Member *mem = struct_designator(&tok, tok->next, init->ty); init->mem = mem; designation(&tok, tok, init->children[mem->idx]); - *rest = skip(tok, "}"); + *rest = skip(tok, '}'); return; } init->mem = init->ty->members; if (EQUAL(tok, "{")) { initializer2(&tok, tok->next, init->children[0]); - *rest = skip(tok, "}"); + *rest = skip(tok, '}'); } else { initializer2(rest, tok, init->children[0]); } @@ -1386,15 +1399,23 @@ static void union_initializer(Token **rest, Token *tok, Initializer *init) { // | struct-initializer | union-initializer // | assign static void initializer2(Token **rest, Token *tok, Initializer *init) { + if (EQUAL(tok, "(") && init->ty->kind == TY_ARRAY && + tok->next->kind == TK_STR) { + /* XXX: Kludge so typeof("str") s = ("str"); macros work. */ + initializer2(rest, tok->next, init); + *rest = skip(*rest, ')'); + return; + } if (init->ty->kind == TY_ARRAY && tok->kind == TK_STR) { string_initializer(rest, tok, init); return; } if (init->ty->kind == TY_ARRAY) { - if (EQUAL(tok, "{")) + if (EQUAL(tok, "{")) { array_initializer1(rest, tok, init); - else + } else { array_initializer2(rest, tok, init, 0); + } return; } if (init->ty->kind == TY_STRUCT) { @@ -1422,7 +1443,7 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) { // 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, "}"); + *rest = skip(tok, '}'); return; } init->expr = assign(rest, tok); @@ -1511,6 +1532,7 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, // x[0][1] = 7; // x[1][0] = 8; // x[1][1] = 9; +// 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}; @@ -1619,13 +1641,13 @@ 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", "__inline", "_Thread_local", "__thread", - "_Atomic", "__int128", + "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", "__typeof", "inline", "__inline", "_Thread_local", + "__thread", "_Atomic", "__int128", }; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) { hashmap_put(&map, kw[i], (void *)1); @@ -1634,6 +1656,14 @@ static bool is_typename(Token *tok) { return hashmap_get2(&map, tok->loc, tok->len) || find_typedef(tok); } +static bool is_const_expr_true(Node *node) { + if (is_flonum(node->ty)) { + return !!eval_double(node); + } else { + return eval(node); + } +} + // stmt = "return" expr? ";" // | "if" "(" expr ")" stmt ("else" stmt)? // | "switch" "(" expr ")" stmt @@ -1654,7 +1684,7 @@ static Node *stmt(Token **rest, Token *tok) { Node *node = new_node(ND_RETURN, tok); if (CONSUME(rest, tok->next, ";")) return node; Node *exp = expr(&tok, tok->next); - *rest = skip(tok, ";"); + *rest = skip(tok, ';'); add_type(exp); Type *ty = current_fn->ty->return_ty; if (ty->kind != TY_STRUCT && ty->kind != TY_UNION) @@ -1664,19 +1694,33 @@ static Node *stmt(Token **rest, Token *tok) { } if (EQUAL(tok, "if")) { Node *node = new_node(ND_IF, tok); - tok = skip(tok->next, "("); + tok = skip(tok->next, '('); node->cond = expr(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); node->then = stmt(&tok, tok); if (EQUAL(tok, "else")) node->els = stmt(&tok, tok->next); *rest = tok; + if (is_const_expr(node->cond)) { + if (is_const_expr_true(node->cond)) { /* DCE */ + return node->then; + } else if (node->els) { + return node->els; + } else { + return new_node(ND_BLOCK, node->tok); + } + } return node; } + if (EQUAL(tok, "_Static_assert")) { + Token *start = tok; + *rest = static_assertion(tok); + return new_node(ND_BLOCK, start); + } if (EQUAL(tok, "switch")) { Node *node = new_node(ND_SWITCH, tok); - tok = skip(tok->next, "("); + tok = skip(tok->next, '('); node->cond = expr(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); Node *sw = current_switch; current_switch = node; char *brk = brk_label; @@ -1698,7 +1742,7 @@ static Node *stmt(Token **rest, Token *tok) { } else { end = begin; } - tok = skip(tok, ":"); + tok = skip(tok, ':'); node->label = new_unique_name(); node->lhs = stmt(rest, tok); node->begin = begin; @@ -1710,7 +1754,7 @@ static Node *stmt(Token **rest, Token *tok) { if (EQUAL(tok, "default")) { if (!current_switch) error_tok(tok, "stray default"); Node *node = new_node(ND_CASE, tok); - tok = skip(tok->next, ":"); + tok = skip(tok->next, ':'); node->label = new_unique_name(); node->lhs = stmt(rest, tok); current_switch->default_case = node; @@ -1718,7 +1762,7 @@ static Node *stmt(Token **rest, Token *tok) { } if (EQUAL(tok, "for")) { Node *node = new_node(ND_FOR, tok); - tok = skip(tok->next, "("); + tok = skip(tok->next, '('); enter_scope(); char *brk = brk_label; char *cont = cont_label; @@ -1731,9 +1775,9 @@ static Node *stmt(Token **rest, Token *tok) { node->init = expr_stmt(&tok, tok); } if (!EQUAL(tok, ";")) node->cond = expr(&tok, tok); - tok = skip(tok, ";"); + tok = skip(tok, ';'); if (!EQUAL(tok, ")")) node->inc = expr(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); node->then = stmt(rest, tok); leave_scope(); brk_label = brk; @@ -1742,9 +1786,9 @@ static Node *stmt(Token **rest, Token *tok) { } if (EQUAL(tok, "while")) { Node *node = new_node(ND_FOR, tok); - tok = skip(tok->next, "("); + tok = skip(tok->next, '('); node->cond = expr(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); char *brk = brk_label; char *cont = cont_label; brk_label = node->brk_label = new_unique_name(); @@ -1763,11 +1807,13 @@ static Node *stmt(Token **rest, Token *tok) { node->then = stmt(&tok, tok->next); brk_label = brk; cont_label = cont; - tok = skip(tok, "while"); - tok = skip(tok, "("); + if (!EQUAL(tok, "while")) { + error_tok(tok, "expected while"); + } + tok = skip(tok->next, '('); node->cond = expr(&tok, tok); - tok = skip(tok, ")"); - *rest = skip(tok, ";"); + tok = skip(tok, ')'); + *rest = skip(tok, ';'); return node; } if (EQUAL(tok, "asm") || EQUAL(tok, "__asm__")) { @@ -1780,28 +1826,28 @@ static Node *stmt(Token **rest, Token *tok) { // [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, ";"); + *rest = skip(tok, ';'); return node; } Node *node = new_node(ND_GOTO, tok); node->label = get_ident(tok->next); node->goto_next = gotos; gotos = node; - *rest = skip(tok->next->next, ";"); + *rest = skip(tok->next->next, ';'); return node; } 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, ";"); + *rest = skip(tok->next, ';'); return node; } 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, ";"); + *rest = skip(tok->next, ';'); return node; } if (tok->kind == TK_IDENT && EQUAL(tok->next, ":")) { @@ -1859,7 +1905,7 @@ static Node *expr_stmt(Token **rest, Token *tok) { } Node *node = new_node(ND_EXPR_STMT, tok); node->lhs = expr(&tok, tok); - *rest = skip(tok, ";"); + *rest = skip(tok, ';'); return node; } @@ -1899,15 +1945,15 @@ int64_t eval2(Node *node, char ***label) { return eval(node->lhs) / eval(node->rhs); case ND_NEG: return -eval(node->lhs); - case ND_MOD: + case ND_REM: if (node->ty->is_unsigned) return (uint64_t)eval(node->lhs) % eval(node->rhs); return eval(node->lhs) % eval(node->rhs); - case ND_BITAND: + case ND_BINAND: return eval(node->lhs) & eval(node->rhs); - case ND_BITOR: + case ND_BINOR: return eval(node->lhs) | eval(node->rhs); - case ND_BITXOR: + case ND_BINXOR: return eval(node->lhs) ^ eval(node->rhs); case ND_SHL: return eval(node->lhs) << eval(node->rhs); @@ -1915,10 +1961,34 @@ int64_t eval2(Node *node, char ***label) { if (node->ty->is_unsigned && node->ty->size == 8) return (uint64_t)eval(node->lhs) >> eval(node->rhs); return eval(node->lhs) >> eval(node->rhs); - case ND_EQ: - return eval(node->lhs) == eval(node->rhs); - case ND_NE: - return eval(node->lhs) != eval(node->rhs); + case ND_EQ: { + bool lhs = is_const_expr(node->lhs); + bool rhs = is_const_expr(node->rhs); + if (rhs && node->lhs->kind == ND_VAR && node->lhs->ty->kind == TY_ARRAY && + node->lhs->var->is_string_literal) { + return eval(node->rhs) == (intptr_t)node->lhs->var->init_data; + } else if (lhs && node->rhs->kind == ND_VAR && + node->rhs->ty->kind == TY_ARRAY && + node->rhs->var->is_string_literal) { + return eval(node->lhs) == (intptr_t)node->rhs->var->init_data; + } else { + return eval(node->lhs) == eval(node->rhs); + } + } + case ND_NE: { + bool lhs = is_const_expr(node->lhs); + bool rhs = is_const_expr(node->rhs); + if (rhs && node->lhs->kind == ND_VAR && node->lhs->ty->kind == TY_ARRAY && + node->lhs->var->is_string_literal) { + return eval(node->rhs) != (intptr_t)node->lhs->var->init_data; + } else if (lhs && node->rhs->kind == ND_VAR && + node->rhs->ty->kind == TY_ARRAY && + node->rhs->var->is_string_literal) { + return eval(node->lhs) != (intptr_t)node->rhs->var->init_data; + } else { + return eval(node->lhs) != eval(node->rhs); + } + } case ND_LT: if (node->lhs->ty->is_unsigned) return (uint64_t)eval(node->lhs) < eval(node->rhs); @@ -1965,7 +2035,12 @@ int64_t eval2(Node *node, char ***label) { error_tok(node->tok, "invalid initializer"); return eval_rval(node->lhs, label) + node->member->offset; case ND_VAR: - if (!label) error_tok(node->tok, "not a compile-time constant"); + if (!label) { + if (node->ty->kind == TY_ARRAY && node->var->is_string_literal) { + return (intptr_t)node->var->init_data; + } + error_tok(node->tok, "not a compile-time constant"); + } if (node->var->ty->kind != TY_ARRAY && node->var->ty->kind != TY_FUNC) error_tok(node->tok, "invalid initializer"); *label = &node->var->name; @@ -1998,18 +2073,26 @@ bool is_const_expr(Node *node) { case ND_SUB: case ND_MUL: case ND_DIV: - case ND_BITAND: - case ND_BITOR: - case ND_BITXOR: + case ND_BINAND: + case ND_BINOR: + case ND_BINXOR: case ND_SHL: case ND_SHR: - case ND_EQ: - case ND_NE: case ND_LT: case ND_LE: case ND_LOGAND: case ND_LOGOR: return is_const_expr(node->lhs) && is_const_expr(node->rhs); + case ND_EQ: + case ND_NE: { + bool lhs = is_const_expr(node->lhs); + bool rhs = is_const_expr(node->rhs); + return (lhs && rhs) || + (rhs && node->lhs->kind == ND_VAR && + node->lhs->var->is_string_literal) || + (lhs && node->rhs->kind == ND_VAR && + node->rhs->var->is_string_literal); + } case ND_COND: if (!is_const_expr(node->cond)) return false; return is_const_expr(eval(node->cond) ? node->then : node->els); @@ -2022,6 +2105,8 @@ bool is_const_expr(Node *node) { return is_const_expr(node->lhs); case ND_NUM: return true; + case ND_VAR: + return node->var->is_string_literal; } return false; } @@ -2151,6 +2236,7 @@ static Node *to_assign(Node *binary) { return new_binary(ND_COMMA, expr1, expr2, tok); } +// @hint it's expr() without the commas // assign = conditional (assign-op assign)? // assign-op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" // | "<<=" | ">>=" @@ -2167,13 +2253,13 @@ static Node *assign(Token **rest, Token *tok) { if (EQUAL(tok, "/=")) return to_assign(new_binary(ND_DIV, node, assign(rest, tok->next), tok)); if (EQUAL(tok, "%=")) - return to_assign(new_binary(ND_MOD, node, assign(rest, tok->next), tok)); + return to_assign(new_binary(ND_REM, node, assign(rest, tok->next), tok)); if (EQUAL(tok, "&=")) - return to_assign(new_binary(ND_BITAND, node, assign(rest, tok->next), tok)); + return to_assign(new_binary(ND_BINAND, node, assign(rest, tok->next), tok)); if (EQUAL(tok, "|=")) - return to_assign(new_binary(ND_BITOR, node, assign(rest, tok->next), tok)); + return to_assign(new_binary(ND_BINOR, node, assign(rest, tok->next), tok)); if (EQUAL(tok, "^=")) - return to_assign(new_binary(ND_BITXOR, node, assign(rest, tok->next), tok)); + return to_assign(new_binary(ND_BINXOR, node, assign(rest, tok->next), tok)); if (EQUAL(tok, "<<=")) return to_assign(new_binary(ND_SHL, node, assign(rest, tok->next), tok)); if (EQUAL(tok, ">>=")) @@ -2191,20 +2277,35 @@ static Node *conditional(Token **rest, Token *tok) { } if (EQUAL(tok->next, ":")) { // [GNU] Compile `a ?: b` as `tmp = a, tmp ? tmp : b`. - add_type(cond); + Node *els = conditional(rest, tok->next->next); + if (is_const_expr(cond)) { /* DCE */ + if (is_const_expr_true(cond)) { + return cond; + } else { + return els; + } + } Obj *var = new_lvar("", cond->ty); Node *lhs = new_binary(ND_ASSIGN, new_var_node(var, tok), cond, tok); Node *rhs = new_node(ND_COND, tok); rhs->cond = new_var_node(var, tok); rhs->then = new_var_node(var, tok); - rhs->els = conditional(rest, tok->next->next); + rhs->els = els; return new_binary(ND_COMMA, lhs, rhs, tok); } Node *node = new_node(ND_COND, tok); node->cond = cond; node->then = expr(&tok, tok->next); - tok = skip(tok, ":"); + tok = skip(tok, ':'); node->els = conditional(rest, tok); + add_type(node); + if (is_const_expr(cond)) { /* DCE */ + if (is_const_expr_true(cond)) { + return new_cast(node->then, node->ty); + } else { + return new_cast(node->els, node->ty); + } + } return node; } @@ -2219,45 +2320,57 @@ static Node *logor(Token **rest, Token *tok) { return node; } -// logand = bitor ("&&" bitor)* +// logand = binor ("&&" binor)* static Node *logand(Token **rest, Token *tok) { - Node *node = bitor (&tok, tok); + Token *start = tok; + Node *node = binor(&tok, tok); while (EQUAL(tok, "&&")) { Token *start = tok; - node = new_binary(ND_LOGAND, node, bitor (&tok, tok->next), start); + node = new_binary(ND_LOGAND, node, binor(&tok, tok->next), start); } *rest = tok; +#if 0 + if (node->lhs && node->rhs) { + add_type(node->lhs); + add_type(node->rhs); + if (((is_const_expr(node->lhs) && !is_const_expr_true(node->lhs)) || + (is_const_expr(node->rhs) && !is_const_expr_true(node->rhs)))) { + node->lhs = new_cast(new_num(0, start), node->lhs->ty); /* DCE */ + node->rhs = new_cast(new_num(0, start), node->rhs->ty); + } + } +#endif return node; } -// bitor = bitxor ("|" bitxor)* -static Node * bitor (Token * *rest, Token *tok) { - Node *node = bitxor(&tok, tok); +// binor = binxor ("|" binxor)* +static Node *binor(Token **rest, Token *tok) { + Node *node = binxor(&tok, tok); while (EQUAL(tok, "|")) { Token *start = tok; - node = new_binary(ND_BITOR, node, bitxor(&tok, tok->next), start); + node = new_binary(ND_BINOR, node, binxor(&tok, tok->next), start); } *rest = tok; return node; } -// bitxor = bitand ("^" bitand)* -static Node *bitxor(Token **rest, Token *tok) { - Node *node = bitand(&tok, tok); +// binxor = binand ("^" binand)* +static Node *binxor(Token **rest, Token *tok) { + Node *node = binand(&tok, tok); while (EQUAL(tok, "^")) { Token *start = tok; - node = new_binary(ND_BITXOR, node, bitand(&tok, tok->next), start); + node = new_binary(ND_BINXOR, node, binand(&tok, tok->next), start); } *rest = tok; return node; } -// bitand = equality ("&" equality)* -static Node *bitand(Token **rest, Token *tok) { +// binand = equality ("&" equality)* +static Node *binand(Token **rest, Token *tok) { Node *node = equality(&tok, tok); while (EQUAL(tok, "&")) { Token *start = tok; - node = new_binary(ND_BITAND, node, equality(&tok, tok->next), start); + node = new_binary(ND_BINAND, node, equality(&tok, tok->next), start); } *rest = tok; return node; @@ -2387,6 +2500,31 @@ static Node *new_sub(Node *lhs, Node *rhs, Token *tok) { error_tok(tok, "invalid operands"); } +static Node *new_mul(Node *lhs, Node *rhs, Token *tok) { + return new_binary(ND_MUL, lhs, rhs, tok); +} + +static Node *builtin_overflow(Token **rest, Token *tok, + Node *new_op(Node *, Node *, Token *)) { + Token *start = tok; + tok = skip(tok->next, '('); + Node *lhs = assign(&tok, tok); + tok = skip(tok, ','); + Node *rhs = assign(&tok, tok); + tok = skip(tok, ','); + Node *dst = assign(&tok, tok); + *rest = skip(tok, ')'); + Node *node = new_op(lhs, rhs, start); + add_type(node); + add_type(dst); + if (!is_compatible(pointer_to(node->ty), dst->ty)) { + error_tok(start, "output pointer type incompatible"); + } + node->overflow = dst; + node->ty = copy_type(ty_bool); + return node; +} + // add = mul ("+" mul | "-" mul)* static Node *add(Token **rest, Token *tok) { Node *node = mul(&tok, tok); @@ -2411,7 +2549,7 @@ static Node *mul(Token **rest, Token *tok) { for (;;) { Token *start = tok; if (EQUAL(tok, "*")) { - node = new_binary(ND_MUL, node, cast(&tok, tok->next), start); + node = new_mul(node, cast(&tok, tok->next), start); continue; } if (EQUAL(tok, "/")) { @@ -2419,7 +2557,7 @@ static Node *mul(Token **rest, Token *tok) { continue; } if (EQUAL(tok, "%")) { - node = new_binary(ND_MOD, node, cast(&tok, tok->next), start); + node = new_binary(ND_REM, node, cast(&tok, tok->next), start); continue; } *rest = tok; @@ -2448,7 +2586,7 @@ static Node *cast(Token **rest, Token *tok) { if (EQUAL(tok, "(") && is_typename(tok->next)) { Token *start = tok; Type *ty = typename(&tok, tok->next); - tok = skip(tok, ")"); + tok = skip(tok, ')'); // compound literal if (EQUAL(tok, "{")) return compound_literal(rest, tok, ty, start); // type cast @@ -2523,7 +2661,7 @@ static void struct_members(Token **rest, Token *tok, Type *ty) { } // Regular struct members while (!CONSUME(&tok, tok, ";")) { - if (!first) tok = skip(tok, ","); + if (!first) tok = skip(tok, ','); first = false; Member *mem = calloc(1, sizeof(Member)); mem->ty = declarator(&tok, tok, basety); @@ -2576,7 +2714,7 @@ static Type *struct_union_decl(Token **rest, Token *tok) { push_tag_scope(tag, ty); return ty; } - tok = skip(tok, "{"); + tok = skip(tok, '{'); // Construct a struct object. struct_members(&tok, tok, ty); *rest = attribute_list(tok, ty, type_attributes); @@ -2719,7 +2857,7 @@ static Node *postfix(Token **rest, Token *tok) { // x[y] is short for *(x+y) Token *start = tok; Node *idx = expr(&tok, tok->next); - tok = skip(tok, "]"); + tok = skip(tok, ']'); node = new_unary(ND_DEREF, new_add(node, idx, start), start); continue; } @@ -2761,7 +2899,7 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) { Node head = {}; Node *cur = &head; while (!EQUAL(tok, ")")) { - if (cur != &head) tok = skip(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"); @@ -2777,7 +2915,7 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) { cur = cur->next = arg; } if (param_ty) error_tok(tok, "too few arguments"); - *rest = skip(tok, ")"); + *rest = skip(tok, ')'); Node *node = new_unary(ND_FUNCALL, fn, tok); node->func_ty = ty; node->ty = ty->return_ty; @@ -2795,7 +2933,7 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) { // | "default" ":" assign static Node *generic_selection(Token **rest, Token *tok) { Token *start = tok; - tok = skip(tok, "("); + tok = skip(tok, '('); Node *ctrl = assign(&tok, tok); add_type(ctrl); Type *t1 = ctrl->ty; @@ -2805,15 +2943,15 @@ static Node *generic_selection(Token **rest, Token *tok) { t1 = pointer_to(t1->base); Node *ret = NULL; while (!CONSUME(rest, tok, ")")) { - tok = skip(tok, ","); + tok = skip(tok, ','); if (EQUAL(tok, "default")) { - tok = skip(tok->next, ":"); + tok = skip(tok->next, ':'); Node *node = assign(&tok, tok); if (!ret) ret = node; continue; } Type *t2 = typename(&tok, tok); - tok = skip(tok, ":"); + tok = skip(tok, ':'); Node *node = assign(&tok, tok); if (is_compatible(t1, t2)) ret = node; } @@ -2842,18 +2980,18 @@ static Node *primary(Token **rest, Token *tok) { // 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, ")"); + *rest = skip(tok, ')'); return node; } if (EQUAL(tok, "(")) { Node *node = expr(&tok, tok->next); - *rest = skip(tok, ")"); + *rest = skip(tok, ')'); return node; } if (EQUAL(tok, "sizeof") && EQUAL(tok->next, "(") && is_typename(tok->next->next)) { Type *ty = typename(&tok, tok->next->next); - *rest = skip(tok, ")"); + *rest = skip(tok, ')'); if (ty->kind == TY_VLA) { if (ty->vla_size) { return new_var_node(ty->vla_size, tok); @@ -2873,7 +3011,7 @@ static Node *primary(Token **rest, Token *tok) { if (EQUAL(tok, "_Alignof") && EQUAL(tok->next, "(") && is_typename(tok->next->next)) { Type *ty = typename(&tok, tok->next->next); - *rest = skip(tok, ")"); + *rest = skip(tok, ')'); return new_ulong(ty->align, tok); } if (EQUAL(tok, "_Alignof")) { @@ -2884,90 +3022,196 @@ static Node *primary(Token **rest, Token *tok) { 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, ","); - Type *t2 = typename(&tok, tok); - *rest = skip(tok, ")"); - return new_num(is_compatible(t1, t2), start); - } - 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"); + if (tok->len > 10 && !memcmp(tok->loc, "__builtin_", 10)) { + 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); /* DCE */ } - 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); + if (EQUAL(tok, "__builtin_types_compatible_p")) { + tok = skip(tok->next, '('); + Type *t1 = typename(&tok, tok); + tok = skip(tok, ','); + Type *t2 = typename(&tok, tok); + *rest = skip(tok, ')'); + return new_num(is_compatible(t1, t2), start); + } + 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")) { + Node *node = new_node(ND_CAS, tok); + tok = skip(tok->next, '('); + node->cas_addr = assign(&tok, tok); + tok = skip(tok, ','); + node->cas_old = assign(&tok, tok); + tok = skip(tok, ','); + node->cas_new = assign(&tok, tok); + *rest = skip(tok, ')'); + return node; + } + if (EQUAL(tok, "__builtin_atomic_exchange")) { + Node *node = new_node(ND_EXCH, tok); + tok = skip(tok->next, '('); + node->lhs = assign(&tok, tok); + tok = skip(tok, ','); + node->rhs = assign(&tok, tok); + *rest = skip(tok, ')'); + return node; + } + if (EQUAL(tok, "__builtin_expect")) { /* do nothing */ + tok = skip(tok->next, '('); + Node *node = assign(&tok, tok); + tok = skip(tok, ','); + const_expr(&tok, tok); + *rest = skip(tok, ')'); + return node; + } + if (EQUAL(tok, "__builtin_assume_aligned")) { /* do nothing */ + tok = skip(tok->next, '('); + Node *node = assign(&tok, tok); + tok = skip(tok, ','); + const_expr(&tok, tok); + if (EQUAL(tok, ",")) { + const_expr(&tok, tok->next); + } + *rest = skip(tok, ')'); + return node; + } + if (EQUAL(tok, "__builtin_add_overflow")) { + return builtin_overflow(rest, tok, new_add); + } + if (EQUAL(tok, "__builtin_sub_overflow")) { + return builtin_overflow(rest, tok, new_sub); + } + if (EQUAL(tok, "__builtin_mul_overflow")) { + return builtin_overflow(rest, tok, new_mul); + } + if (EQUAL(tok, "__builtin_neg_overflow")) { + Token *start = tok; + tok = skip(tok->next, '('); + Node *lhs = assign(&tok, tok); + tok = skip(tok, ','); + Node *dst = assign(&tok, tok); + *rest = skip(tok, ')'); + Node *node = new_unary(ND_NEG, lhs, start); + add_type(node); + add_type(dst); + if (!is_compatible(pointer_to(node->ty), dst->ty)) { + error_tok(start, "output pointer type incompatible"); + } + node->overflow = dst; + node->ty = copy_type(ty_bool); + 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, '('); + Node *node = assign(&t, t); + if (is_const_expr(node)) { + *rest = skip(t, ')'); + return new_num(popcnt(eval(node)), t); } } - 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_strlen") || + (!opt_no_builtin && EQUAL(tok, "strlen"))) && + EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR && + EQUAL(tok->next->next->next, ")")) { + *rest = tok->next->next->next->next; + return new_num(strlen(tok->next->next->str), tok); } - if (EQUAL(tok, "__builtin_compare_and_swap")) { - Node *node = new_node(ND_CAS, tok); - tok = skip(tok->next, "("); - node->cas_addr = assign(&tok, tok); - tok = skip(tok, ","); - node->cas_old = assign(&tok, tok); - tok = skip(tok, ","); - node->cas_new = assign(&tok, tok); - *rest = skip(tok, ")"); - return node; - } - if (EQUAL(tok, "__builtin_atomic_exchange")) { - Node *node = new_node(ND_EXCH, tok); - tok = skip(tok->next, "("); - node->lhs = assign(&tok, tok); - tok = skip(tok, ","); - node->rhs = assign(&tok, 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, ","); + if ((EQUAL(tok, "__builtin_strpbrk") || + (!opt_no_builtin && EQUAL(tok, "strpbrk")))) { + if (EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR && + EQUAL(tok->next->next->next, ",") && + tok->next->next->next->next->kind == TK_STR && + EQUAL(tok->next->next->next->next->next, ")")) { + *rest = tok->next->next->next->next->next->next; + char *res = + strpbrk(tok->next->next->str, tok->next->next->next->next->str); + if (res) { + return new_var_node( + new_string_literal(res, array_of(ty_char, strlen(res) + 1)), tok); + } else { + return new_num(0, 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 ((EQUAL(tok, "__builtin_strstr") || + (!opt_no_builtin && EQUAL(tok, "strstr")))) { + if (EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR && + EQUAL(tok->next->next->next, ",") && + tok->next->next->next->next->kind == TK_STR && + EQUAL(tok->next->next->next->next->next, ")")) { + *rest = tok->next->next->next->next->next->next; + char *res = + strstr(tok->next->next->str, tok->next->next->next->next->str); + if (res) { + return new_var_node( + new_string_literal(res, array_of(ty_char, strlen(res) + 1)), tok); + } else { + return new_num(0, tok); + } + } + } + if ((EQUAL(tok, "__builtin_strchr") || + (!opt_no_builtin && EQUAL(tok, "strchr")))) { + if (EQUAL(tok->next, "(") && tok->next->next->kind == TK_STR && + EQUAL(tok->next->next->next, ",") && + tok->next->next->next->next->kind == TK_NUM && + EQUAL(tok->next->next->next->next->next, ")")) { + *rest = tok->next->next->next->next->next->next; + char *res = + strchr(tok->next->next->str, tok->next->next->next->next->val); + if (res) { + return new_var_node( + new_string_literal(res, array_of(ty_char, strlen(res) + 1)), tok); + } else { + return new_num(0, tok); + } } } if (tok->kind == TK_IDENT) { @@ -2976,17 +3220,19 @@ static Node *primary(Token **rest, Token *tok) { *rest = tok->next; // For "static inline" function if (sc && sc->var && sc->var->is_function) { - if (current_fn) + if (current_fn) { strarray_push(¤t_fn->refs, sc->var->name); - else + } 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) { @@ -3012,7 +3258,7 @@ static Node *primary(Token **rest, Token *tok) { static Token *parse_typedef(Token *tok, Type *basety) { bool first = true; while (!CONSUME(&tok, tok, ";")) { - if (!first) tok = skip(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"); @@ -3043,8 +3289,9 @@ static void resolve_goto_labels(void) { break; } } - if (x->unique_label == NULL) + if (x->unique_label == NULL) { error_tok(x->tok->next, "use of undeclared label"); + } } gotos = labels = NULL; } @@ -3100,9 +3347,9 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) { } fn->is_root = !(fn->is_static && fn->is_inline); if (consume_attribute(&tok, tok, "asm")) { - tok = skip(tok, "("); + tok = skip(tok, '('); fn->asmname = ConsumeStringLiteral(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } tok = attribute_list(tok, &attr, thing_attributes); if (CONSUME(&tok, tok, ";")) return tok; @@ -3119,7 +3366,7 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) { 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, "{"); + 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 = @@ -3137,17 +3384,17 @@ 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, ";")) { - if (!first) tok = skip(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, "("); + tok = skip(tok, '('); var->asmname = ConsumeStringLiteral(&tok, tok); - tok = skip(tok, ")"); + tok = skip(tok, ')'); } - /* tok = attribute_list(tok, &attr, thing_attributes); */ + 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; @@ -3195,32 +3442,32 @@ static void scan_globals(void) { globals = head.next; } -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) { +static Obj *declare0(char *name, Type *ret) { + if (!opt_no_builtin) new_gvar(name, func_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) { +static Obj *declare1(char *name, Type *ret, Type *p1) { Type *ty = func_type(ret); ty->params = copy_type(p1); - ty->params->next = copy_type(p2); + if (!opt_no_builtin) new_gvar(name, ty); return new_gvar(xstrcat("__builtin_", name), ty); } -static Obj *declare_builtin3(char *s, Type *r, Type *a, Type *b, Type *c) { +static Obj *declare2(char *name, Type *ret, Type *p1, Type *p2) { + Type *ty = func_type(ret); + ty->params = copy_type(p1); + ty->params->next = copy_type(p2); + if (!opt_no_builtin) new_gvar(name, ty); + return new_gvar(xstrcat("__builtin_", name), ty); +} + +static Obj *declare3(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); + if (!opt_no_builtin) new_gvar(s, ty); return new_gvar(xstrcat("__builtin_", s), ty); } @@ -3228,47 +3475,48 @@ 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); + declare0("trap", ty_int); + declare0("unreachable", ty_int); + declare0("inff", ty_float); + declare0("inf", ty_double); + declare0("infl", ty_ldouble); + declare1("ctz", ty_int, ty_int); + declare1("ctzl", ty_long, ty_long); + declare1("ctzll", ty_long, ty_long); + declare1("clz", ty_int, ty_int); + declare1("clzl", ty_long, ty_long); + declare1("clzll", ty_long, ty_long); + declare1("ffs", ty_int, ty_int); + declare1("ffsl", ty_int, ty_long); + declare1("ffsll", ty_int, ty_long); + declare1("bswap16", ty_ushort, ty_ushort); + declare1("bswap32", ty_uint, ty_uint); + declare1("bswap64", ty_ulong, ty_ulong); + declare1("popcount", ty_int, ty_uint); + declare1("popcountl", ty_long, ty_ulong); + declare1("popcountll", ty_long, ty_ulong); + declare1("signbitf", ty_int, ty_float); + declare1("signbit", ty_long, ty_double); + declare1("signbitl", ty_int, ty_ldouble); + declare1("nanf", ty_float, pchar); + declare1("nan", ty_double, pchar); + declare1("nanl", ty_ldouble, pchar); + declare1("isnan", ty_int, ty_double); + declare1("isinf", ty_int, ty_double); + declare1("isfinite", ty_int, ty_double); + declare2("isgreater", ty_int, ty_double, ty_double); + declare2("isgreaterequal", ty_int, ty_double, ty_double); + declare2("isless", ty_int, ty_double, ty_double); + declare2("islessequal", ty_int, ty_double, ty_double); + declare2("islessgreater", ty_int, ty_double, ty_double); + declare2("isunordered", ty_int, ty_double, ty_double); + declare2("strpbrk", pchar, pchar, pchar); + declare3("memcpy", pvoid, pvoid, pvoid, ty_ulong); + declare3("memset", pvoid, pvoid, ty_int, ty_ulong); + declare1("strlen", ty_ulong, pchar); + declare2("strchr", pchar, pchar, ty_int); + declare2("strstr", pchar, pchar, pchar); + declare1("frame_address", pvoid, ty_int); } // program = (typedef | function-definition | global-variable)* @@ -3283,6 +3531,10 @@ Obj *parse(Token *tok) { staticasms = a; continue; } + if (EQUAL(tok, "_Static_assert")) { + tok = static_assertion(tok); + continue; + } VarAttr attr = {}; tok = attribute_list(tok, &attr, thing_attributes); Type *basety = typespec(&tok, tok, &attr); diff --git a/third_party/chibicc/preprocess.c b/third_party/chibicc/preprocess.c index 44452084..a0cabf9d 100644 --- a/third_party/chibicc/preprocess.c +++ b/third_party/chibicc/preprocess.c @@ -253,7 +253,7 @@ static Token *read_const_expr(Token **rest, Token *tok) { error_tok(start, "macro name must be an identifier"); Macro *m = find_macro(tok); tok = tok->next; - if (has_paren) tok = skip(tok, ")"); + if (has_paren) tok = skip(tok, ')'); cur = cur->next = new_num_token(m ? 1 : 0, start); continue; } @@ -318,16 +318,16 @@ static MacroParam *read_macro_params(Token **rest, Token *tok, MacroParam head = {}; MacroParam *cur = &head; while (!EQUAL(tok, ")")) { - if (cur != &head) tok = skip(tok, ","); + if (cur != &head) tok = skip(tok, ','); if (EQUAL(tok, "...")) { *va_args_name = "__VA_ARGS__"; - *rest = skip(tok->next, ")"); + *rest = skip(tok->next, ')'); return head.next; } if (tok->kind != TK_IDENT) error_tok(tok, "expected an identifier"); if (EQUAL(tok->next, "...")) { *va_args_name = strndup(tok->loc, tok->len); - *rest = skip(tok->next->next, ")"); + *rest = skip(tok->next->next, ')'); return head.next; } MacroParam *m = calloc(1, sizeof(MacroParam)); @@ -386,7 +386,7 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params, MacroArg *cur = &head; MacroParam *pp = params; for (; pp; pp = pp->next) { - if (cur != &head) tok = skip(tok, ","); + if (cur != &head) tok = skip(tok, ','); cur = cur->next = read_macro_arg_one(&tok, tok, false); cur->name = pp->name; } @@ -396,25 +396,27 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params, arg = calloc(1, sizeof(MacroArg)); arg->tok = new_eof(tok); } else { - if (pp != params) tok = skip(tok, ","); + if (pp != params) tok = skip(tok, ','); arg = read_macro_arg_one(&tok, tok, true); } arg->name = va_args_name; - ; arg->is_va_args = true; cur = cur->next = arg; } else if (pp) { error_tok(start, "too many arguments"); } - skip(tok, ")"); + skip(tok, ')'); *rest = tok; return head.next; } static MacroArg *find_arg(MacroArg *args, Token *tok) { - for (MacroArg *ap = args; ap; ap = ap->next) - if (tok->len == strlen(ap->name) && !strncmp(tok->loc, ap->name, tok->len)) + for (MacroArg *ap = args; ap; ap = ap->next) { + if (tok->len == strlen(ap->name) && + !strncmp(tok->loc, ap->name, tok->len)) { return ap; + } + } return NULL; } @@ -543,7 +545,7 @@ static Token *subst(Token *tok, MacroArg *args) { if (has_varargs(args)) for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next) cur = cur->next = t; - tok = skip(tok, ")"); + tok = skip(tok, ')'); continue; } // Handle a macro token. Macro arguments are completely macro-expanded @@ -932,11 +934,11 @@ __chibicc__\000\ __cosmopolitan__\000\ 1\000\ __GNUC__\000\ -6\000\ +9\000\ __GNUC_MINOR__\000\ -6\000\ +0\000\ __GNUC_PATCHLEVEL__\000\ -6\000\ +0\000\ __NO_INLINE__\000\ 16\000\ __BIGGEST_ALIGNMENT__\000\ @@ -1289,9 +1291,13 @@ static void join_adjacent_string_literals(Token *tok) { "unsupported non-standard concatenation of string literals"); } } - if (basety->size > 1) - for (Token *t = tok1; t->kind == TK_STR; t = t->next) - if (t->ty->base->size == 1) *t = *tokenize_string_literal(t, basety); + if (basety->size > 1) { + for (Token *t = tok1; t->kind == TK_STR; t = t->next) { + if (t->ty->base->size == 1) { + *t = *tokenize_string_literal(t, basety); + } + } + } while (tok1->kind == TK_STR) tok1 = tok1->next; } // Second pass: concatenate adjacent string literals. @@ -1307,10 +1313,9 @@ static void join_adjacent_string_literals(Token *tok) { array_of(tok1->ty->base, tok1->ty->array_len + tok2->ty->array_len - 1); t->str = calloc(1, t->ty->size); t->next = tok2->next; - int i = 0; - for (int j = 0; j < tok1->ty->size - tok1->ty->base->size; i++, j++) - t->str[i] = tok1->str[j]; - for (int j = 0; j < tok2->ty->size; i++, j++) t->str[i] = tok2->str[j]; + memcpy(mempcpy(t->str, tok1->str, tok1->ty->size - tok1->ty->base->size), + tok2->str, tok2->ty->size); + t->len = strlen(t->loc); *tok1 = *t; } } diff --git a/third_party/chibicc/printast.c b/third_party/chibicc/printast.c new file mode 100644 index 00000000..6c46bb90 --- /dev/null +++ b/third_party/chibicc/printast.c @@ -0,0 +1,249 @@ +/*-*- 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 "libc/alg/arraylist2.internal.h" +#include "third_party/chibicc/chibicc.h" + +static const char kBoolStr[2][6] = {"false", "true"}; + +static const char kTypeKindStr[17][8] = { + "VOID", "BOOL", "CHAR", "SHORT", "INT", "LONG", + "INT128", "FLOAT", "DOUBLE", "LDOUBLE", "ENUM", "PTR", + "FUNC", "ARRAY", "VLA", "STRUCT", "UNION", +}; + +static const char kNodeKindStr[50][11] = { + "NULL_EXPR", "ADD", "SUB", "MUL", "DIV", "NEG", + "REM", "BINAND", "BINOR", "BINXOR", "SHL", "SHR", + "EQ", "NE", "LT", "LE", "ASSIGN", "COND", + "COMMA", "MEMBER", "ADDR", "DEREF", "NOT", "BITNOT", + "LOGAND", "LOGOR", "RETURN", "IF", "FOR", "DO", + "SWITCH", "CASE", "BLOCK", "GOTO", "GOTO_EXPR", "LABEL", + "LABEL_VAL", "FUNCALL", "EXPR_STMT", "STMT_EXPR", "VAR", "VLA_PTR", + "NUM", "CAST", "MEMZERO", "ASM", "CAS", "EXCH", + "FPCLASSIFY", +}; + +static struct Visited { + size_t i, n; + intptr_t *p; +} g_visited; + +static void PrintObj(FILE *, int, const char *, Obj *); +static void PrintNode(FILE *, int, const char *, Node *); +static void PrintType(FILE *, int, const char *, Type *); + +static bool Visit(void *ptr) { + size_t i; + intptr_t addr = (intptr_t)ptr; + for (i = 0; i < g_visited.i; ++i) { + if (addr == g_visited.p[i]) { + return false; + } + } + APPEND(&g_visited.p, &g_visited.i, &g_visited.n, &addr); + return true; +} + +static void PrintLine(FILE *f, int l, char *fmt, ...) { + int i; + va_list ap; + for (i = 0; i < l; ++i) fputc(' ', f); + va_start(ap, fmt); + vfprintf(f, fmt, ap); + va_end(ap); + fputc('\n', f); +} + +static void PrintBool(FILE *f, int l, const char *s, bool b) { + if (!b) return; + PrintLine(f, l, "%s%s", s, kBoolStr[b]); +} + +static void PrintInt(FILE *f, int l, const char *s, long x) { + if (!x) return; + PrintLine(f, l, "%s%ld", s, x); +} + +static void PrintStr(FILE *f, int l, const char *s, const char *t) { + if (!t || !*t) return; + PrintLine(f, l, "%s%`'s", s, t); +} + +static void PrintTokStr(FILE *f, int l, const char *s, Token *t) { + if (!t) return; + PrintLine(f, l, "%s%`'.*s", s, t->len, t->loc); +} + +static void PrintMember(FILE *f, int l, const char *s, Member *m) { + if (!m) return; + PrintLine(f, l, "%sMember { # %p", s, m); + PrintTokStr(f, l + 2, "name: ", m->name); + PrintInt(f, l + 2, "idx: ", m->idx); + PrintInt(f, l + 2, "align: ", m->align); + PrintInt(f, l + 2, "offset: ", m->offset); + PrintBool(f, l + 2, "is_bitfield: ", m->is_bitfield); + PrintInt(f, l + 2, "bit_offset: ", m->bit_offset); + PrintInt(f, l + 2, "bit_width: ", m->bit_width); + PrintType(f, l + 2, "ty: ", m->ty); + PrintLine(f, l, "}"); +} + +static void PrintMembers(FILE *f, int l, const char *s, Member *m) { + for (; m; m = m->next) { + PrintMember(f, l, s, m); + } +} + +static void PrintType(FILE *f, int l, const char *s, Type *t) { + for (; t; t = t->next) { + if (Visit(t)) { + PrintLine(f, l, "%sType { # %p", s, t); + PrintLine(f, l + 2, "kind: TY_%s", kTypeKindStr[t->kind]); + PrintInt(f, l + 2, "size: ", t->size); + PrintInt(f, l + 2, "align: ", t->align); + PrintBool(f, l + 2, "is_unsigned: ", t->is_unsigned); + PrintBool(f, l + 2, "is_atomic: ", t->is_atomic); + PrintType(f, l + 2, "origin: ", t->origin); + PrintType(f, l + 2, "base: ", t->base); + PrintTokStr(f, l + 2, "name: ", t->name); + PrintTokStr(f, l + 2, "name_pos: ", t->name_pos); + PrintInt(f, l + 2, "array_len: ", t->array_len); + PrintInt(f, l + 2, "vector_size: ", t->vector_size); + PrintNode(f, l + 2, "vla_len: ", t->vla_len); + PrintObj(f, l + 2, "vla_size: ", t->vla_size); + PrintMembers(f, l + 2, "members: ", t->members); + PrintBool(f, l + 2, "is_flexible: ", t->is_flexible); + PrintBool(f, l + 2, "is_packed: ", t->is_packed); + PrintBool(f, l + 2, "is_aligned: ", t->is_aligned); + PrintType(f, l + 2, "return_ty: ", t->return_ty); + PrintType(f, l + 2, "params: ", t->params); + PrintBool(f, l + 2, "is_variadic: ", t->is_variadic); + PrintLine(f, l, "}"); + } else if (t->name) { + PrintLine(f, l, "%sTY_%s %.*s # %p", s, kTypeKindStr[t->kind], + t->name->len, t->name->loc, t); + } else { + PrintLine(f, l, "%sTY_%s # %p", s, kTypeKindStr[t->kind], t); + } + } +} + +static void PrintAsm(FILE *f, int l, const char *s, Asm *a) { + int i; + if (!a) return; + PrintLine(f, l, "%sAsm { # %p", s, a); + PrintStr(f, l + 2, "str: ", a->str); + for (i = 0; i < a->n; ++i) { + PrintLine(f, l + 2, "ops: AsmOperand {"); + PrintStr(f, l + 4, "str: ", a->ops[i].str); + PrintNode(f, l + 4, "node: ", a->ops[i].node); + PrintLine(f, l + 2, "}"); + } + PrintLine(f, l, "}"); +} + +static void PrintNode(FILE *f, int l, const char *s, Node *n) { + for (; n; n = n->next) { + PrintLine(f, l, "%sNode { # %p", s, n); + PrintLine(f, l + 2, "kind: ND_%s", kNodeKindStr[n->kind]); + PrintType(f, l + 2, "ty: ", n->ty); + PrintNode(f, l + 2, "lhs: ", n->lhs); + PrintNode(f, l + 2, "rhs: ", n->rhs); + PrintNode(f, l + 2, "cond: ", n->cond); + PrintNode(f, l + 2, "then: ", n->then); + PrintNode(f, l + 2, "els: ", n->els); + PrintNode(f, l + 2, "init: ", n->init); + PrintNode(f, l + 2, "inc: ", n->inc); + PrintNode(f, l + 2, "body: ", n->body); + PrintType(f, l + 2, "func_ty: ", n->func_ty); + PrintNode(f, l + 2, "args: ", n->args); + PrintObj(f, l + 2, "ret_buffer: ", n->ret_buffer); + PrintBool(f, l + 2, "pass_by_stack: ", n->pass_by_stack); + PrintBool(f, l + 2, "realign_stack: ", n->realign_stack); + PrintNode(f, l + 2, "case_next: ", n->case_next); + PrintNode(f, l + 2, "default_case: ", n->default_case); + PrintStr(f, l + 2, "label: ", n->label); + PrintStr(f, l + 2, "unique_label: ", n->unique_label); + PrintNode(f, l + 2, "goto_next: ", n->goto_next); + PrintStr(f, l + 2, "brk_label: ", n->brk_label); + PrintStr(f, l + 2, "cont_label: ", n->cont_label); + PrintInt(f, l + 2, "begin: ", n->begin); + PrintAsm(f, l + 2, "azm: ", n->azm); + PrintInt(f, l + 2, "end: ", n->end); + PrintMember(f, l + 2, "member: ", n->member); + PrintObj(f, l + 2, "var: ", n->var); + PrintNode(f, l + 2, "overflow: ", n->overflow); + PrintInt(f, l + 2, "val: ", n->val); + if (n->fval) PrintLine(f, l + 2, "fval: %Lf", n->fval); + PrintLine(f, l, "}"); + } +} + +static void PrintRelo(FILE *f, int l, const char *s, Relocation *r) { + for (; r; r = r->next) { + PrintLine(f, l, "%sRelocation { # %p", s, r); + PrintInt(f, l + 2, "offset: ", r->offset); + if (r->label) PrintStr(f, l + 2, "label: ", *r->label); + PrintInt(f, l + 2, "addend: ", r->addend); + PrintLine(f, l, "}"); + } +} + +static void PrintObj(FILE *f, int l, const char *s, Obj *o) { + if (!o) return; + PrintLine(f, l, "%sObj { # %p", s, o); + PrintStr(f, l + 2, "name: ", o->name); + PrintType(f, l + 2, "ty: ", o->ty); + PrintBool(f, l + 2, "is_local: ", o->is_local); + PrintInt(f, l + 2, "align: ", o->align); + PrintInt(f, l + 2, "offset: ", o->offset); + PrintBool(f, l + 2, "is_function: ", o->is_function); + PrintBool(f, l + 2, "is_definition: ", o->is_definition); + PrintBool(f, l + 2, "is_static: ", o->is_static); + PrintBool(f, l + 2, "is_weak: ", o->is_weak); + PrintBool(f, l + 2, "is_externally_visible: ", o->is_externally_visible); + PrintStr(f, l + 2, "asmname: ", o->asmname); + PrintStr(f, l + 2, "section: ", o->section); + PrintStr(f, l + 2, "visibility: ", o->visibility); + PrintBool(f, l + 2, "is_tentative: ", o->is_tentative); + PrintBool(f, l + 2, "is_string_literal: ", o->is_string_literal); + PrintBool(f, l + 2, "is_tls: ", o->is_tls); + PrintStr(f, l + 2, "init_data: ", o->init_data); + PrintRelo(f, l + 2, "rel: ", o->rel); + PrintBool(f, l + 2, "is_inline: ", o->is_inline); + PrintBool(f, l + 2, "is_aligned: ", o->is_aligned); + PrintBool(f, l + 2, "is_noreturn: ", o->is_noreturn); + PrintBool(f, l + 2, "is_destructor: ", o->is_destructor); + PrintBool(f, l + 2, "is_constructor: ", o->is_constructor); + PrintInt(f, l + 2, "stack_size: ", o->stack_size); + PrintObj(f, l + 2, "params: ", o->params); + PrintNode(f, l + 2, "body: ", o->body); + PrintObj(f, l + 2, "locals: ", o->locals); + PrintObj(f, l + 2, "va_area: ", o->va_area); + PrintObj(f, l + 2, "alloca_bottom: ", o->alloca_bottom); + PrintBool(f, l + 2, "is_live: ", o->is_live); + PrintBool(f, l + 2, "is_root: ", o->is_root); + PrintLine(f, l, "}"); +} + +void print_ast(FILE *f, Obj *o) { + for (; o; o = o->next) { + PrintObj(f, 0, "", o); + } +} diff --git a/third_party/chibicc/test/alloca_test.c b/third_party/chibicc/test/alloca_test.c index d232d103..7cd91c91 100644 --- a/third_party/chibicc/test/alloca_test.c +++ b/third_party/chibicc/test/alloca_test.c @@ -11,7 +11,7 @@ int main() { char *p2 = alloca(16); char *p3 = 1 + (char *)alloca(3) + 1; p3 -= 2; - char *p4 = fn(1, alloca(16), 3); + char *p4 = fn(1, __builtin_alloca(16), 3); ASSERT(16, p1 - p2); ASSERT(16, p2 - p3); diff --git a/third_party/chibicc/test/asm_test.c b/third_party/chibicc/test/asm_test.c index bcd45bd9..b892c454 100644 --- a/third_party/chibicc/test/asm_test.c +++ b/third_party/chibicc/test/asm_test.c @@ -128,5 +128,11 @@ int main() { ASSERT(9, v1[6]); ASSERT(10, v1[7]); + { + char *p; + asm("mov\t%1,%0" : "=r"(p) : "r"("hello")); + ASSERT(1, !strcmp(p, "hello")); + } + return 0; } diff --git a/third_party/chibicc/test/assert_test.c b/third_party/chibicc/test/assert_test.c new file mode 100644 index 00000000..b9ce26fb --- /dev/null +++ b/third_party/chibicc/test/assert_test.c @@ -0,0 +1,8 @@ +#include "third_party/chibicc/test/test.h" + +_Static_assert(1); +_Static_assert(1, "hey"); + +main() { + _Static_assert(sizeof(int) == 4, "wut"); +} diff --git a/third_party/chibicc/test/attribute_test.c b/third_party/chibicc/test/attribute_test.c index af74438a..7d99d5c7 100644 --- a/third_party/chibicc/test/attribute_test.c +++ b/third_party/chibicc/test/attribute_test.c @@ -1,6 +1,21 @@ #include "third_party/chibicc/test/test.h" +void doge() __attribute__((__nonnull__)); +void cate(char *) __attribute__((__nonnull__(1))); +int var __attribute__((__section__(".data.var"))); +int ar[4] __attribute__((__section__(".data.var"))); +typedef int int2[2] __attribute__((__aligned__(64))); +typedef int int4[4] __attribute__((__warn_if_not_aligned__(16))); + +__attribute__((__nonnull__)) void doge2(); +__attribute__((__nonnull__(1))) void cate2(char *); +__attribute__((__section__(".data.var"))) int var2; +__attribute__((__section__(".data.var"))) int ar2[4]; + int main() { + int2 a; + ASSERT(64, _Alignof(int2)); + ASSERT(64, _Alignof(a)); ASSERT(5, ({ struct { char a; diff --git a/third_party/chibicc/test/builtin_test.c b/third_party/chibicc/test/builtin_test.c index 5c1a6491..b94debbc 100644 --- a/third_party/chibicc/test/builtin_test.c +++ b/third_party/chibicc/test/builtin_test.c @@ -8,10 +8,87 @@ #define FPCLASSIFY(x) \ __builtin_fpclassify(FPNAN, FPINFINITE, FPNORMAL, FPSUBNORMAL, FPZERO, x) +#define conceal(x) \ + ({ \ + typeof(x) cloak = x; \ + asm("" : "+r"(cloak)); \ + cloak; \ + }) + +struct frame { + struct frame *next; + intptr_t addr; +}; + +struct frame *frame(void) { + struct frame *myframe = __builtin_frame_address(0); + struct frame *parentframe = myframe->next; + return parentframe; +} + +void test_frame_address(void) { + ASSERT(1, __builtin_frame_address(0) == frame()); +} + void test_constant(void) { ASSERT(1, __builtin_constant_p(1)); + ASSERT(0, __builtin_constant_p(conceal(1))); ASSERT(0, __builtin_constant_p(stdin)); ASSERT(1, __builtin_constant_p(__builtin_popcount(0b10111011))); + ASSERT(1, __builtin_constant_p(__builtin_popcountll((size_t)0b10111011))); +} + +void test_ignored(void) { + ASSERT(123, __builtin_assume_aligned(123, 8)); + ASSERT(123, __builtin_assume_aligned(123, 32, 8)); + ASSERT(123, __builtin_expect(123, 0)); +} + +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)); + ASSERT(25, __builtin_clz(conceal(77))); + __builtin_clz(conceal(77)); +} + +__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)); + ASSERT(0, __builtin_ctz(conceal(77))); +} + +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)); + ASSERT(1, __builtin_ffs(conceal(77))); +} + +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)); + ASSERT(6, __builtin_popcountl(conceal(0b10111011))); +} + +void test_bswap(void) { + ASSERT(0x3412, __builtin_bswap16(0x1234)); + ASSERT(0x78563412, __builtin_bswap32(0x12345678)); + ASSERT(0xefcdab8967452301, __builtin_bswap64(0x0123456789abcdef)); + ASSERT(0xefcdab89, __builtin_bswap32(0x0123456789abcdef)); + ASSERT(0x78563412, __builtin_bswap32(conceal(0x12345678))); } void test_fpclassify(void) { @@ -38,48 +115,34 @@ void test_fpclassify(void) { 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)); +void test_strlen(void) { + ASSERT(5, strlen("hello")); + ASSERT(5, __builtin_strlen("hello")); } -__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_strchr(void) { + ASSERT(1, __builtin_strchr("hello", 'z') == NULL); + ASSERT(0, (strcmp)(__builtin_strchr("hello", 'e'), "ello")); } -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_strpbrk(void) { + ASSERT(1, __builtin_strpbrk("hello", "z") == NULL); + ASSERT(0, (strcmp)(__builtin_strpbrk("hello", "ze"), "ello")); } -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_strstr(void) { + ASSERT(1, __builtin_strstr("hello", "sup") == NULL); + ASSERT(0, (strcmp)(__builtin_strstr("hello", "ell"), "ello")); } 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 == (memcpy)(x, y + 2, 3)); + ASSERT(0, memcmp(x, z, 5)); + } { char x[5] = {4, 3, 2, 1, 0}; char y[5] = {0, 1, 2, 3, 4}; @@ -95,6 +158,109 @@ void test_memcpy(void) { ASSERT(1, x == __builtin_memcpy(x, y + 2, n)); ASSERT(0, memcmp(x, z, 5)); } + { + char x[5] = {4, 3, 2, 1, 0}; + ASSERT(1, x == __builtin_memcpy(x, x + 1, 4)); + ASSERT(0, memcmp(x, (char[5]){3, 2, 1, 0, 0}, 5)); + } +} + +void test_add_overflow(void) { + { + int z; + ASSERT(0, __builtin_add_overflow(2, 3, &z)); + ASSERT(5, z); + } + { + int x, y, z; + x = 2; + y = 3; + ASSERT(0, __builtin_add_overflow(x, y, &z)); + ASSERT(5, z); + } + { + int x, y, z; + x = 0x7fffffff; + y = 1; + ASSERT(1, __builtin_add_overflow(x, y, &z)); + ASSERT(-2147483648, z); + } + { + long x, y, z; + x = 0x7fffffff; + y = 1; + ASSERT(0, __builtin_add_overflow(x, y, &z)); + ASSERT(2147483648, z); + } +} + +void test_sub_overflow(void) { + { + int x, y, z; + x = 2; + y = 3; + ASSERT(0, __builtin_sub_overflow(x, y, &z)); + ASSERT(-1, z); + } + { + int x, y, z; + x = -2147483648; + y = 1; + ASSERT(1, __builtin_sub_overflow(x, y, &z)); + ASSERT(2147483647, z); + } + { + long x, y, z; + x = -2147483648; + y = 1; + ASSERT(0, __builtin_sub_overflow(x, y, &z)); + ASSERT(-2147483649, z); + } +} + +void test_mul_overflow(void) { + { + int x, y, z; + x = 2; + y = 3; + ASSERT(0, __builtin_mul_overflow(x, y, &z)); + ASSERT(6, z); + } + { + int x, y, z; + x = 2147483647; + y = 2; + ASSERT(1, __builtin_mul_overflow(x, y, &z)); + ASSERT(-2, z); + } + { + long x, y, z; + x = 2147483647; + y = 2; + ASSERT(0, __builtin_mul_overflow(x, y, &z)); + ASSERT(4294967294, z); + } +} + +void test_neg_overflow(void) { + { + int x, z; + x = 2; + ASSERT(0, __builtin_neg_overflow(x, &z)); + ASSERT(-2, z); + } + { + int x, z; + x = -2147483648; + ASSERT(1, __builtin_neg_overflow(x, &z)); + ASSERT(-2147483648, z); + } + { + long x, z; + x = -2147483648; + ASSERT(0, __builtin_neg_overflow(x, &z)); + ASSERT(2147483648, z); + } } void test_inf(void) { @@ -225,6 +391,7 @@ void test_offsetof(void) { int main() { test_constant(); + test_frame_address(); test_types_compatible_p(); test_clz(); test_ctz(); @@ -238,5 +405,14 @@ int main() { test_signbit(); test_memcpy(); test_offsetof(); + test_ignored(); + test_add_overflow(); + test_sub_overflow(); + test_mul_overflow(); + test_neg_overflow(); + test_strlen(); + test_strchr(); + test_strpbrk(); + test_strstr(); return 0; } diff --git a/third_party/chibicc/test/constexpr_test.c b/third_party/chibicc/test/constexpr_test.c index 580a3c3b..895b1a2c 100644 --- a/third_party/chibicc/test/constexpr_test.c +++ b/third_party/chibicc/test/constexpr_test.c @@ -176,6 +176,4 @@ int main() { ASSERT(1, g40 == 1.5); ASSERT(1, g41 == 11); - - return 0; } diff --git a/third_party/chibicc/test/dce_test.c b/third_party/chibicc/test/dce_test.c new file mode 100644 index 00000000..cab6d254 --- /dev/null +++ b/third_party/chibicc/test/dce_test.c @@ -0,0 +1,42 @@ +#include "third_party/chibicc/test/test.h" + +int x; + +int main(void) { + if (0) { + asm(".error \"the assembler shall fail\""); + } + + x = 1 ? 777 : ({ + asm(".error \"the system is down\""); + 666; + }); + ASSERT(777, x); + + x = 0; + x = 777 ?: ({ + asm(".error \"the system is down\""); + 666; + }); + + x = 0; + x = __builtin_popcount(strlen("hihi")) == 1 ? 777 : ({ + asm(".error \"the system is down\""); + 666; + }); + ASSERT(777, x); + + x = 0; + x = strpbrk("hihi", "ei") ? 777 : ({ + asm(".error \"the system is down!\""); + 666; + }); + ASSERT(777, x); + + x = 0; + x = !__builtin_strpbrk("HELLO\n", "bxdinupo") ? 777 : ({ + asm(".error \"the system is down\""); + 666; + }); + ASSERT(777, x); +} diff --git a/third_party/chibicc/test/function_test.c b/third_party/chibicc/test/function_test.c index 623be40e..222918eb 100644 --- a/third_party/chibicc/test/function_test.c +++ b/third_party/chibicc/test/function_test.c @@ -87,26 +87,8 @@ 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); -} +int add_all(int, ...); +int add_all(int, ...); double add_double(double x, double y); float add_float(float x, float y); @@ -307,7 +289,7 @@ int main() { { char buf[100]; - fmt(buf, "%d %d %s", 1, 2, "foo"); + sprintf(buf, "%d %d %s", 1, 2, "foo"); fprintf(f, "%s\n", buf); } @@ -319,7 +301,7 @@ int main() { ASSERT(0, ({ char buf[100]; - fmt(buf, "%d %d %s", 1, 2, "foo"); + sprintf(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); })); @@ -342,7 +324,7 @@ int main() { ASSERT(0, ({ char buf[100]; - fmt(buf, "%.1f", (float)3.5); + sprintf(buf, "%.1f", (float)3.5); strcmp(buf, "3.5"); })); diff --git a/third_party/chibicc/test/hog_test.c b/third_party/chibicc/test/hog_test.c new file mode 100644 index 00000000..961a27f5 --- /dev/null +++ b/third_party/chibicc/test/hog_test.c @@ -0,0 +1,4 @@ +main(void) { + void *p; + p = "hello"; +} diff --git a/third_party/chibicc/test/int128_test.c b/third_party/chibicc/test/int128_test.c index bf82245c..474b822c 100644 --- a/third_party/chibicc/test/int128_test.c +++ b/third_party/chibicc/test/int128_test.c @@ -33,7 +33,17 @@ __int128 sub128x5(__int128 a, __int128 b, __int128 c, __int128 d, __int128 e) { return a - b - c - d - e; } +__int128 sub128x6(int f, __int128 a, __int128 b, __int128 c, __int128 d, + __int128 e) { + return f - a - b - c - d - e; +} + +void lotsOfArgs(const char *file, int line, const char *func, intmax_t beg, + intmax_t end, intmax_t got, const char *gotcode, bool isfatal) { +} + void testLang128(void) { + lotsOfArgs(__FILE__, __LINE__, __FUNCTION__, 0, 0, 0, "", false); ASSERT(16, sizeof(__int128)); ASSERT(16, sizeof(unsigned __int128)); ASSERT(16, _Alignof(__int128)); @@ -64,6 +74,12 @@ void testLang128(void) { I128(0x19a0da005190a5ac, 0x755fa06484419e38), I128(0xafc6e44400b9eadd, 0x05e5afdb2e66cdb8), I128(0x5380c8796909a165, 0x47657977e6c4f381))); + ASSERT128(I128(0x1f1b109234418f84, 0x21f9f24c8535e4f0), + sub128x6(0x5ab6ba38, I128(0x0db9cd085ab6ba38, 0xdaf9c05f15896b5f), + I128(0xb6429ba7b5b38454, 0x4061839d268a0a78), + I128(0x19a0da005190a5ac, 0x755fa06484419e38), + I128(0xafc6e44400b9eadd, 0x05e5afdb2e66cdb8), + I128(0x5380c8796909a165, 0x47657977e6c4f381))); } void testCompare128(void) { @@ -8157,6 +8173,27 @@ void testNot128(void) { ASSERT128(I128(0, 0), ~x); } +void testAbi(void) { + ASSERT(0, ({ + char buf[200]; + sprintf(buf, "%d %d %d %d %032jx %032jx", 1, 2, 3, 4, + I128(0x1ffffffff, 0x2ffffffff), + I128(0x3eeeeeeee, 0x4eeeeeeee)); + strcmp("1 2 3 4 00000001ffffffff00000002ffffffff " + "00000003eeeeeeee00000004eeeeeeee", + buf); + })); + ASSERT(0, ({ + char buf[200]; + sprintf(buf, "%d %d %d %d %d %032jx %032jx", 1, 2, 3, 4, 5, + I128(0x1ffffffff, 0x2ffffffff), + I128(0x3eeeeeeee, 0x4eeeeeeee)); + strcmp("1 2 3 4 5 00000001ffffffff00000002ffffffff " + "00000003eeeeeeee00000004eeeeeeee", + buf); + })); +} + int main(void) { testLang128(); testCompare128(); @@ -8179,5 +8216,6 @@ int main(void) { testCastDblUint128(); testCastLdblInt128(); testCastLdblUint128(); + testAbi(); return 0; } diff --git a/third_party/chibicc/test/string_test.c b/third_party/chibicc/test/string_test.c index 96260d84..f44c816e 100644 --- a/third_party/chibicc/test/string_test.c +++ b/third_party/chibicc/test/string_test.c @@ -1,6 +1,9 @@ #include "third_party/chibicc/test/test.h" int main() { + typeof("str") StringInitParen1 = ("str"); + char StringInitParen2[] = ("str"); + ASSERT(0, ""[0]); ASSERT(1, sizeof("")); diff --git a/third_party/chibicc/test/test.mk b/third_party/chibicc/test/test.mk index 555cc8f2..bf46daeb 100644 --- a/third_party/chibicc/test/test.mk +++ b/third_party/chibicc/test/test.mk @@ -49,6 +49,8 @@ THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS = \ LIBC_NEXGEN32E \ LIBC_UNICODE \ LIBC_MEM \ + LIBC_X \ + THIRD_PARTY_CHIBICC \ THIRD_PARTY_COMPILER_RT THIRD_PARTY_CHIBICC_TEST_DEPS := \ @@ -95,6 +97,4 @@ o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \ .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) + $(THIRD_PARTY_CHIBICC_TEST_CHECKS) diff --git a/third_party/chibicc/test/typeof_test.c b/third_party/chibicc/test/typeof_test.c index 4e5bded1..ff77888b 100644 --- a/third_party/chibicc/test/typeof_test.c +++ b/third_party/chibicc/test/typeof_test.c @@ -24,6 +24,12 @@ int main() { sizeof(x); })); ASSERT(12, sizeof(typeof(struct { int a, b, c; }))); - - return 0; + ASSERT(3, ({ + label: + 3; + })); + ASSERT(3, ({ + __typeof(int) x = 3; + x; + })); } diff --git a/third_party/chibicc/tokenize.c b/third_party/chibicc/tokenize.c index eb673630..3e89c881 100644 --- a/third_party/chibicc/tokenize.c +++ b/third_party/chibicc/tokenize.c @@ -1,6 +1,6 @@ #include "third_party/chibicc/chibicc.h" -#define LOOKINGAT(TOK, OP) lookingat(TOK, OP, strlen(OP)) +#define LOOKINGAT(TOK, OP) (!memcmp(TOK, OP, strlen(OP))) // Input file static File *current_file; @@ -75,29 +75,18 @@ 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, size_t n) { - return n == tok->len && !compare_strings(tok->loc, op, tok->len); + return n == tok->len && !memcmp(tok->loc, op, tok->len); } bool consume(Token **rest, Token *tok, char *str, size_t n) { - if (n == tok->len && !compare_strings(tok->loc, str, n)) { + if (n == tok->len && !memcmp(tok->loc, str, n)) { *rest = tok->next; return true; } @@ -106,9 +95,12 @@ bool consume(Token **rest, Token *tok, char *str, size_t n) { } // 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; +Token *skip(Token *tok, char op) { + if (tok->len == 1 && *tok->loc == op) { + return tok->next; + } else { + error_tok(tok, "expected '%c'", op); + } } // Create a new token and add it as the next token of `cur`. diff --git a/third_party/chibicc/type.c b/third_party/chibicc/type.c index fa119e4e..743082aa 100644 --- a/third_party/chibicc/type.c +++ b/third_party/chibicc/type.c @@ -166,10 +166,10 @@ void add_type(Node *node) { case ND_SUB: case ND_MUL: case ND_DIV: - case ND_MOD: - case ND_BITAND: - case ND_BITOR: - case ND_BITXOR: + case ND_REM: + case ND_BINAND: + case ND_BINOR: + case ND_BINXOR: usual_arith_conv(&node->lhs, &node->rhs); node->ty = node->lhs->ty; return; @@ -226,10 +226,11 @@ void add_type(Node *node) { return; case ND_ADDR: { Type *ty = node->lhs->ty; - if (ty->kind == TY_ARRAY) + if (ty->kind == TY_ARRAY) { node->ty = pointer_to(ty->base); - else + } else { node->ty = pointer_to(ty); + } return; } case ND_DEREF: @@ -251,7 +252,17 @@ void add_type(Node *node) { case ND_STMT_EXPR: if (node->body) { Node *stmt = node->body; - while (stmt->next) stmt = stmt->next; + for (;;) { + if (stmt->next) { + stmt = stmt->next; + } else { + if (stmt->kind == ND_LABEL && stmt->lhs) { + stmt = stmt->lhs; + } else { + break; + } + } + } if (stmt->kind == ND_EXPR_STMT) { node->ty = stmt->lhs->ty; return; diff --git a/tool/build/build.mk b/tool/build/build.mk index 8c0e64b8..cc3f0434 100644 --- a/tool/build/build.mk +++ b/tool/build/build.mk @@ -88,12 +88,6 @@ o/$(MODE)/tool/build/emulator.o: \ OVERRIDE_COPTS += \ -fno-sanitize=pointer-overflow -# ifeq (,$(MODE)) -# $(TOOL_BUILD_OBJS): \ -# OVERRIDE_COPTS += \ -# -fsanitize=address -# endif - .PHONY: o/$(MODE)/tool/build o/$(MODE)/tool/build: \ o/$(MODE)/tool/build/emucrt \ diff --git a/tool/build/coefficients.c b/tool/build/coefficients.c deleted file mode 100644 index 6bff7cb2..00000000 --- a/tool/build/coefficients.c +++ /dev/null @@ -1,230 +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/half.h" -#include "dsp/core/q.h" -#include "libc/conv/conv.h" -#include "libc/log/check.h" -#include "libc/log/log.h" -#include "libc/macros.h" -#include "libc/math.h" -#include "libc/mem/mem.h" -#include "libc/runtime/gc.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/ex.h" -#include "libc/sysv/consts/exit.h" -#include "libc/x/x.h" -#include "third_party/gdtoa/gdtoa.h" -#include "third_party/getopt/getopt.h" - -#define USAGE \ - " [FLAGS] [INT|FLOAT...]\n\ -\n\ -Example:\n\ -\n\ - coefficients -n -- 1 4 6 4 1 # Gaussian Blur\n\ - coefficients -L16 -H235 -- .299 .587 .114 # BT.601 RGBโ†’Y\n\ -\n\ -Flags:\n\ - -v verbose\n\ - -n normalize\n\ - -m FLEX explicit Q(bits)\n\ - -L FLEX low data value [default 0]\n\ - -H FLEX high data value [default 255]\n\ - -? shows this information\n\ -\n" - -static struct Flags { - bool n; - long L, H, m; -} flags_ = { - .L = 0, - .H = 255, -}; - -static wontreturn void PrintUsage(int rc, FILE *f) { - fprintf(f, "Usage: %s%s", program_invocation_name, USAGE); - exit(rc); -} - -static void GetOpts(int argc, char *argv[]) { - int opt; - while ((opt = getopt(argc, argv, "?nvrL:H:m:")) != -1) { - switch (opt) { - case 'v': - g_loglevel++; - break; - case 'n': - flags_.n = true; - break; - case 'L': - flags_.L = strtol(optarg, NULL, 0); - break; - case 'H': - flags_.H = strtol(optarg, NULL, 0); - break; - case 'm': - flags_.m = strtol(optarg, NULL, 0); - break; - case '?': - PrintUsage(EXIT_SUCCESS, stdout); - default: - PrintUsage(EX_USAGE, stderr); - } - } -} - -static void *Normalize(int n, double A[static 8]) { - int i; - double sum, rnorm; - for (sum = i = 0; i < n; ++i) { - sum += A[i]; - } - if (fabs(sum - 1) > DBL_MIN * n) { - rnorm = 1 / sum; - for (i = 0; i < n; ++i) { - A[i] *= rnorm; - } - } - return A; -} - -static void GetLimits(int n, const long I[static 8], long m, long L, long H, - long res[2][2]) { - int i, j[8]; - long x, p[2] = {L, H}; - DCHECK(0 < n && n <= 8); - memset(res, 0, sizeof(long) * 2 * 2); - for (j[0] = 0; j[0] < ARRAYLEN(p); ++j[0]) { - for (j[1] = 0; j[1] < ARRAYLEN(p); ++j[1]) { - for (j[2] = 0; j[2] < ARRAYLEN(p); ++j[2]) { - for (j[3] = 0; j[3] < ARRAYLEN(p); ++j[3]) { - for (j[4] = 0; j[4] < ARRAYLEN(p); ++j[4]) { - for (j[5] = 0; j[5] < ARRAYLEN(p); ++j[5]) { - for (j[6] = 0; j[6] < ARRAYLEN(p); ++j[6]) { - for (j[7] = 0; j[7] < ARRAYLEN(p); ++j[7]) { - x = 0; - for (i = 0; i < ARRAYLEN(j); ++i) { - x += p[j[i]] * I[i]; - if (x < res[0][0]) res[0][0] = x; - if (x > res[0][1]) res[0][1] = x; - } - x += 1l << (m - 1); - if (x < res[0][0]) res[0][0] = x; - if (x > res[0][1]) res[0][1] = x; - x >>= m; - if (x < res[1][0]) res[1][0] = x; - if (x > res[1][1]) res[1][1] = x; - } - } - } - } - } - } - } - } -} - -static const char *GetFittingMachineWord(long L, long H) { - if (-128 <= L && H <= 127) return "int8"; - if (0 <= L && H <= 255) return "uint8"; - if (-0x8000 <= L && H <= 0x7fff) return "int16"; - if (~0x7fffffff <= L && H <= 0x7fffffff) return "int32"; - if (0 <= L && H <= 0xffffffff) return "uint32"; - return "INT64"; -} - -static char *DescribeMachineWord(long L, long H) { - return xasprintf("%s[%,ld..%,ld]", GetFittingMachineWord(L, H), L, H); -} - -static void ShowBetterCoefficients(int n, double C[static 8], long L, long H) { - long err, I[8], lim[2][2]; - char buf[32], kAlphabet[] = "abcdefgh"; - int i, j, m, emitted, count, indices[8]; - CHECK_LT(L, H); - DCHECK(0 < n && n <= 8); - for (m = 2; m < 40; ++m) { - memset(I, 0, sizeof(I)); - if (C[6] || C[7]) { - err = GetIntegerCoefficients8(I, C, m, L, H); - } else { - err = GetIntegerCoefficients(I, C, m, L, H); - } - GetLimits(n, I, m, L, H, lim); - for (count = i = 0; i < n; ++i) { - if (I[i]) { - indices[count++] = i; - } - } - if (count) { - emitted = 0; - if (m) emitted += printf("("); - for (i = 0; i < count; ++i) { - if (i) emitted += printf(" + "); - if (I[indices[i]] != 1) { - emitted += printf("%ld*%c", I[indices[i]], kAlphabet[indices[i]]); - } else { - emitted += printf("%c", kAlphabet[indices[i]]); - } - } - if (m) { - if (m > 1) { - emitted += printf(" + %ld", 1l << (m - 1)); - } - emitted += printf(")>>%d", m); - } - printf("%*s", MAX(0, 80 - emitted), " "); - printf("/* %s %s %s ฮต=%,ld */\n", gc(DescribeMachineWord(L, H)), - gc(DescribeMachineWord(lim[0][0], lim[0][1])), - gc(DescribeMachineWord(lim[1][0], lim[1][1])), err); - } - } -} - -static int ReadIdealCoefficients(double C[static 8], int sn, char *S[sn]) { - int i, n; - if ((n = MIN(8, sn)) > 0) { - C[0] = C[1] = C[2] = C[3] = C[4] = C[5] = 0; - for (i = 0; i < n; ++i) { - C[i] = strtod(S[i], NULL); - } - } - return n; -} - -int ToolBuildCoefficients(int argc, char *argv[]) { - int n; - double C[8]; - GetOpts(argc, argv); - setvbuf(stdout, malloc(PAGESIZE), _IOLBF, PAGESIZE); - if ((n = ReadIdealCoefficients(C, argc - optind, argv + optind))) { - if (flags_.n) Normalize(n, C); - ShowBetterCoefficients(n, C, flags_.L, flags_.H); - } - return 0; -} - -int main(int argc, char *argv[]) { - g_loglevel = kLogWarn; - showcrashreports(); - return ToolBuildCoefficients(argc, argv); -} diff --git a/tool/build/img2code.c b/tool/build/img2code.c deleted file mode 100644 index 2b7aa4c9..00000000 --- a/tool/build/img2code.c +++ /dev/null @@ -1,267 +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/scale/scale.h" -#include "libc/calls/calls.h" -#include "libc/calls/struct/stat.h" -#include "libc/conv/conv.h" -#include "libc/fmt/bing.internal.h" -#include "libc/limits.h" -#include "libc/log/check.h" -#include "libc/log/log.h" -#include "libc/macros.h" -#include "libc/math.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/ex.h" -#include "libc/sysv/consts/exit.h" -#include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/o.h" -#include "libc/sysv/consts/prot.h" -#include "libc/testlib/testlib.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" - -#define USAGE \ - " [FLAGS] [PATH]\n\ -\n\ -Example:\n\ -\n\ - img2code -cw79 -p2 foo.png\n\ -\n\ -Flags:\n\ - -c compress range\n\ - -o PATH out\n\ - -r FLEX ratio\n\ - -w FLEX new width\n\ - -h FLEX new height\n\ - -p FLEX pixel y ratio\n\ - -? shows this information\n\ -\n" - -static struct Flags { - const char *o; - double r, p; - int w, h; - bool c; -} flags_ = { - .o = "-", - .p = 1, -}; - -static wontreturn void PrintUsage(int rc, FILE *f) { - fprintf(f, "Usage: %s%s", program_invocation_name, USAGE); - exit(rc); -} - -static void GetOpts(int *argc, char *argv[]) { - int opt; - if (*argc == 2 && - (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-help") == 0)) { - PrintUsage(EXIT_SUCCESS, stdout); - } - while ((opt = getopt(*argc, argv, "?co:r:w:h:p:")) != -1) { - switch (opt) { - case 'c': - flags_.c = true; - break; - case 'o': - flags_.o = optarg; - break; - case 'r': - flags_.r = strtod(optarg, NULL); - break; - case 'p': - flags_.p = strtod(optarg, NULL); - break; - case 'w': - flags_.w = strtol(optarg, NULL, 0); - break; - case 'h': - flags_.h = strtol(optarg, NULL, 0); - break; - case '?': - PrintUsage(EXIT_SUCCESS, stdout); - default: - PrintUsage(EX_USAGE, stderr); - } - } - if (optind == *argc) { - argv[(*argc)++] = "-"; - } -} - -static void GetOutputGeometry(long syn, long sxn, long *out_dyn, long *out_dxn, - double *out_ry, double *out_rx) { - double ry, rx; - long dyn, dxn; - if (!flags_.h && !flags_.w) { - if (flags_.r) { - ry = flags_.r * flags_.p; - rx = flags_.r; - } else { - ry = flags_.p; - rx = 1; - } - dyn = round(syn / ry); - dxn = round(sxn / rx); - } else if (flags_.w && !flags_.h) { - if (flags_.r) { - rx = 1. * sxn / flags_.w; - ry = flags_.r * flags_.p; - dxn = flags_.w; - dyn = round(syn / ry); - } else { - rx = 1. * sxn / flags_.w; - ry = flags_.p * rx; - dxn = flags_.w; - dyn = round(syn / ry); - } - } else if (flags_.h && !flags_.w) { - if (flags_.r) { - rx = flags_.r; - ry = flags_.p * syn / flags_.h; - dxn = flags_.w; - dyn = round(syn / ry); - } else { - ry = flags_.p * syn / flags_.h; - rx = ry; - dyn = flags_.h; - dxn = round(syn / rx); - } - } else { - ry = flags_.p; - rx = 1; - dyn = round(flags_.h / ry); - dxn = flags_.w; - } - *out_dyn = dyn; - *out_dxn = dxn; - *out_ry = ry; - *out_rx = rx; -} - -static void *Deinterlace(long dcn, long dyn, long dxn, - unsigned char dst[dcn][dyn][dxn], long syw, long sxw, - long scw, const unsigned char src[syw][sxw][scw], - long syn, long sxn, long sy0, long sx0, long sc0) { - long y, x, c; - for (y = 0; y < dyn; ++y) { - for (x = 0; x < dxn; ++x) { - for (c = 0; c < dcn; ++c) { - dst[c][y][x] = src[sy0 + y][sx0 + x][sc0 + c]; - } - } - } - return dst; -} - -static void CompressRange(long cn, long yn, long xn, - unsigned char img[cn][yn][xn]) { - static const char R[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - double f; - long c, y, x, L, H; - L = R[0], H = R[strlen(R) - 1]; - for (c = 0; c < cn; ++c) { - for (y = 0; y < yn; ++y) { - for (x = 0; x < xn; ++x) { - f = img[c][y][x]; - f /= 255; - f *= H - L; - f += L; - img[c][y][x] = MIN(H, MAX(L, lround(f))); - } - } - } -} - -static void PrintCode(FILE *f, long cn, long yn, long xn, - unsigned char img[cn][yn][xn]) { - long c, y, x; - if (flags_.c) CompressRange(cn, yn, xn, img); - for (c = 0; c < cn; ++c) { - fputc('\n', f); - for (y = 0; y < yn; ++y) { - fputc('\n', f); - for (x = 0; x < xn; ++x) { - fputwc(bing(img[c][y][x], 0), f); - } - } - } - fputc('\n', f); -} - -static void ProcessImage(const char *path, long scn, long syn, long sxn, - unsigned char img[syn][sxn][scn], FILE *f) { - double ry, rx; - long dyn, dxn, cn; - GetOutputGeometry(syn, sxn, &dyn, &dxn, &ry, &rx); - if (dyn == syn && dxn == sxn) { - /* TODO(jart): Why doesn't Gyarados no-op? */ - PrintCode(f, scn, dyn, dxn, - Deinterlace(scn, syn, sxn, gc(memalign(32, scn * syn * sxn)), syn, - sxn, scn, img, syn, sxn, 0, 0, 0)); - } else { - PrintCode( - f, scn, dyn, dxn, - EzGyarados(scn, dyn, dxn, gc(memalign(32, scn * dyn * dxn)), scn, syn, - sxn, - Deinterlace(scn, syn, sxn, gc(memalign(32, scn * syn * sxn)), - syn, sxn, scn, img, syn, sxn, 0, 0, 0), - 0, scn, dyn, dxn, syn, sxn, ry, rx, 0, 0)); - } -} - -static void WithImageFile(const char *path, FILE *f, - void fn(const char *path, long cn, long yn, long xn, - unsigned char src[yn][xn][cn], FILE *f)) { - struct stat st; - void *map, *data; - int fd, yn, xn, cn; - CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path); - CHECK_NE(-1, fstat(fd, &st)); - CHECK_GT(st.st_size, 0); - CHECK_LE(st.st_size, INT_MAX); - CHECK_NE(MAP_FAILED, - (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); - CHECK_NOTNULL( - (data = stbi_load_from_memory(map, st.st_size, &xn, &yn, &cn, 0)), "%s", - path); - CHECK_NE(-1, munmap(map, st.st_size)); - CHECK_NE(-1, close(fd)); - fn(path, cn, yn, xn, data, f); - free(data); -} - -int main(int argc, char *argv[]) { - int i; - FILE *f; - showcrashreports(); - GetOpts(&argc, argv); - stbi_set_unpremultiply_on_load(true); - CHECK_NOTNULL((f = fopen(flags_.o, "w"))); - for (i = optind; i < argc; ++i) { - WithImageFile(argv[i], f, ProcessImage); - } - return fclose(f); -} diff --git a/tool/build/lib/divmul.c b/tool/build/lib/divmul.c index b36568f6..6ce78fa5 100644 --- a/tool/build/lib/divmul.c +++ b/tool/build/lib/divmul.c @@ -164,8 +164,8 @@ void OpMulAxAlEbSigned(struct Machine *m, uint32_t rde) { int16_t ax; uint8_t *p; p = GetModrmRegisterBytePointerRead(m, rde); - __builtin_mul_overflow((int8_t)Read8(m->ax), (int8_t)Read8(p), &ax); - of = (int)ax != (int8_t)ax; + ax = (int8_t)Read8(m->ax) * (int8_t)Read8(p); + of = ax != (int8_t)ax; m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); Write16(m->ax, ax); @@ -176,8 +176,8 @@ void OpMulAxAlEbUnsigned(struct Machine *m, uint32_t rde) { bool of; uint8_t *p; p = GetModrmRegisterBytePointerRead(m, rde); - __builtin_mul_overflow(Read8(m->ax), Read8(p), &ax); - of = (uint8_t)ax != ax; + ax = Read8(m->ax) * Read8(p); + of = ax != (uint8_t)ax; m->flags = SetFlag(m->flags, FLAGS_CF, of); m->flags = SetFlag(m->flags, FLAGS_OF, of); Write16(m->ax, ax); @@ -256,10 +256,12 @@ static void AluImul(struct Machine *m, uint32_t rde, uint8_t *a, uint8_t *b) { of = __builtin_mul_overflow(x, y, &z); Write64(RegRexrReg(m, rde), z & 0xffffffff); } else { - int16_t x, y, z; + int z; + int16_t x, y; x = Read16(a); y = Read16(b); - of = __builtin_mul_overflow(x, y, &z); + z = x * y; + of = z != (int16_t)z; Write16(RegRexrReg(m, rde), z); } m->flags = SetFlag(m->flags, FLAGS_CF, of); diff --git a/tool/build/lib/memory.c b/tool/build/lib/memory.c index 5d13086d..9ad4c80f 100644 --- a/tool/build/lib/memory.c +++ b/tool/build/lib/memory.c @@ -169,7 +169,7 @@ void *ReserveAddress(struct Machine *m, int64_t v, size_t n) { } void *AccessRam(struct Machine *m, int64_t v, size_t n, void *p[2], - uint8_t tmp[n], bool copy) { + uint8_t *tmp, bool copy) { unsigned k; uint8_t *a, *b; DCHECK_LE(n, 0x1000); @@ -188,32 +188,31 @@ void *AccessRam(struct Machine *m, int64_t v, size_t n, void *p[2], return tmp; } -void *Load(struct Machine *m, int64_t v, size_t n, uint8_t b[n]) { +void *Load(struct Machine *m, int64_t v, size_t n, uint8_t *b) { void *p[2]; SetReadAddr(m, v, n); return AccessRam(m, v, n, p, b, true); } void *BeginStore(struct Machine *m, int64_t v, size_t n, void *p[2], - uint8_t b[n]) { + uint8_t *b) { SetWriteAddr(m, v, n); return AccessRam(m, v, n, p, b, false); } void *BeginStoreNp(struct Machine *m, int64_t v, size_t n, void *p[2], - uint8_t b[n]) { + uint8_t *b) { if (!v) return NULL; return BeginStore(m, v, n, p, b); } void *BeginLoadStore(struct Machine *m, int64_t v, size_t n, void *p[2], - uint8_t b[n]) { + uint8_t *b) { SetWriteAddr(m, v, n); return AccessRam(m, v, n, p, b, true); } -void EndStore(struct Machine *m, int64_t v, size_t n, void *p[2], - uint8_t b[n]) { +void EndStore(struct Machine *m, int64_t v, size_t n, void *p[2], uint8_t *b) { uint8_t *a; unsigned k; DCHECK_LE(n, 0x1000); @@ -228,7 +227,7 @@ void EndStore(struct Machine *m, int64_t v, size_t n, void *p[2], } void EndStoreNp(struct Machine *m, int64_t v, size_t n, void *p[2], - uint8_t b[n]) { + uint8_t *b) { if (v) EndStore(m, v, n, p, b); } diff --git a/tool/build/lib/panel.c b/tool/build/lib/panel.c index b5adea96..a32da7ce 100644 --- a/tool/build/lib/panel.c +++ b/tool/build/lib/panel.c @@ -39,7 +39,7 @@ * @return -1 w/ errno if an error happened * @see nblack's notcurses project too! */ -ssize_t PrintPanels(int fd, long pn, struct Panel p[pn], long tyn, long txn) { +ssize_t PrintPanels(int fd, long pn, struct Panel *p, long tyn, long txn) { wint_t wc; ssize_t rc; size_t wrote; diff --git a/tool/build/lib/ssefloat.c b/tool/build/lib/ssefloat.c index 9347295d..9ec1436f 100644 --- a/tool/build/lib/ssefloat.c +++ b/tool/build/lib/ssefloat.c @@ -34,173 +34,6 @@ #include "tool/build/lib/ssefloat.h" #include "tool/build/lib/throw.h" -#define SSE_BUILTINS \ - (!IsModeDbg() && __SSE3__ + 0 && \ - (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408) - -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; -} - -static double_v Addpd(struct Machine *m, double_v x, double_v y) { - return x + y; -} - -static float_v Mulps(struct Machine *m, float_v x, float_v y) { - return x * y; -} - -static double_v Mulpd(struct Machine *m, double_v x, double_v y) { - return x * y; -} - -static float_v Subps(struct Machine *m, float_v x, float_v y) { - return x - y; -} - -static double_v Subpd(struct Machine *m, double_v x, double_v y) { - return x - y; -} - -static float_v Divps(struct Machine *m, float_v x, float_v y) { - return x / y; -} - -static double_v Divpd(struct Machine *m, double_v x, double_v y) { - return x / y; -} - -static float_v Andps(struct Machine *m, float_v x, float_v y) { - return (float_v)((int_v)x & (int_v)y); -} - -static double_v Andpd(struct Machine *m, double_v x, double_v y) { - return (double_v)((long_v)x & (long_v)y); -} - -static float_v Andnps(struct Machine *m, float_v x, float_v y) { - return (float_v)(~(int_v)x & (int_v)y); -} - -static double_v Andnpd(struct Machine *m, double_v x, double_v y) { - return (double_v)(~(long_v)x & (long_v)y); -} - -static float_v Orps(struct Machine *m, float_v x, float_v y) { - return (float_v)((int_v)x | (int_v)y); -} - -static double_v Orpd(struct Machine *m, double_v x, double_v y) { - return (double_v)((long_v)x | (long_v)y); -} - -static float_v Xorps(struct Machine *m, float_v x, float_v y) { - return (float_v)((int_v)x ^ (int_v)y); -} - -static double_v Xorpd(struct Machine *m, double_v x, double_v y) { - return (double_v)((long_v)x ^ (long_v)y); -} - -static float_v Minps(struct Machine *m, float_v x, float_v y) { -#if SSE_BUILTINS - return __builtin_ia32_minps(x, y); -#else - unsigned i; - for (i = 0; i < 4; ++i) { - x[i] = MIN(x[i], y[i]); - } - return x; -#endif -} - -static double_v Minpd(struct Machine *m, double_v x, double_v y) { -#if SSE_BUILTINS - return __builtin_ia32_minpd(x, y); -#else - unsigned i; - for (i = 0; i < 2; ++i) { - x[i] = MIN(x[i], y[i]); - } - return x; -#endif -} - -static float_v Maxps(struct Machine *m, float_v x, float_v y) { -#if SSE_BUILTINS - return __builtin_ia32_maxps(x, y); -#else - unsigned i; - for (i = 0; i < 4; ++i) { - x[i] = MAX(x[i], y[i]); - } - return x; -#endif -} - -static double_v Maxpd(struct Machine *m, double_v x, double_v y) { -#if SSE_BUILTINS - return __builtin_ia32_maxpd(x, y); -#else - unsigned i; - for (i = 0; i < 2; ++i) { - x[i] = MAX(x[i], y[i]); - } - return x; -#endif -} - -static double_v Haddpd(struct Machine *m, double_v x, double_v y) { -#if SSE_BUILTINS - return __builtin_ia32_haddpd(x, y); -#else - return (double_v){x[0] + x[1], y[0] + y[1]}; -#endif -} - -static float_v Haddps(struct Machine *m, float_v x, float_v y) { -#if SSE_BUILTINS - return __builtin_ia32_haddps(x, y); -#else - return (float_v){x[0] + x[1], x[2] + x[3], y[0] + y[1], y[2] + y[3]}; -#endif -} - -static double_v Hsubpd(struct Machine *m, double_v x, double_v y) { -#if SSE_BUILTINS - return __builtin_ia32_hsubpd(x, y); -#else - return (double_v){x[0] - x[1], y[0] - y[1]}; -#endif -} - -static float_v Hsubps(struct Machine *m, float_v x, float_v y) { -#if SSE_BUILTINS - return __builtin_ia32_hsubps(x, y); -#else - return (float_v){x[0] - x[1], x[2] - x[3], y[0] - y[1], y[2] - y[3]}; -#endif -} - -static double_v Addsubpd(struct Machine *m, double_v x, double_v y) { -#if SSE_BUILTINS - return __builtin_ia32_addsubpd(x, y); -#else - return (double_v){x[0] - y[0], x[1] + y[1]}; -#endif -} - -static float_v Addsubps(struct Machine *m, float_v x, float_v y) { -#if SSE_BUILTINS - return __builtin_ia32_addsubps(x, y); -#else - return (float_v){x[0] - y[0], x[1] + y[1], x[2] - y[2], x[3] + y[3]}; -#endif -} - void OpUnpcklpsd(struct Machine *m, uint32_t rde) { uint8_t *a, *b; a = XmmRexrReg(m, rde); @@ -294,28 +127,28 @@ void OpShufpsd(struct Machine *m, uint32_t rde) { void OpSqrtpsd(struct Machine *m, uint32_t rde) { long i; - float_v xf; - double_v xd; + float xf[4]; + double xd[2]; switch (Rep(rde) | Osz(rde)) { case 0: - memcpy(&xf, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(xf, GetModrmRegisterXmmPointerRead16(m, rde), 16); for (i = 0; i < 4; ++i) xf[i] = sqrtf(xf[i]); - memcpy(XmmRexrReg(m, rde), &xf, 16); + memcpy(XmmRexrReg(m, rde), xf, 16); break; case 1: - memcpy(&xd, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(xd, GetModrmRegisterXmmPointerRead16(m, rde), 16); for (i = 0; i < 2; ++i) xd[i] = sqrt(xd[i]); - memcpy(XmmRexrReg(m, rde), &xd, 16); + memcpy(XmmRexrReg(m, rde), xd, 16); break; case 2: - memcpy(&xd, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(xd, GetModrmRegisterXmmPointerRead8(m, rde), 8); xd[0] = sqrt(xd[0]); - memcpy(XmmRexrReg(m, rde), &xd, 8); + memcpy(XmmRexrReg(m, rde), xd, 8); break; case 3: - memcpy(&xf, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(xf, GetModrmRegisterXmmPointerRead4(m, rde), 4); xf[0] = sqrtf(xf[0]); - memcpy(XmmRexrReg(m, rde), &xf, 4); + memcpy(XmmRexrReg(m, rde), xf, 4); break; default: unreachable; @@ -323,91 +156,30 @@ void OpSqrtpsd(struct Machine *m, uint32_t rde) { } void OpRsqrtps(struct Machine *m, uint32_t rde) { - float_v x; + float x[4]; unsigned i; if (Rep(rde) != 3) { - memcpy(&x, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, GetModrmRegisterXmmPointerRead16(m, rde), 16); for (i = 0; i < 4; ++i) x[i] = 1.f / sqrtf(x[i]); - memcpy(XmmRexrReg(m, rde), &x, 16); + memcpy(XmmRexrReg(m, rde), x, 16); } else { - memcpy(&x, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(x, GetModrmRegisterXmmPointerRead4(m, rde), 4); x[0] = 1.f / sqrtf(x[0]); - memcpy(XmmRexrReg(m, rde), &x, 4); + memcpy(XmmRexrReg(m, rde), x, 4); } } void OpRcpps(struct Machine *m, uint32_t rde) { - float_v x; + float x[4]; unsigned i; if (Rep(rde) != 3) { - memcpy(&x, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, GetModrmRegisterXmmPointerRead16(m, rde), 16); for (i = 0; i < 4; ++i) x[i] = 1.f / x[i]; - memcpy(XmmRexrReg(m, rde), &x, 16); + memcpy(XmmRexrReg(m, rde), x, 16); } else { - memcpy(&x, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(x, GetModrmRegisterXmmPointerRead4(m, rde), 4); x[0] = 1.f / x[0]; - memcpy(XmmRexrReg(m, rde), &x, 4); - } -} - -static void VpsdWpsd(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v), - bool isfloat, bool isdouble) { - float_v xf, yf; - double_v xd, yd; - if (isfloat) { - memcpy(&xf, XmmRexrReg(m, rde), 16); - memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16); - xf = opf(m, xf, yf); - memcpy(XmmRexrReg(m, rde), &xf, 16); - } else if (isdouble) { - memcpy(&xd, XmmRexrReg(m, rde), 16); - memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16); - xd = opd(m, xd, yd); - memcpy(XmmRexrReg(m, rde), &xd, 16); - } else { - OpUd(m, rde); - } -} - -static void VpsdWpsd66(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v)) { - VpsdWpsd(m, rde, opf, opd, !Osz(rde), Osz(rde)); -} - -static void VpsdWpsd66f2(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v)) { - VpsdWpsd(m, rde, opf, opd, Rep(rde) == 2, Osz(rde)); -} - -static void VspsdWspsd(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v)) { - float_v xf, yf; - double_v xd, yd; - if (Rep(rde) == 2) { - memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&xd, XmmRexrReg(m, rde), 8); - xd = opd(m, xd, yd); - memcpy(XmmRexrReg(m, rde), &xd, 8); - } else if (Rep(rde) == 3) { - memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&xf, XmmRexrReg(m, rde), 4); - xf = opf(m, xf, yf); - memcpy(XmmRexrReg(m, rde), &xf, 4); - } else if (Osz(rde)) { - memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(&xd, XmmRexrReg(m, rde), 16); - xd = opd(m, xd, yd); - memcpy(XmmRexrReg(m, rde), &xd, 16); - } else { - memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(&xf, XmmRexrReg(m, rde), 16); - xf = opf(m, xf, yf); - memcpy(XmmRexrReg(m, rde), &xf, 16); + memcpy(XmmRexrReg(m, rde), x, 4); } } @@ -448,118 +220,376 @@ void OpComissVsWs(struct Machine *m, uint32_t rde) { } } -static float_v Cmpps(struct Machine *m, float_v x, float_v y) { - long i; - switch (m->xedd->op.uimm0) { +static int Cmps(int imm, float x, float y) { + switch (imm) { case 0: - return x == y; + return x == y ? -1 : 0; case 1: - return x < y; + return x < y ? -1 : 0; case 2: - return x <= y; + return x <= y ? -1 : 0; case 3: - for (i = 0; i < 4; ++i) { - x[i] = isnan(x[i]) || isnan(y[i]); - } - return x; + return isnan(x) || isnan(y) ? -1 : 0; case 4: - return x != y; + return x != y ? -1 : 0; case 5: - return x >= y; + return x >= y ? -1 : 0; case 6: - return x > y; + return x > y ? -1 : 0; case 7: - for (i = 0; i < 4; ++i) { - x[i] = !(isnan(x[i]) || isnan(y[i])); - } - return x; + return !(isnan(x) || isnan(y)) ? -1 : 0; default: - OpUd(m, 0); + return 0; } } -static double_v Cmppd(struct Machine *m, double_v x, double_v y) { +static int32_t Cmpd(int imm, double x, double y) { long i; - switch (m->xedd->op.uimm0) { + switch (imm) { case 0: - return x == y; + return x == y ? -1 : 0; case 1: - return x < y; + return x < y ? -1 : 0; case 2: - return x <= y; + return x <= y ? -1 : 0; case 3: - for (i = 0; i < 2; ++i) { - x[i] = isnan(x[i]) || isnan(y[i]); - } - return x; + return isnan(x) || isnan(y) ? -1 : 0; case 4: - return x != y; + return x != y ? -1 : 0; case 5: - return x >= y; + return x >= y ? -1 : 0; case 6: - return x > y; + return x > y ? -1 : 0; case 7: - for (i = 0; i < 2; ++i) { - x[i] = !(isnan(x[i]) || isnan(y[i])); - } - return x; + return !(isnan(x) || isnan(y)) ? -1 : 0; default: - OpUd(m, 0); + return 0; } } void OpAddpsd(struct Machine *m, uint32_t rde) { - VspsdWspsd(m, rde, Addps, Addpd); + if (Rep(rde) == 2) { + double x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&x, XmmRexrReg(m, rde), 8); + x += y; + memcpy(XmmRexrReg(m, rde), &x, 8); + } else if (Rep(rde) == 3) { + float x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&x, XmmRexrReg(m, rde), 4); + x += y; + memcpy(XmmRexrReg(m, rde), &x, 4); + } else if (Osz(rde)) { + double x[2], y[2]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] += y[0]; + x[1] += y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); + } else { + float x[4], y[4]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] += y[0]; + x[1] += y[1]; + x[2] += y[2]; + x[3] += y[3]; + memcpy(XmmRexrReg(m, rde), x, 16); + } } void OpMulpsd(struct Machine *m, uint32_t rde) { - VspsdWspsd(m, rde, Mulps, Mulpd); + if (Rep(rde) == 2) { + double x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&x, XmmRexrReg(m, rde), 8); + x *= y; + memcpy(XmmRexrReg(m, rde), &x, 8); + } else if (Rep(rde) == 3) { + float x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&x, XmmRexrReg(m, rde), 4); + x *= y; + memcpy(XmmRexrReg(m, rde), &x, 4); + } else if (Osz(rde)) { + double x[2], y[2]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] *= y[0]; + x[1] *= y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); + } else { + float x[4], y[4]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] *= y[0]; + x[1] *= y[1]; + x[2] *= y[2]; + x[3] *= y[3]; + memcpy(XmmRexrReg(m, rde), x, 16); + } } void OpSubpsd(struct Machine *m, uint32_t rde) { - VspsdWspsd(m, rde, Subps, Subpd); + if (Rep(rde) == 2) { + double x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&x, XmmRexrReg(m, rde), 8); + x -= y; + memcpy(XmmRexrReg(m, rde), &x, 8); + } else if (Rep(rde) == 3) { + float x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&x, XmmRexrReg(m, rde), 4); + x -= y; + memcpy(XmmRexrReg(m, rde), &x, 4); + } else if (Osz(rde)) { + double x[2], y[2]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] -= y[0]; + x[1] -= y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); + } else { + float x[4], y[4]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] -= y[0]; + x[1] -= y[1]; + x[2] -= y[2]; + x[3] -= y[3]; + memcpy(XmmRexrReg(m, rde), x, 16); + } } void OpDivpsd(struct Machine *m, uint32_t rde) { - VspsdWspsd(m, rde, Divps, Divpd); + if (Rep(rde) == 2) { + double x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&x, XmmRexrReg(m, rde), 8); + x /= y; + memcpy(XmmRexrReg(m, rde), &x, 8); + } else if (Rep(rde) == 3) { + float x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&x, XmmRexrReg(m, rde), 4); + x /= y; + memcpy(XmmRexrReg(m, rde), &x, 4); + } else if (Osz(rde)) { + double x[2], y[2]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] /= y[0]; + x[1] /= y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); + } else { + float x[4], y[4]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] /= y[0]; + x[1] /= y[1]; + x[2] /= y[2]; + x[3] /= y[3]; + memcpy(XmmRexrReg(m, rde), x, 16); + } } void OpMinpsd(struct Machine *m, uint32_t rde) { - VspsdWspsd(m, rde, Minps, Minpd); + if (Rep(rde) == 2) { + double x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&x, XmmRexrReg(m, rde), 8); + x = MIN(x, y); + memcpy(XmmRexrReg(m, rde), &x, 8); + } else if (Rep(rde) == 3) { + float x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&x, XmmRexrReg(m, rde), 4); + x = MIN(x, y); + memcpy(XmmRexrReg(m, rde), &x, 4); + } else if (Osz(rde)) { + double x[2], y[2]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] = MIN(x[0], y[0]); + x[1] = MIN(x[1], y[1]); + memcpy(XmmRexrReg(m, rde), x, 16); + } else { + float x[4], y[4]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] = MIN(x[0], y[0]); + x[1] = MIN(x[1], y[1]); + x[2] = MIN(x[2], y[2]); + x[3] = MIN(x[3], y[3]); + memcpy(XmmRexrReg(m, rde), x, 16); + } } void OpMaxpsd(struct Machine *m, uint32_t rde) { - VspsdWspsd(m, rde, Maxps, Maxpd); + if (Rep(rde) == 2) { + double x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&x, XmmRexrReg(m, rde), 8); + x = MAX(x, y); + memcpy(XmmRexrReg(m, rde), &x, 8); + } else if (Rep(rde) == 3) { + float x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&x, XmmRexrReg(m, rde), 4); + x = MAX(x, y); + memcpy(XmmRexrReg(m, rde), &x, 4); + } else if (Osz(rde)) { + double x[2], y[2]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] = MAX(x[0], y[0]); + x[1] = MAX(x[1], y[1]); + memcpy(XmmRexrReg(m, rde), x, 16); + } else { + float x[4], y[4]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] = MAX(x[0], y[0]); + x[1] = MAX(x[1], y[1]); + x[2] = MAX(x[2], y[2]); + x[3] = MAX(x[3], y[3]); + memcpy(XmmRexrReg(m, rde), x, 16); + } } void OpCmppsd(struct Machine *m, uint32_t rde) { - VspsdWspsd(m, rde, Cmpps, Cmppd); + int imm = m->xedd->op.uimm0; + if (Rep(rde) == 2) { + double x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&x, XmmRexrReg(m, rde), 8); + x = Cmpd(imm, x, y); + memcpy(XmmRexrReg(m, rde), &x, 8); + } else if (Rep(rde) == 3) { + float x, y; + memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&x, XmmRexrReg(m, rde), 4); + x = Cmps(imm, x, y); + memcpy(XmmRexrReg(m, rde), &x, 4); + } else if (Osz(rde)) { + double x[2], y[2]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] = Cmpd(imm, x[0], y[0]); + x[1] = Cmpd(imm, x[1], y[1]); + memcpy(XmmRexrReg(m, rde), x, 16); + } else { + float x[4], y[4]; + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(x, XmmRexrReg(m, rde), 16); + x[0] = Cmps(imm, x[0], y[0]); + x[1] = Cmps(imm, x[1], y[1]); + x[2] = Cmps(imm, x[2], y[2]); + x[3] = Cmps(imm, x[3], y[3]); + memcpy(XmmRexrReg(m, rde), x, 16); + } } void OpAndpsd(struct Machine *m, uint32_t rde) { - VpsdWpsd66(m, rde, Andps, Andpd); + uint64_t x[2], y[2]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + x[0] &= y[0]; + x[1] &= y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); } void OpAndnpsd(struct Machine *m, uint32_t rde) { - VpsdWpsd66(m, rde, Andnps, Andnpd); + uint64_t x[2], y[2]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + x[0] = ~x[0] & y[0]; + x[1] = ~x[1] & y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); } void OpOrpsd(struct Machine *m, uint32_t rde) { - VpsdWpsd66(m, rde, Orps, Orpd); + uint64_t x[2], y[2]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + x[0] |= y[0]; + x[1] |= y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); } void OpXorpsd(struct Machine *m, uint32_t rde) { - VpsdWpsd66(m, rde, Xorps, Xorpd); + uint64_t x[2], y[2]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + x[0] ^= y[0]; + x[1] ^= y[1]; + memcpy(XmmRexrReg(m, rde), x, 16); } void OpHaddpsd(struct Machine *m, uint32_t rde) { - VpsdWpsd66f2(m, rde, Haddps, Haddpd); + if (Rep(rde) == 2) { + float x[4], y[4], z[4]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + z[0] = x[0] + x[1]; + z[1] = x[2] + x[3]; + z[2] = y[0] + y[1]; + z[3] = y[2] + y[3]; + memcpy(XmmRexrReg(m, rde), x, 16); + } else if (Osz(rde)) { + double x[2], y[2], z[2]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + z[0] = x[0] + x[1]; + z[1] = y[0] + y[1]; + memcpy(XmmRexrReg(m, rde), z, 16); + } else { + OpUd(m, rde); + } } void OpHsubpsd(struct Machine *m, uint32_t rde) { - VpsdWpsd66f2(m, rde, Hsubps, Hsubpd); + if (Rep(rde) == 2) { + float x[4], y[4], z[4]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + z[0] = x[0] - x[1]; + z[1] = x[2] - x[3]; + z[2] = y[0] - y[1]; + z[3] = y[2] - y[3]; + memcpy(XmmRexrReg(m, rde), x, 16); + } else if (Osz(rde)) { + double x[2], y[2], z[2]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + z[0] = x[0] - x[1]; + z[1] = y[0] - y[1]; + memcpy(XmmRexrReg(m, rde), z, 16); + } else { + OpUd(m, rde); + } } void OpAddsubpsd(struct Machine *m, uint32_t rde) { - VpsdWpsd66f2(m, rde, Addsubps, Addsubpd); + if (Rep(rde) == 2) { + float x[4], y[4], z[4]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + z[0] = x[0] - y[0]; + z[1] = x[1] + y[1]; + z[2] = x[2] - y[2]; + z[3] = x[3] + y[3]; + memcpy(XmmRexrReg(m, rde), x, 16); + } else if (Osz(rde)) { + double x[2], y[2], z[2]; + memcpy(x, XmmRexrReg(m, rde), 16); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); + z[0] = x[0] - y[0]; + z[1] = x[1] + y[1]; + memcpy(XmmRexrReg(m, rde), z, 16); + } else { + OpUd(m, rde); + } } diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index dbd05991..3157346e 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -442,7 +442,7 @@ static int AppendIovsReal(struct Machine *m, struct Iovs *ib, int64_t addr, static int AppendIovsGuest(struct Machine *m, struct Iovs *iv, int64_t iovaddr, long iovlen) { int rc; - long i, iovsize; + size_t i, iovsize; struct iovec *guestiovs; if (!__builtin_mul_overflow(iovlen, sizeof(struct iovec), &iovsize) && (0 <= iovsize && iovsize <= 0x7ffff000)) { diff --git a/tool/emacs/cosmo-c-builtins.el b/tool/emacs/cosmo-c-builtins.el index e01b2529..c4175dec 100644 --- a/tool/emacs/cosmo-c-builtins.el +++ b/tool/emacs/cosmo-c-builtins.el @@ -69,6 +69,9 @@ "__builtin_va_end" "__builtin_abs" "__builtin_strcpy" + "__builtin_strstr" + "__builtin_strpbrk" + "__builtin_strchr" "__builtin_stpcpy" "__builtin_setjmp" "__builtin_longjmp" diff --git a/tool/emacs/cosmo-c-keywords.el b/tool/emacs/cosmo-c-keywords.el index 58d10587..9428ba61 100644 --- a/tool/emacs/cosmo-c-keywords.el +++ b/tool/emacs/cosmo-c-keywords.el @@ -1,6 +1,6 @@ (defconst cosmo-c-keywords-regex (let ( - + ;; (kar ;; '("case" ;; "do" @@ -237,6 +237,7 @@ "__aligned__" "__alloc_align__" "__alloc_size__" + "__warn_if_not_aligned__" "__artificial__" "__assume_aligned__" "__cold__"