aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-30 11:21:24 +0200
committerlemon <lsof@mailbox.org>2022-08-30 11:21:24 +0200
commitdeb6b8e1b6fc2543ff27f8d0c75789733374a2c1 (patch)
tree3d618e367bbf4a509e40eab8edc8bd9265b17f52 /src
parentdea68bafe81c40adf29e45630cfeceb97b91a630 (diff)
bitfield initializers
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff1
-rw-r--r--src/llvm.cff14
-rw-r--r--src/parse.cff52
3 files changed, 65 insertions, 2 deletions
diff --git a/src/cffc.hff b/src/cffc.hff
index 5eded01..06e87fb 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -202,6 +202,7 @@ struct Expr {
EUnionIni struct { var *const AggField, ex *Expr },
AggIni struct { flds [#]*const AggField, exs [#]Expr },
ArrIni struct { idxs [#]u32, exs [#]Expr, maxn i64 },
+ BitFIni struct { flds [#]*const BitFField, exs [#]Expr },
VaStart *Expr,
VaArg *Expr,
VaCopy struct { dst *Expr, src *Expr },
diff --git a/src/llvm.cff b/src/llvm.cff
index 97d1e3c..1a3bfef 100644
--- a/src/llvm.cff
+++ b/src/llvm.cff
@@ -933,6 +933,20 @@ fn genexpr(f *Fn, ex *Expr) Value {
gen("\t%v = load %t, %t %v\n", &val, ty, tmp.ty, &tmp);
return val;
+ case BitFIni ini;
+ assert(ex.ty->is(:BitF), "not bitf bitf ini");
+
+ let intty = ex.ty.u.BitF.intty;
+ let tmp = gentmp(ex.ty, "bitcast %t 0 to %t", ex.ty, ex.ty);
+ foreach(fld, i, ini.flds) {
+ let ex0 = convert(f, intty, &ini.exs[i]);
+ let fmask = fld.size == 64 ? ~0u64 : ((1u64 << fld.size) - 1);
+ let masked = gentmp(intty, "and %t %v, %I", intty, &ex0, fmask);
+ let shifted = gentmp(intty, "shl %t %v, %d", intty, &masked, fld.off);
+ tmp = gentmp(ex.ty, "or %t %v, %v", intty, &tmp, &shifted);
+ }
+ return tmp;
+
case EUnionIni ini;
let t0 = mktmp(mkptrtype(ex.ty));
let vidx = ini.var - ex.ty.u.Agg.flds.#ptr;
diff --git a/src/parse.cff b/src/parse.cff
index dbc8e29..ffe9a9d 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -827,6 +827,15 @@ fn findaggfield(ty *const Type, name *const u8) *AggField {
return #null;
}
+fn findbitffield(ty *const Type, name *const u8) *BitFField {
+ foreach_ptr(fld, i, ty.u.BitF.flds) {
+ if streq(fld.name, name) {
+ return fld;
+ }
+ }
+ return #null;
+}
+
fn parsebitfield(P *Parser, name *const u8) *const Type {
let ty Type = { .u: :BitF{} };
let bitf = &ty.u.BitF;
@@ -1246,6 +1255,43 @@ fn parsearrini(P *Parser, loc Loc, ty *const Type) Expr {
return { loc, ty, :ArrIni { idxs->move(P.alloc), exs->move(P.alloc), maxn }};
}
+fn parsebitfini(P *Parser, loc Loc, ty *const Type) Expr {
+ let loc = loc;
+ let tok Tok #?;
+ let flds Vec<*const BitFField> = {};
+ let exs Vec<Expr> = {};
+ let iota = 0u64;
+ while !lexmatch(P, &tok, '}') {
+ let fld *BitFField #?;
+ let ex Expr #?;
+ if lexmatch(P, &tok, '.') {
+ fld = findbitffield(ty, (tok = lexexpects(P, :ident, "field name")).u.ident);
+ lexexpect(P, ':');
+ if fld == #null {
+ fatal(P, tok.loc, "%t has no such field %qT", ty, &tok);
+ }
+ iota = (fld - ty.u.BitF.flds.#ptr) + 1;
+ } else {
+ if iota >= ty.u.BitF.flds.#len {
+ fatal(P, tok.loc, "excess elements in %t struct initializer", ty);
+ }
+ fld = &ty.u.BitF.flds[iota++];
+ }
+ P.targty = fld.ty;
+ ex = parseexpr(P);
+ if !typematchestarg(fld.ty, ex.ty) {
+ err(P, ex.loc, "incompatible element `%s' type in %t initializer (%t, expected %t)",
+ fld.name, ty, ex.ty, fld.ty);
+ }
+ flds->push(fld);
+ exs->push(ex);
+ if !lexmatch(P, &tok, ',') {
+ lexexpects(P, '}', "`,' or `}'");
+ break;
+ }
+ }
+ return { loc, ty, :BitFIni { flds->move(P.alloc), exs->move(P.alloc) }};
+}
fn mergetoktrees(alloc *Allocator, src *[#]Tok, n int) [#]Tok {
let total = 0z;
@@ -1412,7 +1458,7 @@ fn pexprimary(P *Parser) Expr {
fatal(P, tok.loc, "%t has no such decl %qT", ty, &tok);
}
continue;
- } else if !ty->is(:Agg) and !ty->is(:Enum) {
+ } else if !ty->is(:Agg) and !ty->is(:Enum) and !ty->is(:BitF) {
fatal(P, tok.loc, "type is not aggregate or enum");
} else {;
P.targty = ty;
@@ -1500,7 +1546,7 @@ fn pexprimary(P *Parser) Expr {
let off = 0z;
for ;; {
let name = (tok = lexexpect(P, :ident)).u.ident;
- let fld = findaggfield(ty, name);
+ let fld *AggField = ty->is(:Agg) ? findaggfield(ty, name) : #null;
if fld == #null {
fatal(P, tok.loc, "%t has no such field %qT", ty, &tok);
}
@@ -1585,6 +1631,8 @@ fn pexprimary(P *Parser) Expr {
ex = parseaggini(P, tok.loc, ty);
} else if ty->is(:Arr) {
ex = parsearrini(P, tok.loc, ty);
+ } else if ty->is(:BitF) {
+ ex = parsebitfini(P, tok.loc, ty);
} else {
fatal(P, tok.loc, "excess elements in initializer");
}