diff options
| -rw-r--r-- | src/cffc.hff | 1 | ||||
| -rw-r--r-- | src/llvm.cff | 14 | ||||
| -rw-r--r-- | src/parse.cff | 52 | ||||
| -rw-r--r-- | test/3.cff | 10 |
4 files changed, 75 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"); } @@ -1,5 +1,13 @@ import "libc.hff"; +bitfield ColorMaskFlags : u32 { + red 1 bool, + green 1 bool, + blue 1 bool, + alpha 1 bool, + id (8,3), +}; + fn sum(res int, ...) int { let ap va_list = {}; ap->start(); @@ -16,4 +24,6 @@ fn sum(res int, ...) int { extern fn main(argc int, argv **u8) int { printf("= %d\n", sum(1,2,3,42,-1,0)); + let rgb = ColorMaskFlags { .red: #t, .blue: #t, .id: 13}; + printf("0x%X\n", rgb.#raw); } |