diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cffc.hff | 3 | ||||
| -rw-r--r-- | src/idxmap.hff | 63 | ||||
| -rw-r--r-- | src/libc.hff | 1 | ||||
| -rw-r--r-- | src/llvm.cff | 6 | ||||
| -rw-r--r-- | src/parse.cff | 45 | ||||
| -rw-r--r-- | src/util.hff | 9 |
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; |