aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cffc.hff3
-rw-r--r--src/idxmap.hff63
-rw-r--r--src/libc.hff1
-rw-r--r--src/llvm.cff6
-rw-r--r--src/parse.cff45
-rw-r--r--src/util.hff9
6 files changed, 105 insertions, 22 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index 6ae2c6d..4735828 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -1,6 +1,7 @@
import "libc.hff";
import "mem.hff";
import "option.hff";
+import "idxmap.hff";
/// Types
@@ -112,6 +113,7 @@ struct Type {
enumty *const Type,
tpargs [#]TeplArg,
flds [#]AggField,
+ idxmap IdxMap,
decls *Env,
},
BitF struct {
@@ -119,6 +121,7 @@ struct Type {
name *const u8,
id int,
flds [#]BitFField,
+ idxmap IdxMap,
},
VaList,
},
diff --git a/src/idxmap.hff b/src/idxmap.hff
new file mode 100644
index 0000000..7e5f066
--- /dev/null
+++ b/src/idxmap.hff
@@ -0,0 +1,63 @@
+import "util.hff";
+import "common.hff";
+
+// Round x up to power of 2
+fn roundup2(x u32) u32 {
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x++;
+ return x;
+}
+
+// Assume for less than this number of fields just doing a linear search is faster
+// than the IdxMap overhead (arbitrarily chosen).
+def IDXMAP_MIN_WORTHIT = 12;
+
+// A map of names to indeces for aggregates' (and bitfields') fields lookup.
+// Assumes a pointer to the field name is the first element of each
+// field structure (true for AggField and BitFField).
+struct IdxMap {
+ idxs *u16,
+ N u16,
+
+ def EMPTY = 0xFFFF;
+ fn init(this *IdxMap, n usize, fields *const void, fieldstride usize) void {
+ assert(n < EMPTY, "too many indeces");
+ this.N = roundup2(n * 2);
+ this.idxs = xcalloc(this.N, sizeof u16);
+ memset(this.idxs, 0xFF, this.N * sizeof u16);
+ for let i = 0z; i < n; ++i {
+ let name *const u8 = *as(**const u8)fields;
+ fields += fieldstride;
+ let h = cwhash32(as(uptrint)name);
+ let hidx = h & (this.N - 1);
+ for ;; {
+ if this.idxs[hidx] == EMPTY {
+ this.idxs[hidx] = i;
+ break;
+ }
+ hidx = (hidx + 1) & (this.N - 1);
+ }
+ }
+ }
+
+ fn find(this *const IdxMap, name *const u8, fields *void, fieldstride usize) *void {
+ let h = cwhash32(as(uptrint)name);
+ let hidx = h & (this.N - 1);
+ for ;; {
+ if this.idxs[hidx] == EMPTY {
+ return #null;
+ }
+ let idx = this.idxs[hidx];
+ let fname *const u8 = *as(**const u8)(fields + (idx * fieldstride));
+ if name == fname {
+ return fields + (idx * fieldstride);
+ }
+ hidx = (hidx + 1) & (this.N - 1);
+ }
+ }
+}
diff --git a/src/libc.hff b/src/libc.hff
index 533a933..57ff532 100644
--- a/src/libc.hff
+++ b/src/libc.hff
@@ -33,6 +33,7 @@ extern fn strncmp(a *const u8, b *const u8, usize) int;
extern fn memcmp(*const void, *const void, usize) int;
extern fn strcasecmp(a *const u8, b *const u8) int;
extern fn memcpy(*void, *const void, usize) *void;
+extern fn memset(*const void, int, usize) *void;
extern fn strcpy(*u8, *const u8) *u8;
extern fn strerror(int) *const u8;
extern fn strstr(*const u8, *const u8) *const u8;
diff --git a/src/llvm.cff b/src/llvm.cff
index bb07c77..83f3f10 100644
--- a/src/llvm.cff
+++ b/src/llvm.cff
@@ -557,12 +557,12 @@ fn genexpr(f *Fn, ex *Expr) Value {
} else if lhs.ty->is(:Ptr) {
let $t = mktmp(type);
gen("\t%v = getelementptr %t, %t %v, %t %v\n",
- &$t, lhs.ty.u.Ptr == ty_void ? ty_i8 : lhs.ty.u.Ptr, lhs.ty, &lhs, rhs.ty, &rhs);
+ &$t, lhs.ty.u.Ptr->is(:Void) ? ty_i8 : lhs.ty.u.Ptr, lhs.ty, &lhs, rhs.ty, &rhs);
res = $t;
} else if rhs.ty->is(:Ptr) {
let $t = mktmp(type);
gen("\t%v = getelementptr %t, %t %v, %t %v\n",
- &$t, rhs.ty.u.Ptr == ty_void ? ty_i8 : rhs.ty.u.Ptr, rhs.ty, &rhs, rhs.ty, &lhs);
+ &$t, rhs.ty.u.Ptr->is(:Void) ? ty_i8 : rhs.ty.u.Ptr, rhs.ty, &rhs, rhs.ty, &lhs);
res = $t;
} else {
assert(#f, "bad ad");
@@ -641,7 +641,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
case '+=';
let ref = genref(f, b.lhs);
- let rhs = convert(f, b.lhs.ty, b.rhs);
+ let rhs = b.lhs.ty->is(:Ptr) ? genexpr(f, b.rhs) : convert(f, b.lhs.ty, b.rhs);
let lhs0 = genload(f, ref);
let tmp = genadd(ex.ty, lhs0, rhs);
genstore(f, ref, tmp);
diff --git a/src/parse.cff b/src/parse.cff
index 7afec96..1b5fba3 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -730,23 +730,13 @@ fn isdecltokt(t TokT) bool {
struct BloomFilt {
bits [4]u32,
- fn _hash(x u32) u32 {
- // https://nullprogram.com/blog/2018/07/31/
- x ^= x >> 16;
- x *= 0x7feb352dU;
- x ^= x >> 15;
- x *= 0x846ca68bU;
- x ^= x >> 16;
- return x;
- }
-
def NHASH = 4;
def NBITS = 8 * sizeof BloomFilt;
fn add(this *BloomFilt, s *const u8) void {
let h u32 = as(uptrint)s;
for let i = 0; i < NHASH; ++i {
- h = _hash(h);
+ h = cwhash32(h);
let idx = h % NBITS;
this.bits[idx/32] |= 1u32 << (idx%32);
}
@@ -755,7 +745,7 @@ struct BloomFilt {
fn matches(this *const BloomFilt, s *const u8) bool {
let h u32 = as(uptrint)s;
for let i = 0; i < NHASH; ++i {
- h = _hash(h);
+ h = cwhash32(h);
let idx = h % NBITS;
if this.bits[idx/32] & (1u64 << (idx%32)) == 0 {
return #f;
@@ -840,6 +830,11 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c
ty.size = size;
ty.align = align;
agg.flds = flds.dat[0::flds.len];
+ if agg.flds.#len >= IDXMAP_MIN_WORTHIT {
+ agg.idxmap->init(agg.flds.#len, agg.flds.#ptr, sizeof AggField);
+ } else {
+ agg.idxmap = {};
+ }
*constty = *ty;
constty.konst = #t;
if kind == :EUnion {
@@ -890,7 +885,10 @@ fn parseagg(P *Parser, loc Loc, kind AggKind, name *const u8, retdecl **Decl) *c
}
fn findaggfield(ty *const Type, name *const u8) *AggField {
- foreach_ptr(fld, i, ty.u.Agg.flds) {
+ if ty.u.Agg.idxmap.idxs {
+ return ty.u.Agg.idxmap->find(name, ty.u.Agg.flds.#ptr, sizeof AggField);
+ }
+ foreach_ptr(fld, _, ty.u.Agg.flds) {
if fld.name == name {
return fld;
}
@@ -899,7 +897,10 @@ fn findaggfield(ty *const Type, name *const u8) *AggField {
}
fn findbitffield(ty *const Type, name *const u8) *BitFField {
- foreach_ptr(fld, i, ty.u.BitF.flds) {
+ if ty.u.BitF.idxmap.idxs {
+ return ty.u.BitF.idxmap->find(name, ty.u.BitF.flds.#ptr, sizeof BitFField);
+ }
+ foreach_ptr(fld, _, ty.u.BitF.flds) {
if fld.name == name {
return fld;
}
@@ -987,6 +988,11 @@ fn parsebitfield(P *Parser, name *const u8) *const Type {
}
bitf.flds = flds->move(P.alloc);
+ if bitf.flds.#len >= IDXMAP_MIN_WORTHIT {
+ bitf.idxmap->init(bitf.flds.#len, bitf.flds.#ptr, sizeof BitFField);
+ } else {
+ bitf.idxmap = {};
+ }
return interntype(&ty);
}
@@ -2303,11 +2309,12 @@ fn pexassign(P *Parser) Expr {
switch {
case !islvalue(&ex);
err(P, ex.loc, "left operand to assignment is not lvalue");
- case (typeof2(ex.ty, rhs.ty) == #null)
- and !((ex.ty->is(:Ptr) and rhs.ty->is(:Int)
- and (tok.t == '+=' or tok.t == '-=')));
+ case ex.ty->is(:Ptr) and rhs.ty->is(:Int) and (tok.t == '+=' or tok.t == '-=');
+ // pass
+ case typeof2(ex.ty, rhs.ty) == #null;
err(P, tok.loc, "invalid operands %t and %t for assignment operator %qT",
ex.ty, rhs.ty, &tok);
+
case okind == :IntFlo and (!isnumtype(ex.ty) or !isnumtype(rhs.ty));
err(P, tok.loc, "invalid operands %t and %t for assignment operator %qT",
ex.ty, rhs.ty, &tok);
@@ -2957,7 +2964,7 @@ fn doimport(P *Parser, loc Loc, path *const u8) [#]*Decl {
return d0.decls;
}
rpath = strcpy(malloc(strlen(rpath) + 1), rpath);
- let e = seen->put(rpath, { {}, #t });
+ seen->put(rpath, { {}, #t });
let P2 Parser #?;
parser_init(&P2, rpath);
P2.is_header = #t;
@@ -2965,7 +2972,7 @@ fn doimport(P *Parser, loc Loc, path *const u8) [#]*Decl {
P2.alloc = P.alloc;
let decls = parse4import(&P2);
- *e = { decls, #f };
+ seen->put(rpath, { decls, #f });
return decls;
}
diff --git a/src/util.hff b/src/util.hff
index 19c8c41..b8416f1 100644
--- a/src/util.hff
+++ b/src/util.hff
@@ -7,6 +7,15 @@ def FNV1A_INI u32 = 0x811c9dc5;
extern fn fnv1a(h u32, [#]const u8) u32;
extern fn fnv1a_s(h u32, *const u8) u32;
extern fn fnv1a_i(h u32, i64) u32;
+fn cwhash32(x u32) u32 {
+ // https://nullprogram.com/blog/2018/07/31/
+ x ^= x >> 16;
+ x *= 0x7feb352dU;
+ x ^= x >> 15;
+ x *= 0x846ca68bU;
+ x ^= x >> 16;
+ return x;
+}
extern fn addfilepath(*const u8) int;
extern fn fileid2path(id int) *const u8;
extern fn internstr(*const u8) *const u8;