Hunt down some small bugs
parent
95b142e4e5
commit
830334d767
|
@ -23,10 +23,18 @@
|
|||
#include "libc/macros.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/knuthmultiplicativehash.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
static uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) {
|
||||
size_t i;
|
||||
uint32_t h;
|
||||
const uint32_t kPhiPrime = 0x9e3779b1;
|
||||
const unsigned char *p = (const unsigned char *)buf;
|
||||
for (h = i = 0; i < size; i++) h = (p[i] + h) * kPhiPrime;
|
||||
return h;
|
||||
}
|
||||
|
||||
static textwindows noinline uint32_t GetUserNameHash(void) {
|
||||
char16_t buf[257];
|
||||
uint32_t size = ARRAYLEN(buf);
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*-*- 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 2017 Google LLC │
|
||||
│ │
|
||||
│ Licensed under the Apache License, Version 2.0 (the "License"); │
|
||||
│ you may not use this file except in compliance with the License. │
|
||||
│ You may obtain a copy of the License at │
|
||||
│ │
|
||||
│ http://www.apache.org/licenses/LICENSE-2.0 │
|
||||
│ │
|
||||
│ Unless required by applicable law or agreed to in writing, software │
|
||||
│ distributed under the License is distributed on an "AS IS" BASIS, │
|
||||
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
|
||||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/highwayhash64.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
HighwayHash (Apache 2.0)\\n\
|
||||
Copyright 2017 Google LLC\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
typedef struct {
|
||||
uint64_t v0[4];
|
||||
uint64_t v1[4];
|
||||
uint64_t mul0[4];
|
||||
uint64_t mul1[4];
|
||||
} HighwayHashState;
|
||||
|
||||
static void HighwayHashReset(const uint64_t key[4], HighwayHashState *state) {
|
||||
state->mul0[0] = 0xdbe6d5d5fe4cce2full;
|
||||
state->mul0[1] = 0xa4093822299f31d0ull;
|
||||
state->mul0[2] = 0x13198a2e03707344ull;
|
||||
state->mul0[3] = 0x243f6a8885a308d3ull;
|
||||
state->mul1[0] = 0x3bd39e10cb0ef593ull;
|
||||
state->mul1[1] = 0xc0acf169b5f18a8cull;
|
||||
state->mul1[2] = 0xbe5466cf34e90c6cull;
|
||||
state->mul1[3] = 0x452821e638d01377ull;
|
||||
state->v0[0] = state->mul0[0] ^ key[0];
|
||||
state->v0[1] = state->mul0[1] ^ key[1];
|
||||
state->v0[2] = state->mul0[2] ^ key[2];
|
||||
state->v0[3] = state->mul0[3] ^ key[3];
|
||||
state->v1[0] = state->mul1[0] ^ ((key[0] >> 32) | (key[0] << 32));
|
||||
state->v1[1] = state->mul1[1] ^ ((key[1] >> 32) | (key[1] << 32));
|
||||
state->v1[2] = state->mul1[2] ^ ((key[2] >> 32) | (key[2] << 32));
|
||||
state->v1[3] = state->mul1[3] ^ ((key[3] >> 32) | (key[3] << 32));
|
||||
}
|
||||
|
||||
static void ZipperMergeAndAdd(const uint64_t v1, const uint64_t v0,
|
||||
uint64_t *add1, uint64_t *add0) {
|
||||
*add0 += (((v0 & 0xff000000ull) | (v1 & 0xff00000000ull)) >> 24) |
|
||||
(((v0 & 0xff0000000000ull) | (v1 & 0xff000000000000ull)) >> 16) |
|
||||
(v0 & 0xff0000ull) | ((v0 & 0xff00ull) << 32) |
|
||||
((v1 & 0xff00000000000000ull) >> 8) | (v0 << 56);
|
||||
*add1 += (((v1 & 0xff000000ull) | (v0 & 0xff00000000ull)) >> 24) |
|
||||
(v1 & 0xff0000ull) | ((v1 & 0xff0000000000ull) >> 16) |
|
||||
((v1 & 0xff00ull) << 24) | ((v0 & 0xff000000000000ull) >> 8) |
|
||||
((v1 & 0xffull) << 48) | (v0 & 0xff00000000000000ull);
|
||||
}
|
||||
|
||||
static void Update(const uint64_t lanes[4], HighwayHashState *state) {
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
state->v1[i] += state->mul0[i] + lanes[i];
|
||||
state->mul0[i] ^= (state->v1[i] & 0xffffffff) * (state->v0[i] >> 32);
|
||||
state->v0[i] += state->mul1[i];
|
||||
state->mul1[i] ^= (state->v0[i] & 0xffffffff) * (state->v1[i] >> 32);
|
||||
}
|
||||
ZipperMergeAndAdd(state->v1[1], state->v1[0], &state->v0[1], &state->v0[0]);
|
||||
ZipperMergeAndAdd(state->v1[3], state->v1[2], &state->v0[3], &state->v0[2]);
|
||||
ZipperMergeAndAdd(state->v0[1], state->v0[0], &state->v1[1], &state->v1[0]);
|
||||
ZipperMergeAndAdd(state->v0[3], state->v0[2], &state->v1[3], &state->v1[2]);
|
||||
}
|
||||
|
||||
static uint64_t Read64(const uint8_t *src) {
|
||||
return (uint64_t)src[0] | ((uint64_t)src[1] << 8) | ((uint64_t)src[2] << 16) |
|
||||
((uint64_t)src[3] << 24) | ((uint64_t)src[4] << 32) |
|
||||
((uint64_t)src[5] << 40) | ((uint64_t)src[6] << 48) |
|
||||
((uint64_t)src[7] << 56);
|
||||
}
|
||||
|
||||
static void HighwayHashUpdatePacket(const uint8_t *packet,
|
||||
HighwayHashState *state) {
|
||||
uint64_t lanes[4];
|
||||
lanes[0] = Read64(packet + 0);
|
||||
lanes[1] = Read64(packet + 8);
|
||||
lanes[2] = Read64(packet + 16);
|
||||
lanes[3] = Read64(packet + 24);
|
||||
Update(lanes, state);
|
||||
}
|
||||
|
||||
static void Rotate32By(uint64_t count, uint64_t lanes[4]) {
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
uint32_t half0 = lanes[i] & 0xffffffff;
|
||||
uint32_t half1 = (lanes[i] >> 32);
|
||||
lanes[i] = (half0 << count) | (half0 >> (32 - count));
|
||||
lanes[i] |= (uint64_t)((half1 << count) | (half1 >> (32 - count))) << 32;
|
||||
}
|
||||
}
|
||||
|
||||
static void HighwayHashUpdateRemainder(const uint8_t *bytes,
|
||||
const size_t size_mod32,
|
||||
HighwayHashState *state) {
|
||||
int i;
|
||||
const size_t size_mod4 = size_mod32 & 3;
|
||||
const uint8_t *remainder = bytes + (size_mod32 & ~3);
|
||||
uint8_t packet[32] = {0};
|
||||
for (i = 0; i < 4; ++i) {
|
||||
state->v0[i] += ((uint64_t)size_mod32 << 32) + size_mod32;
|
||||
}
|
||||
Rotate32By(size_mod32, state->v1);
|
||||
for (i = 0; i < remainder - bytes; i++) {
|
||||
packet[i] = bytes[i];
|
||||
}
|
||||
if (size_mod32 & 16) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
packet[28 + i] = remainder[i + size_mod4 - 4];
|
||||
}
|
||||
} else {
|
||||
if (size_mod4) {
|
||||
packet[16 + 0] = remainder[0];
|
||||
packet[16 + 1] = remainder[size_mod4 >> 1];
|
||||
packet[16 + 2] = remainder[size_mod4 - 1];
|
||||
}
|
||||
}
|
||||
HighwayHashUpdatePacket(packet, state);
|
||||
}
|
||||
|
||||
static void Permute(const uint64_t v[4], uint64_t *permuted) {
|
||||
permuted[0] = (v[2] >> 32) | (v[2] << 32);
|
||||
permuted[1] = (v[3] >> 32) | (v[3] << 32);
|
||||
permuted[2] = (v[0] >> 32) | (v[0] << 32);
|
||||
permuted[3] = (v[1] >> 32) | (v[1] << 32);
|
||||
}
|
||||
|
||||
static void PermuteAndUpdate(HighwayHashState *state) {
|
||||
uint64_t permuted[4];
|
||||
Permute(state->v0, permuted);
|
||||
Update(permuted, state);
|
||||
}
|
||||
|
||||
static uint64_t HighwayHashFinalize64(HighwayHashState *state) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) PermuteAndUpdate(state);
|
||||
return state->v0[0] + state->v1[0] + state->mul0[0] + state->mul1[0];
|
||||
}
|
||||
|
||||
static void ProcessAll(const uint8_t *data, size_t size, const uint64_t key[4],
|
||||
HighwayHashState *state) {
|
||||
size_t i;
|
||||
HighwayHashReset(key, state);
|
||||
for (i = 0; i + 32 <= size; i += 32) {
|
||||
HighwayHashUpdatePacket(data + i, state);
|
||||
}
|
||||
if ((size & 31) != 0) HighwayHashUpdateRemainder(data + i, size & 31, state);
|
||||
}
|
||||
|
||||
uint64_t HighwayHash64(const uint8_t *data, size_t size,
|
||||
const uint64_t key[4]) {
|
||||
HighwayHashState state;
|
||||
ProcessAll(data, size, key, &state);
|
||||
return HighwayHashFinalize64(&state);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_STR_HIGHWAYHASH64_H_
|
||||
#define COSMOPOLITAN_LIBC_STR_HIGHWAYHASH64_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
uint64_t HighwayHash64(const uint8_t *, size_t, const uint64_t[4]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_STR_HIGHWAYHASH64_H_ */
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_STR_KNUTHMULTIPLICATIVEHASH_H_
|
||||
#define COSMOPOLITAN_LIBC_STR_KNUTHMULTIPLICATIVEHASH_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
forceinline uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) {
|
||||
size_t i;
|
||||
uint32_t h;
|
||||
const uint32_t kPhiPrime = 0x9e3779b1;
|
||||
const unsigned char *p = (const unsigned char *)buf;
|
||||
for (h = i = 0; i < size; i++) h = (p[i] + h) * kPhiPrime;
|
||||
return h;
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_STR_KNUTHMULTIPLICATIVEHASH_H_ */
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/knuthmultiplicativehash.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
|
@ -49,9 +48,3 @@ BENCH(crc32c, bench) {
|
|||
EZBENCH2("crc32c", donothing,
|
||||
EXPROPRIATE(crc32c(0, VEIL("r", TESTSTR), sizeof(TESTSTR) - 1)));
|
||||
}
|
||||
|
||||
BENCH(KnuthMultiplicativeHash32, bench) {
|
||||
EZBENCH2("KMP", donothing,
|
||||
EXPROPRIATE(KnuthMultiplicativeHash32(VEIL("r", TESTSTR),
|
||||
sizeof(TESTSTR) - 1)));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*-*- 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 2017 Google LLC │
|
||||
│ │
|
||||
│ Licensed under the Apache License, Version 2.0 (the "License"); │
|
||||
│ you may not use this file except in compliance with the License. │
|
||||
│ You may obtain a copy of the License at │
|
||||
│ │
|
||||
│ http://www.apache.org/licenses/LICENSE-2.0 │
|
||||
│ │
|
||||
│ Unless required by applicable law or agreed to in writing, software │
|
||||
│ distributed under the License is distributed on an "AS IS" BASIS, │
|
||||
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
|
||||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/inttypes.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/highwayhash64.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define kMaxSize 64
|
||||
|
||||
static const uint64_t kTestKey1[4] = {
|
||||
0x0706050403020100ull,
|
||||
0x0F0E0D0C0B0A0908ull,
|
||||
0x1716151413121110ull,
|
||||
0x1F1E1D1C1B1A1918ull,
|
||||
};
|
||||
|
||||
static const uint64_t kTestKey2[4] = {1ull, 2ull, 3ull, 4ull};
|
||||
|
||||
const uint64_t kExpected64[kMaxSize + 1] = {
|
||||
0x907A56DE22C26E53ull, 0x7EAB43AAC7CDDD78ull, 0xB8D0569AB0B53D62ull,
|
||||
0x5C6BEFAB8A463D80ull, 0xF205A46893007EDAull, 0x2B8A1668E4A94541ull,
|
||||
0xBD4CCC325BEFCA6Full, 0x4D02AE1738F59482ull, 0xE1205108E55F3171ull,
|
||||
0x32D2644EC77A1584ull, 0xF6E10ACDB103A90Bull, 0xC3BBF4615B415C15ull,
|
||||
0x243CC2040063FA9Cull, 0xA89A58CE65E641FFull, 0x24B031A348455A23ull,
|
||||
0x40793F86A449F33Bull, 0xCFAB3489F97EB832ull, 0x19FE67D2C8C5C0E2ull,
|
||||
0x04DD90A69C565CC2ull, 0x75D9518E2371C504ull, 0x38AD9B1141D3DD16ull,
|
||||
0x0264432CCD8A70E0ull, 0xA9DB5A6288683390ull, 0xD7B05492003F028Cull,
|
||||
0x205F615AEA59E51Eull, 0xEEE0C89621052884ull, 0x1BFC1A93A7284F4Full,
|
||||
0x512175B5B70DA91Dull, 0xF71F8976A0A2C639ull, 0xAE093FEF1F84E3E7ull,
|
||||
0x22CA92B01161860Full, 0x9FC7007CCF035A68ull, 0xA0C964D9ECD580FCull,
|
||||
0x2C90F73CA03181FCull, 0x185CF84E5691EB9Eull, 0x4FC1F5EF2752AA9Bull,
|
||||
0xF5B7391A5E0A33EBull, 0xB9B84B83B4E96C9Cull, 0x5E42FE712A5CD9B4ull,
|
||||
0xA150F2F90C3F97DCull, 0x7FA522D75E2D637Dull, 0x181AD0CC0DFFD32Bull,
|
||||
0x3889ED981E854028ull, 0xFB4297E8C586EE2Dull, 0x6D064A45BB28059Cull,
|
||||
0x90563609B3EC860Cull, 0x7AA4FCE94097C666ull, 0x1326BAC06B911E08ull,
|
||||
0xB926168D2B154F34ull, 0x9919848945B1948Dull, 0xA2A98FC534825EBEull,
|
||||
0xE9809095213EF0B6ull, 0x582E5483707BC0E9ull, 0x086E9414A88A6AF5ull,
|
||||
0xEE86B98D20F6743Dull, 0xF89B7FF609B1C0A7ull, 0x4C7D9CC19E22C3E8ull,
|
||||
0x9A97005024562A6Full, 0x5DD41CF423E6EBEFull, 0xDF13609C0468E227ull,
|
||||
0x6E0DA4F64188155Aull, 0xB755BA4B50D7D4A1ull, 0x887A3484647479BDull,
|
||||
0xAB8EEBE9BF2139A0ull, 0x75542C5D4CD2A6FFull,
|
||||
};
|
||||
|
||||
uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) {
|
||||
size_t i;
|
||||
uint32_t h;
|
||||
const uint32_t kPhiPrime = 0x9e3779b1;
|
||||
const unsigned char *p = (const unsigned char *)buf;
|
||||
for (h = i = 0; i < size; i++) h = (p[i] + h) * kPhiPrime;
|
||||
return h;
|
||||
}
|
||||
|
||||
void TestHash64(uint64_t expected, const uint8_t *data, size_t size,
|
||||
const uint64_t *key) {
|
||||
uint64_t hash = HighwayHash64(data, size, key);
|
||||
if (expected != hash) {
|
||||
printf("Test failed: expected %016" PRIx64 ", got %016" PRIx64
|
||||
", size: %d\n",
|
||||
expected, hash, (int)size);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(highwayhash64, test) {
|
||||
int i;
|
||||
uint8_t data[kMaxSize + 1] = {0};
|
||||
for (i = 0; i <= kMaxSize; i++) {
|
||||
data[i] = i;
|
||||
TestHash64(kExpected64[i], data, i, kTestKey1);
|
||||
}
|
||||
for (i = 0; i < 33; i++) {
|
||||
data[i] = 128 + i;
|
||||
}
|
||||
TestHash64(0x53c516cce478cad7ull, data, 33, kTestKey2);
|
||||
}
|
||||
|
||||
BENCH(highwayhash64, bench) {
|
||||
EZBENCH2("crc32c small", donothing, crc32c(0, "hello", 5));
|
||||
EZBENCH2("knuth small", donothing,
|
||||
EXPROPRIATE(KnuthMultiplicativeHash32(VEIL("r", "hello"), 5)));
|
||||
EZBENCH2("highwayhash64 small", donothing,
|
||||
HighwayHash64((void *)"hello", 5, kTestKey1));
|
||||
EZBENCH2("crc32c big", donothing, crc32c(0, kHyperion, kHyperionSize));
|
||||
EZBENCH2("knuth big", donothing,
|
||||
EXPROPRIATE(
|
||||
KnuthMultiplicativeHash32(VEIL("r", kHyperion), kHyperionSize)));
|
||||
EZBENCH2("highwayhash64 big", donothing,
|
||||
HighwayHash64((void *)kHyperion, kHyperionSize, kTestKey1));
|
||||
}
|
|
@ -156,6 +156,7 @@ struct As {
|
|||
int inpath; // strings
|
||||
int outpath; // strings
|
||||
int counter;
|
||||
int pcrelative;
|
||||
bool inhibiterr;
|
||||
bool inhibitwarn;
|
||||
struct Ints {
|
||||
|
@ -1320,14 +1321,14 @@ static int ParseEquality(struct As *a, int *rest, int i) {
|
|||
if (IsPunct(a, i, '=' << 8 | '=')) {
|
||||
y = ParseRelational(a, &i, i + 1);
|
||||
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
|
||||
a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x & 63;
|
||||
a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x;
|
||||
} else {
|
||||
x = NewBinary(a, EX_EQ, x, y);
|
||||
}
|
||||
} else if (IsPunct(a, i, '!' << 8 | '=')) {
|
||||
y = ParseRelational(a, &i, i + 1);
|
||||
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
|
||||
a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x & 63;
|
||||
a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x;
|
||||
} else {
|
||||
x = NewBinary(a, EX_NE, x, y);
|
||||
}
|
||||
|
@ -1878,73 +1879,44 @@ static void OnSize(struct As *a, struct Slice s) {
|
|||
a->symbols.p[i].size = GetInt(a);
|
||||
}
|
||||
|
||||
static void OnInternal(struct As *a, struct Slice s) {
|
||||
static void OpVisibility(struct As *a, int visibility) {
|
||||
int i;
|
||||
while (IsSlice(a, a->i)) {
|
||||
i = GetSymbol(a, a->things.p[a->i++].i);
|
||||
a->symbols.p[i].stv = STV_INTERNAL;
|
||||
a->symbols.p[i].stv = visibility;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnInternal(struct As *a, struct Slice s) {
|
||||
OpVisibility(a, STV_INTERNAL);
|
||||
}
|
||||
|
||||
static void OnHidden(struct As *a, struct Slice s) {
|
||||
int i;
|
||||
while (IsSlice(a, a->i)) {
|
||||
i = GetSymbol(a, a->things.p[a->i++].i);
|
||||
a->symbols.p[i].stv = STV_HIDDEN;
|
||||
}
|
||||
OpVisibility(a, STV_HIDDEN);
|
||||
}
|
||||
|
||||
static void OnProtected(struct As *a, struct Slice s) {
|
||||
OpVisibility(a, STV_PROTECTED);
|
||||
}
|
||||
|
||||
static void OpBind(struct As *a, int bind) {
|
||||
int i;
|
||||
while (IsSlice(a, a->i)) {
|
||||
i = GetSymbol(a, a->things.p[a->i++].i);
|
||||
a->symbols.p[i].stv = STV_PROTECTED;
|
||||
a->symbols.p[i].stb = bind;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnLocal(struct As *a, struct Slice s) {
|
||||
int i;
|
||||
while (IsSlice(a, a->i)) {
|
||||
i = GetSymbol(a, a->things.p[a->i++].i);
|
||||
a->symbols.p[i].stb = STB_LOCAL;
|
||||
}
|
||||
OpBind(a, STB_LOCAL);
|
||||
}
|
||||
|
||||
static void OnWeak(struct As *a, struct Slice s) {
|
||||
int i;
|
||||
while (IsSlice(a, a->i)) {
|
||||
i = GetSymbol(a, a->things.p[a->i++].i);
|
||||
a->symbols.p[i].stb = STB_WEAK;
|
||||
}
|
||||
OpBind(a, STB_WEAK);
|
||||
}
|
||||
|
||||
static void OnGlobal(struct As *a, struct Slice s) {
|
||||
int i;
|
||||
while (IsSlice(a, a->i)) {
|
||||
i = GetSymbol(a, a->things.p[a->i++].i);
|
||||
a->symbols.p[i].stb = STB_GLOBAL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSizableOp(const char *op, struct Slice s) {
|
||||
int n = strlen(op);
|
||||
if (n == s.n) return !memcmp(op, s.p, n);
|
||||
if (n + 1 == s.n && !memcmp(op, s.p, n)) {
|
||||
switch (s.p[n]) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
case 'w':
|
||||
case 'W':
|
||||
case 'l':
|
||||
case 'L':
|
||||
case 'q':
|
||||
case 'Q':
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
OpBind(a, STB_GLOBAL);
|
||||
}
|
||||
|
||||
static int GetOpSize(struct As *a, struct Slice s, int modrm, int i) {
|
||||
|
@ -2183,18 +2155,21 @@ static void EmitModrm(struct As *a, int reg, int modrm, int disp) {
|
|||
if (modrm & ISREG) {
|
||||
EmitByte(a, 0300 | reg | modrm & 7);
|
||||
} else {
|
||||
if (modrm & (HASBASE | HASINDEX)) {
|
||||
if (modrm & ISRIP) {
|
||||
EmitByte(a, 005 | reg);
|
||||
} else {
|
||||
EmitByte(a, 0204 | reg); // suboptimal
|
||||
EmitByte(a, modrm);
|
||||
}
|
||||
if (modrm & ISRIP) {
|
||||
EmitByte(a, 005 | reg);
|
||||
} else if (modrm & (HASBASE | HASINDEX)) {
|
||||
EmitByte(a, 0204 | reg); // suboptimal
|
||||
EmitByte(a, modrm);
|
||||
} else {
|
||||
EmitByte(a, 004 | reg);
|
||||
EmitByte(a, 045);
|
||||
}
|
||||
EmitExpr(a, disp, R_X86_64_32S, EmitLong);
|
||||
EmitExpr(
|
||||
a, disp,
|
||||
a->pcrelative && ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX)))
|
||||
? a->pcrelative
|
||||
: R_X86_64_32S,
|
||||
EmitLong);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2691,7 +2666,9 @@ static void OnCall(struct As *a, struct Slice s) {
|
|||
if (IsPunct(a, a->i, '*')) ++a->i;
|
||||
modrm = RemoveRexw(ParseModrm(a, &disp));
|
||||
if (modrm & (ISREG | ISRIP | HASINDEX | HASBASE)) {
|
||||
if (modrm & ISRIP) a->pcrelative = R_X86_64_GOTPCRELX;
|
||||
EmitRexOpModrm(a, 0xFF, 2, modrm, disp, 0);
|
||||
a->pcrelative = 0;
|
||||
} else {
|
||||
EmitByte(a, 0xE8);
|
||||
EmitExpr(a, disp, R_X86_64_PC32, EmitLong);
|
||||
|
@ -2703,7 +2680,12 @@ static noinline void OpJmpImpl(struct As *a, int cc) {
|
|||
if (IsPunct(a, a->i, '*')) ++a->i;
|
||||
modrm = RemoveRexw(ParseModrm(a, &disp));
|
||||
if (cc == -1) {
|
||||
if ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX))) {
|
||||
modrm |= ISRIP;
|
||||
a->pcrelative = R_X86_64_GOTPCRELX;
|
||||
}
|
||||
EmitRexOpModrm(a, 0xFF, 4, modrm, disp, 0);
|
||||
a->pcrelative = 0;
|
||||
} else {
|
||||
EmitByte(a, 0x0F);
|
||||
EmitByte(a, 0x80 + cc);
|
||||
|
@ -3795,6 +3777,15 @@ static void Write32(char b[4], int x) {
|
|||
b[3] = x >> 030;
|
||||
}
|
||||
|
||||
static void MarkUndefinedSymbolsGlobal(struct As *a) {
|
||||
int i;
|
||||
for (i = 0; i < a->symbols.n; ++i) {
|
||||
if (!a->symbols.p[i].section && a->symbols.p[i].stb == STB_LOCAL) {
|
||||
a->symbols.p[i].stb = STB_GLOBAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void MarkUsedSymbols(struct As *a, int i) {
|
||||
if (i == -1) return;
|
||||
MarkUsedSymbols(a, a->exprs.p[i].lhs);
|
||||
|
@ -3939,7 +3930,9 @@ void Assembler(int argc, char *argv[]) {
|
|||
/* PrintThings(a); */
|
||||
Assemble(a);
|
||||
Evaluate(a);
|
||||
MarkUndefinedSymbolsGlobal(a);
|
||||
Objectify(a, a->outpath);
|
||||
malloc_stats();
|
||||
FreeAssembler(a);
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,15 @@ o/$(MODE)/third_party/chibicc/as.com.dbg: \
|
|||
$(THIRD_PARTY_CHIBICC_A).pkg
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/hello.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_A) \
|
||||
$(APE) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/hello.chibicc.o \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/chibicc.o: \
|
||||
CPPFLAGS += $(THIRD_PARTY_CHIBICC_DEFINES)
|
||||
|
||||
|
|
|
@ -0,0 +1,802 @@
|
|||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
char g3 = 3;
|
||||
short g4 = 4;
|
||||
int g5 = 5;
|
||||
long g6 = 6;
|
||||
int g9[3] = {0, 1, 2};
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} g11[2] = {{1, 2}, {3, 4}};
|
||||
struct {
|
||||
int a[2];
|
||||
} g12[2] = {{{1, 2}}};
|
||||
union {
|
||||
int a;
|
||||
char b[8];
|
||||
} g13[2] = {0x01020304, 0x05060708};
|
||||
char g17[] = "foobar";
|
||||
char g18[10] = "foobar";
|
||||
char g19[3] = "foobar";
|
||||
char *g20 = g17 + 0;
|
||||
char *g21 = g17 + 3;
|
||||
char *g22 = &g17 - 3;
|
||||
char *g23[] = {g17 + 0, g17 + 3, g17 - 3};
|
||||
int g24 = 3;
|
||||
int *g25 = &g24;
|
||||
int g26[3] = {1, 2, 3};
|
||||
int *g27 = g26 + 1;
|
||||
int *g28 = &g11[1].a;
|
||||
long g29 = (long)(long)g26;
|
||||
struct {
|
||||
struct {
|
||||
int a[3];
|
||||
} a;
|
||||
} g30 = {{{1, 2, 3}}};
|
||||
int *g31 = g30.a.a;
|
||||
struct {
|
||||
int a[2];
|
||||
} g40[2] = {{1, 2}, 3, 4};
|
||||
struct {
|
||||
int a[2];
|
||||
} g41[2] = {1, 2, 3, 4};
|
||||
char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0};
|
||||
char *g44 = {"foo"};
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} g50 = {.b[2] = 0x12};
|
||||
union {
|
||||
int a;
|
||||
} g51[2] = {};
|
||||
|
||||
typedef char T60[];
|
||||
T60 g60 = {1, 2, 3};
|
||||
T60 g61 = {1, 2, 3, 4, 5, 6};
|
||||
|
||||
typedef struct {
|
||||
char a, b[];
|
||||
} T65;
|
||||
T65 g65 = {'f', 'o', 'o', 0};
|
||||
T65 g66 = {'f', 'o', 'o', 'b', 'a', 'r', 0};
|
||||
|
||||
int main() {
|
||||
ASSERT(1, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[2];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[2];
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
int x[3] = {};
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[3] = {};
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[3] = {};
|
||||
x[2];
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
int x[2][3] = {{1, 2}};
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[2][3] = {{1, 2}};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[2][3] = {{1, 2}};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT('a', ({
|
||||
char x[4] = "abc";
|
||||
x[0];
|
||||
}));
|
||||
ASSERT('c', ({
|
||||
char x[4] = "abc";
|
||||
x[2];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[4] = "abc";
|
||||
x[3];
|
||||
}));
|
||||
ASSERT('a', ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[0][3];
|
||||
}));
|
||||
ASSERT('d', ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT('f', ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
int x[] = {1, 2, 3, 4};
|
||||
x[3];
|
||||
}));
|
||||
ASSERT(16, ({
|
||||
int x[] = {1, 2, 3, 4};
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char x[] = "foo";
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
typedef char T[];
|
||||
T x = "foo";
|
||||
T y = "x";
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef char T[];
|
||||
T x = "foo";
|
||||
T y = "x";
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef char T[];
|
||||
T x = "x";
|
||||
T y = "foo";
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
typedef char T[];
|
||||
T x = "x";
|
||||
T y = "foo";
|
||||
sizeof(y);
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1, 2, 3};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1, 2, 3};
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1, 2, 3};
|
||||
x.c;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1};
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1};
|
||||
x.c;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[0].a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[0].b;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[1].a;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[1].b;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}};
|
||||
x[1].b;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x = {};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x = {};
|
||||
x.b;
|
||||
}));
|
||||
|
||||
ASSERT(5, ({
|
||||
typedef struct {
|
||||
int a, b, c, d, e, f;
|
||||
} T;
|
||||
T x = {1, 2, 3, 4, 5, 6};
|
||||
T y;
|
||||
y = x;
|
||||
y.e;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y, z;
|
||||
z = y = x;
|
||||
z.b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y = x;
|
||||
y.a;
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x = {0x01020304};
|
||||
x.b[0];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x = {0x01020304};
|
||||
x.b[1];
|
||||
}));
|
||||
|
||||
ASSERT(0x01020304, ({
|
||||
union {
|
||||
struct {
|
||||
char a, b, c, d;
|
||||
} e;
|
||||
int f;
|
||||
} x = {{4, 3, 2, 1}};
|
||||
x.f;
|
||||
}));
|
||||
|
||||
ASSERT(3, g3);
|
||||
ASSERT(4, g4);
|
||||
ASSERT(5, g5);
|
||||
ASSERT(6, g6);
|
||||
|
||||
ASSERT(0, g9[0]);
|
||||
ASSERT(1, g9[1]);
|
||||
ASSERT(2, g9[2]);
|
||||
|
||||
ASSERT(1, g11[0].a);
|
||||
ASSERT(2, g11[0].b);
|
||||
ASSERT(3, g11[1].a);
|
||||
ASSERT(4, g11[1].b);
|
||||
|
||||
ASSERT(1, g12[0].a[0]);
|
||||
ASSERT(2, g12[0].a[1]);
|
||||
ASSERT(0, g12[1].a[0]);
|
||||
ASSERT(0, g12[1].a[1]);
|
||||
|
||||
ASSERT(4, g13[0].b[0]);
|
||||
ASSERT(3, g13[0].b[1]);
|
||||
ASSERT(8, g13[1].b[0]);
|
||||
ASSERT(7, g13[1].b[1]);
|
||||
|
||||
ASSERT(7, sizeof(g17));
|
||||
ASSERT(10, sizeof(g18));
|
||||
ASSERT(3, sizeof(g19));
|
||||
|
||||
ASSERT(0, memcmp(g17, "foobar", 7));
|
||||
ASSERT(0, memcmp(g18, "foobar\0\0\0", 10));
|
||||
ASSERT(0, memcmp(g19, "foo", 3));
|
||||
|
||||
ASSERT(0, strcmp(g20, "foobar"));
|
||||
ASSERT(0, strcmp(g21, "bar"));
|
||||
ASSERT(0, strcmp(g22 + 3, "foobar"));
|
||||
|
||||
ASSERT(0, strcmp(g23[0], "foobar"));
|
||||
ASSERT(0, strcmp(g23[1], "bar"));
|
||||
ASSERT(0, strcmp(g23[2] + 3, "foobar"));
|
||||
|
||||
ASSERT(3, g24);
|
||||
ASSERT(3, *g25);
|
||||
ASSERT(2, *g27);
|
||||
ASSERT(3, *g28);
|
||||
ASSERT(1, *(int *)g29);
|
||||
|
||||
ASSERT(1, g31[0]);
|
||||
ASSERT(2, g31[1]);
|
||||
ASSERT(3, g31[2]);
|
||||
|
||||
ASSERT(1, g40[0].a[0]);
|
||||
ASSERT(2, g40[0].a[1]);
|
||||
ASSERT(3, g40[1].a[0]);
|
||||
ASSERT(4, g40[1].a[1]);
|
||||
|
||||
ASSERT(1, g41[0].a[0]);
|
||||
ASSERT(2, g41[0].a[1]);
|
||||
ASSERT(3, g41[1].a[0]);
|
||||
ASSERT(4, g41[1].a[1]);
|
||||
|
||||
ASSERT(0, ({
|
||||
int x[2][3] = {0, 1, 2, 3, 4, 5};
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[2][3] = {0, 1, 2, 3, 4, 5};
|
||||
x[1][0];
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {0, 1, 2, 3};
|
||||
x[0].a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {0, 1, 2, 3};
|
||||
x[1].a;
|
||||
}));
|
||||
|
||||
ASSERT(0, strcmp(g43[0], "foo"));
|
||||
ASSERT(0, strcmp(g43[1], "bar"));
|
||||
ASSERT(0, strcmp(g44, "foo"));
|
||||
|
||||
ASSERT(3, ({
|
||||
int a[] = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
};
|
||||
a[2];
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a, b, c;
|
||||
} x = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
union {
|
||||
int a;
|
||||
char b;
|
||||
} x = {
|
||||
1,
|
||||
};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
enum {
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
};
|
||||
z;
|
||||
}));
|
||||
|
||||
ASSERT(3, sizeof(g60));
|
||||
ASSERT(6, sizeof(g61));
|
||||
|
||||
ASSERT(4, sizeof(g65));
|
||||
ASSERT(7, sizeof(g66));
|
||||
ASSERT(0, strcmp(g65.b, "oo"));
|
||||
ASSERT(0, strcmp(g66.b, "oobar"));
|
||||
|
||||
ASSERT(4, ({
|
||||
int x[3] = {1, 2, 3, [0] = 4, 5};
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3] = {1, 2, 3, [0] = 4, 5};
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[3] = {1, 2, 3, [0] = 4, 5};
|
||||
x[2];
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(11, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
|
||||
x[0][2];
|
||||
}));
|
||||
ASSERT(12, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
|
||||
x[1][1];
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT(7, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[0][2];
|
||||
}));
|
||||
ASSERT(9, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[1][1];
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT(7, ((int[10]){[3] = 7})[3]);
|
||||
ASSERT(0, ((int[10]){[3] = 7})[4]);
|
||||
|
||||
ASSERT(10, ({
|
||||
char x[] = {[10 - 3] = 1, 2, 3};
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
char x[][2] = {[8][1] = 1, 2};
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(3, sizeof(g60));
|
||||
ASSERT(6, sizeof(g61));
|
||||
|
||||
ASSERT(4, sizeof(g65));
|
||||
ASSERT(7, sizeof(g66));
|
||||
ASSERT(0, strcmp(g65.b, "oo"));
|
||||
ASSERT(0, strcmp(g66.b, "oobar"));
|
||||
|
||||
ASSERT(7, ((int[10]){[3] 7})[3]);
|
||||
ASSERT(0, ((int[10]){[3] 7})[4]);
|
||||
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x = {1, 2, .b = 3, .a = 4};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x = {1, 2, .b = 3, .a = 4};
|
||||
x.b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c = 1, 2};
|
||||
x.c.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c = 1, 2};
|
||||
x.c.b;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c.b = 1};
|
||||
x.c.a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c.b = 1};
|
||||
x.c.b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a = 1, 2};
|
||||
x.a[0];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a = 1, 2};
|
||||
x.a[1];
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a[1] = 1};
|
||||
x.a[0];
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a[1] = 1};
|
||||
x.a[1];
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[0].a;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[0].b;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[1].a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[1].b;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[2].a;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[2].b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x};
|
||||
y[0].a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x};
|
||||
y[0].b;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x, [0].b = 3};
|
||||
y[0].a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x, [0].b = 3};
|
||||
y[0].b;
|
||||
}));
|
||||
|
||||
ASSERT(5, ((struct { int a, b, c; }){.c = 5}).c);
|
||||
ASSERT(0, ((struct { int a, b, c; }){.c = 5}).a);
|
||||
|
||||
ASSERT(0x00ff, ({
|
||||
union {
|
||||
unsigned short a;
|
||||
char b[2];
|
||||
} x = {.b[0] = 0xff};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(0xff00, ({
|
||||
union {
|
||||
unsigned short a;
|
||||
char b[2];
|
||||
} x = {.b[1] = 0xff};
|
||||
x.a;
|
||||
}));
|
||||
|
||||
ASSERT(0x00120000, g50.a);
|
||||
ASSERT(0, g51[0].a);
|
||||
ASSERT(0, g51[1].a);
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
};
|
||||
int c;
|
||||
} x = {1, 2, 3, .b = 4, 5};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
};
|
||||
int c;
|
||||
} x = {1, 2, 3, .b = 4, 5};
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
};
|
||||
int c;
|
||||
} x = {1, 2, 3, .b = 4, 5};
|
||||
x.c;
|
||||
}));
|
||||
|
||||
ASSERT(16, ({
|
||||
char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'};
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'};
|
||||
memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16);
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -17,7 +17,7 @@ COSMOPOLITAN_C_START_
|
|||
#define DLMALLOC_VERSION 20806
|
||||
|
||||
#ifndef FOOTERS
|
||||
#define FOOTERS !IsTrustworthy()
|
||||
#define FOOTERS !NoDebug()
|
||||
#endif
|
||||
|
||||
#define HAVE_MMAP 1
|
||||
|
|
|
@ -163,7 +163,6 @@ int main(int argc, char *argv[]) {
|
|||
CONCAT(&filenames.p, &filenames.i, &filenames.n, "/\n", 2);
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(elf = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
madvise(elf, st->st_size, MADV_WILLNEED);
|
||||
CHECK(IsElf64Binary(elf, st->st_size));
|
||||
CHECK_NOTNULL((strs = GetElfStringTable(elf, st->st_size)));
|
||||
CHECK_NOTNULL((syms = GetElfSymbolTable(elf, st->st_size, &symcount)));
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/alg/arraylist2.internal.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/knuthmultiplicativehash.internal.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/interner.h"
|
||||
|
@ -100,7 +100,7 @@ size_t internobj(struct Interner *t, const void *data, size_t size) {
|
|||
step = 0;
|
||||
item = data;
|
||||
it = (struct InternerObject *)t;
|
||||
hash = max(1, KnuthMultiplicativeHash32(data, size));
|
||||
hash = max(1, crc32c(0, data, size));
|
||||
do {
|
||||
/* it is written that triangle probe halts iff i<n/2 && popcnt(n)==1 */
|
||||
i = (hash + step * ((step + 1) >> 1)) & (it->n - 1);
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/knuthmultiplicativehash.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
|
|
|
@ -41,7 +41,7 @@ nodiscard char *tabpad(const char *s, unsigned width) {
|
|||
size_t i, l, need;
|
||||
l = strlen(s);
|
||||
need = width > l ? (roundup(width, 8) - l - 1) / 8 + 1 : 0;
|
||||
p = memcpy(malloc(l + need + 1), s, l);
|
||||
p = memcpy(malloc(l + need + 2), s, l);
|
||||
for (i = 0; i < need; ++i) p[l + i] = '\t';
|
||||
if (!need) {
|
||||
p[l] = ' ';
|
||||
|
|
|
@ -221,6 +221,7 @@ const struct IdName kElfSpecialSectionNames[] = {
|
|||
};
|
||||
|
||||
const struct IdName kElfNexgen32eRelocationNames[] = {
|
||||
{R_X86_64_NONE, "NONE"},
|
||||
{R_X86_64_64, "64"},
|
||||
{R_X86_64_PC32, "PC32"},
|
||||
{R_X86_64_GOT32, "GOT32"},
|
||||
|
|
Loading…
Reference in New Issue