diff options
| author | 2022-08-26 22:08:52 +0200 | |
|---|---|---|
| committer | 2022-08-26 22:11:30 +0200 | |
| commit | 4a7d610bb9a441f6fb7f88caaa803c1c85e4fcfd (patch) | |
| tree | 3ac01c9be375f30efd09f0a670da74f886ad44ca | |
| parent | 475125eaba2852f88a4ee8d9be64c8b4964df3a9 (diff) | |
bitfields
| -rw-r--r-- | misc/cff.vim | 2 | ||||
| -rw-r--r-- | src/cffc.hff | 18 | ||||
| -rw-r--r-- | src/fmt.cff | 6 | ||||
| -rw-r--r-- | src/llvm.cff | 92 | ||||
| -rw-r--r-- | src/parse.cff | 172 | ||||
| -rw-r--r-- | src/type.cff | 6 | ||||
| -rw-r--r-- | test/2.cff | 17 | ||||
| -rw-r--r-- | x.ll | 309 |
8 files changed, 260 insertions, 362 deletions
diff --git a/misc/cff.vim b/misc/cff.vim index 0d64b5b..8bf358e 100644 --- a/misc/cff.vim +++ b/misc/cff.vim @@ -15,7 +15,7 @@ syn keyword Type i8 u8 i16 u16 i32 u32 i64 u64 syn keyword Type int uint isize usize iptrint uptrint syn keyword Type c_char c_long c_ulong c_llong c_ullong syn keyword Type bool intbool void f32 f64 typeof -syn keyword Structure struct enum union +syn keyword Structure struct enum union bitfield syn keyword Operator alignof sizeof as and or offsetof syn match PreProc "#\i*\>" diff --git a/src/cffc.hff b/src/cffc.hff index d1d423f..066c1f7 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -19,8 +19,8 @@ struct Loc { #[lax] enum TokT : i32 { // !sorted - kw_alignof, kw_and, kw_as, kw_break, kw_case, kw_const, - kw_continue, kw_def, kw_defer, kw_defmacro, kw_do, + kw_alignof, kw_and, kw_as, kw_bitfield, kw_break, kw_case, + kw_const, kw_continue, kw_def, kw_defer, kw_defmacro, kw_do, kw_else, kw_enum, kw_extern, kw_fn, kw_for, kw_if, kw_import, kw_let, kw_offsetof, kw_or, kw_return, kw_sizeof, kw_static, @@ -71,6 +71,12 @@ struct AggField { struct EnumVal { name *const u8, i i64 } +struct BitFField { + name *const u8, + ty *const Type, + off u16, size u16 +} + enum union TeplArg; struct Type { @@ -108,6 +114,12 @@ struct Type { flds [#]AggField, decls *Env, }, + BitF struct { + intty *const Type, + name *const u8, + id int, + flds [#]BitFField, + }, VaList, }, @@ -178,9 +190,11 @@ struct Expr { Cond struct { test *Expr, t *Expr, f *Expr }, Cast *Expr, Dot struct { lhs *Expr, fld *const AggField }, + BitDot struct { lhs *Expr, fld *const BitFField }, SLen *Expr, SPtr *Expr, EUTag *Expr, + BitRaw *Expr, Index struct { lhs *Expr, rhs *Expr }, Slice struct { lhs *Expr, begin *Expr, end *Expr }, Call struct { lhs *Expr, args [#]Expr }, diff --git a/src/fmt.cff b/src/fmt.cff index 8c0f6a4..6707222 100644 --- a/src/fmt.cff +++ b/src/fmt.cff @@ -198,6 +198,12 @@ extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) } else { ps("(anonymous)"); } + case BitF b; + if b.name { + ps(b.name); + } else { + ps("(anonymous)"); + } } } diff --git a/src/llvm.cff b/src/llvm.cff index 8ff32ba..32b1066 100644 --- a/src/llvm.cff +++ b/src/llvm.cff @@ -96,6 +96,7 @@ fn gen(fmt *const u8, ...) void { case Agg; genagg(ty); case Enum enu; pritype(enu.intty); + case BitF bitf; pritype(bitf.intty); case Fn f; gen("%t(", f.ret); foreach(ty, i, f.params) { @@ -202,6 +203,16 @@ fn mktmp(ty *const Type) Value { return Value{ty, :Tmp(tmpid++)}; } +defmacro gentmp(type, ...rest) [ + (do + let $tmp = mktmp(type); + gen("\t%v = ", $tmp); + gen(rest); + gen("\n"); + $tmp; + ) +] + fn convert(f *Fn, to *const Type, ex *Expr) Value; fn genexpr(f *Fn, ex *Expr) Value; static arena Arena = {}; @@ -235,20 +246,18 @@ fn genaddr(f *Fn, ex *Expr) Value { switch idx.lhs.ty.u { case Arr arrty; let arr = genaddr(f, idx.lhs); - lhs = mktmp(mkptrtype(ex.ty)); - gen("\t%v = getelementptr %t, %t %v, i32 0, i32 0\n", lhs, idx.lhs.ty, arr.ty, arr); + lhs = gentmp(mkptrtype(ex.ty), "getelementptr %t, %t %v, i32 0, i32 0", idx.lhs.ty, arr.ty, arr); case Ptr; lhs = genexpr(f, idx.lhs); case Slice child; let tmp = genexpr(f, idx.lhs); - lhs = mktmp(mkptrtype(child)); - gen("\t%v = extractvalue %t %v, 0\n", lhs, tmp.ty, tmp); + lhs = gentmp(mkptrtype(child), "extractvalue %t %v, 0", tmp.ty, tmp); case else; assert(#f, "index"); } - let rhs = genexpr(f, idx.rhs), - addr = mktmp(mkptrtype(ex.ty)); - gen("\t%v = getelementptr %t, %t %v, %t %v\n", addr, ex.ty, lhs.ty, lhs, rhs.ty, rhs); + let rhs = genexpr(f, idx.rhs); + let addr = gentmp(mkptrtype(ex.ty), "getelementptr %t, %t %v, %t %v", + ex.ty, lhs.ty, lhs, rhs.ty, rhs); return addr; case Dot dot; @@ -262,27 +271,30 @@ fn genaddr(f *Fn, ex *Expr) Value { } else { idx = dot.fld - dot.lhs.ty.u.Agg.flds.#ptr; } - let addr = mktmp(mkptrtype(ex.ty)); + let addr Value #?; + let ptrty = mkptrtype(ex.ty); switch lhs.ty.u.Ptr.u.Agg.kind { case :Struct; - gen("\t%v = getelementptr %t, %t %v, i32 0, i32 %d\n", addr, lhs.ty.u.Ptr, lhs.ty, lhs, idx); + addr = gentmp(ptrty, "getelementptr %t, %t %v, i32 0, i32 %d", + lhs.ty.u.Ptr, lhs.ty, lhs, idx); case :Union; - gen("\t%v = bitcast %t %v to %t", addr, lhs.ty, lhs, addr.ty); + addr = gentmp(ptrty, "bitcast %t %v to %t", lhs.ty, lhs, ptrty); case else let off int = dot.fld.off; - gen("\t%v = getelementptr i8, %t %v, i32 %d\n", addr, lhs.ty, lhs, off); + addr = gentmp(ptrty, "getelementptr i8, %t %v, i32 %d", lhs.ty, lhs, off); } return addr; case EUTag eex; let lhs = eex.ty->is(:Ptr) ? genexpr(f, eex) : genaddr(f, eex); - let addr = mktmp(mkptrtype(ex.ty)); - gen("\t%v = bitcast %t %v to %t", addr, lhs.ty, lhs, addr.ty); + let addr = gentmp(mkptrtype(ex.ty), "bitcast %t %v to %t", lhs.ty, lhs, mkptrtype(ex.ty)); return addr; + case BitRaw ex; + return genaddr(f, ex); + case AggIni ini; - let tmp = mktmp(mkptrtype(ex.ty)); - gen("\t%v = alloca %t\n", tmp, ex.ty); + let tmp = gentmp(mkptrtype(ex.ty), "alloca %t", ex.ty); gen("\tstore %t zeroinitializer, %t %v\n", ex.ty, tmp.ty, tmp); foreach(fld, i, ini.flds) { let fex = &ini.exs[i]; @@ -300,8 +312,7 @@ fn genaddr(f *Fn, ex *Expr) Value { case ArrIni ini; let ty = mkarrtype(ini.maxn, #f, ex.ty.u.Arr.child); - let tmp = mktmp(mkptrtype(ty)); - gen("\t%v = alloca %t\n", tmp, ty); + let tmp = gentmp(mkptrtype(ty), "alloca %t", ty); gen("\tstore %t zeroinitializer, %t %v\n", ty, tmp.ty, tmp); foreach(idx, i, ini.idxs) { let fex = &ini.exs[i]; @@ -524,10 +535,28 @@ fn genexpr(f *Fn, ex *Expr) Value { case '>'; gencmp(ty2->is(:Flo) ? "ogt" : ty2.u.Int.sgn ? "sgt" : "ugt"); case '>='; gencmp(ty2->is(:Flo) ? "oge" : ty2.u.Int.sgn ? "sge" : "uge"); case '='; - let addr = genaddr(f, b.lhs); - let rhs = convert(f, b.lhs.ty, b.rhs); - gen("\tstore %t %v, %t %v\n", ex.ty, rhs, addr.ty, addr); - return rhs; + if b.lhs.u.#tag != :BitDot { + let addr = genaddr(f, b.lhs); + let rhs = convert(f, b.lhs.ty, b.rhs); + gen("\tstore %t %v, %t %v\n", ex.ty, rhs, addr.ty, addr); + return rhs; + } else { + let dot = &b.lhs.u.BitDot; + let intty = dot.lhs.ty.u.BitF.intty; + let fld = dot.fld; + let srcmask = fld.size == 64 ? ~0u64 : ((1u64 << fld.size) - 1); + let addr = genaddr(f, dot.lhs); + let src0 = convert(f, intty, b.rhs); + let src = gentmp(intty, "and %t %v, %I", src0.ty, src0, srcmask); + let src = gentmp(intty, "shl %t %v, %d", src.ty, src, fld.off); + let dstmask = ~(srcmask << fld.off); + let lhs = gentmp(intty, "load %t, %t %v", intty, addr.ty, addr); + let lhs = gentmp(lhs.ty, "and %t %v, %I", lhs.ty, lhs, dstmask); + let raw = gentmp(lhs.ty, "or %t %v, %v", lhs.ty, lhs, src); + gen("\tstore %t %v, %t %v\n", raw.ty, raw, addr.ty, addr); + let res = gentmp(intty, "load %t, %t %v", fld.ty, addr.ty, addr); + return res; + } case '+='; let addr = genaddr(f, b.lhs); let rhs = convert(f, b.lhs.ty, b.rhs); @@ -696,6 +725,27 @@ fn genexpr(f *Fn, ex *Expr) Value { gen("\t%v = load %t, %t %v\n", tmp, ex.ty, addr.ty, addr); return tmp; + case BitRaw ex; + return genexpr(f, ex); + + case BitDot dot; + let fld = dot.fld; + let lhs = genexpr(f, dot.lhs); + let shifted = fld.off == 0 ? lhs : gentmp(lhs.ty, "lshr %t %v, %d", lhs.ty, lhs, fld.off); + let truncd = gentmp(#null, "trunc %t %v to i%d", shifted.ty, shifted, fld.size); + let res = mktmp(fld.ty); + switch { + case dot.fld.ty->is(:Bool); + let tmp = gentmp(ty_bool, "icmp ne i%d %v, 0", fld.size, truncd); + gen("\t%v = zext i1 %v to %t\n", res, tmp, res.ty); + + case dot.fld.ty->is(:Int); + gen("\t%v = %s i%d %v to %t\n", res, dot.fld.ty.u.Int.sgn ? "sext" : "zext", truncd, fld.size, lhs.ty); + + case else assert(#f, ""); + } + return res; + case SPtr sl; let sl = genexpr(f, sl); let ptr = mktmp(mkptrtype(sl.ty.u.Slice)); diff --git a/src/parse.cff b/src/parse.cff index d4b8b7a..364b23b 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -141,8 +141,8 @@ fn eatspaces(P *Parser) void { // !sorted extern static keyword2str [NUM_KEYWORDS]*const u8 = { - "alignof", "and", "as", "break", "case", "const", - "continue", "def", "defer", "defmacro", "do", + "alignof", "and", "as", "bitfield", "break", "case", + "const", "continue", "def", "defer", "defmacro", "do", "else", "enum", "extern", "fn", "for", "if", "import", "let", "offsetof", "or", "return", "sizeof", "static", @@ -400,6 +400,8 @@ fn lex(P *Parser) Tok { tok.t = '#ptr'; case streq(s, "#tag"); tok.t = '#tag'; + case streq(s, "#raw"); + tok.t = '#raw'; case streq(s, "#FILE"); tok.t = '#FIL'; case streq(s, "#LINE"); @@ -693,7 +695,7 @@ fn parseenum(P *Parser, name *const u8, lax bool) *const Type { fn isdecltokt(t TokT) bool { switch t { case :kw_fn, :kw_static, :kw_def, :kw_defmacro, :kw_struct, :kw_union, :kw_enum, - :kw_extern; + :kw_extern, :kw_bitfield; return #t; } return #f; @@ -824,6 +826,79 @@ fn findaggfield(ty *const Type, name *const u8) *AggField { return #null; } +fn parsebitfield(P *Parser, name *const u8) *const Type { + let ty Type = { .u: :BitF{} }; + let bitf = &ty.u.BitF; + let tok = lexexpect(P, ':'); + bitf.name = name; + bitf.intty = parsetype(P); + if !bitf.intty->is(:Int) or bitf.intty.u.Int.sgn { + fatal(P, tok.loc, "bitfield backing type must be unsigned integer (got %t)", bitf.intty); + } + ty.size = bitf.intty.size; + ty.align = bitf.intty.align; + lexexpect(P, '{'); + static id int = {}; + bitf.id = id++; + let flds Vec<BitFField> = {}; + let iota = 0u16; + while !lexmatch(P, &tok, '}') { + let name = (tok = lexexpects(P, :ident, "field name")).u.ident; + let off u16 = 0, size u16 = 0; + let ty = bitf.intty; + + if lexmatch(P, &tok, '(') { + // `(offset, size)` + let off_ex = parseexpr(P); + lexexpect(P, ','); + let size_ex = parseexpr(P); + lexmatch(P, &tok, ','); + lexexpect(P, ')'); + if !fold(&off_ex) or off_ex.u.#tag != :IntLit or off_ex.u.IntLit.i < 0 { + fatal(P, off_ex.loc, "expected non-negative constant integer for field offset"); + } + if !fold(&size_ex) or size_ex.u.#tag != :IntLit or size_ex.u.IntLit.i <= 0 { + fatal(P, size_ex.loc, "expected positive constant integer for field size"); + } + off = off_ex.u.IntLit.i; + size = size_ex.u.IntLit.i; + } else { + // `size` (offset is right after previous field) + let size_ex = parseexpr(P); + if !fold(&size_ex) or size_ex.u.#tag != :IntLit or size_ex.u.IntLit.i <= 0 { + fatal(P, size_ex.loc, "expected positive constant integer for field size"); + } + off = iota; + size = size_ex.u.IntLit.i; + } + + if (tok = lexpeek(P)).t == :ident and streq(tok.u.ident, "bool") { + lex(P); + ty = ty_bool; + } else if (tok = lexpeek(P)).t == :ident and streq(tok.u.ident, "signed") { + lex(P); + let signedty = *bitf.intty; + signedty.u.Int.sgn = #t; + ty = interntype(signedty); + } + + iota += size; + if off + size > bitf.intty.size * 8 { + err(P, tok.loc, "field `%s' outside %t bit range", name, bitf.intty); + } + + flds->push({ name, ty, off, size }); + + if !lexmatch(P, #null, ',') { + lexexpect(P, '}'); + break; + } + } + + bitf.flds = flds->move(P.alloc); + return interntype(ty); +} + fn typematchestarg(targ *const Type, ty *const Type) bool { if targ == ty { return #t; @@ -1077,9 +1152,12 @@ fn parsetype(P *Parser) *const Type { if lexmatch(P, #null, :kw_union) { return parseagg(P, tok.loc, :EUnion, #null, &decl); } else { - return parseenum(P, #null, #{lax?} #f); + return parseenum(P, #{name} #null, #{lax?} #f); } + case lexmatch(P, &tok, :kw_bitfield); + return parsebitfield(P, #{name} #null); + case else; fatal(P, tok.loc, "expected type (near %qT)", tok); } @@ -1093,7 +1171,7 @@ fn exprdup(alloc *Allocator, ex Expr) *Expr { return memcpy(alloc->alloc(sizeof(ex), alignof(ex)), &ex, sizeof(ex)); } -fn islvalue(ex Expr) bool { +fn islvalue(ex *Expr) bool { switch ex.u { case Symbol decl; return decl.u.#tag == :Let or decl.u.#tag == :Static; @@ -1103,6 +1181,10 @@ fn islvalue(ex Expr) bool { return #t; case Dot; return #t; + case BitDot bdot; + return islvalue(bdot.lhs); + case BitRaw ex; + return islvalue(ex); case EUTag; return #t; } @@ -1588,12 +1670,16 @@ fn pexpostfix(P *Parser) Expr { if !isnumtype(ex.ty) and !ex.ty->is(:Ptr) { fatal(P, ex.loc, "invalid operand to unary operator %qT (%t)", tok, ex.ty); } - if !islvalue(ex) { + if !islvalue(&ex) { err(P, ex.loc, "left operand to prefix %qT operator is not lvalue", tok); } if ex.ty.konst { err(P, ex.loc, "left operand to prefix %qT operator is const", tok); } + if ex.u.#tag == :BitDot { + err(P, ex.loc, "cannot apply post-%srement operator to bitfield value", + tok.t == '++' ? "inc" : "dec"); + } ex = { tok.loc, ex.ty, .u: :UnOp { tok.t == '++' ? :postinc : :postdec, exprdup(P.alloc, ex) @@ -1607,26 +1693,32 @@ fn pexpostfix(P *Parser) Expr { if ty->is(:Ptr) { ty = ty.u.Ptr; } - if !ty->is(:Agg) { - fatal(P, tok.loc, "left-hand-side is not an aggregate (%t)", ty); - } let konst = ty.konst; - ty = unconstify(ty); - let agg = &ty.u.Agg; - let fld *AggField = #null; - foreach(f, i, agg.flds) { - if streq(name, f.name) { - fld = &agg.flds[i]; - break; + switch ty.u { + case Agg *agg; + let fld *AggField = #null; + foreach(f, i, agg.flds) { + if streq(name, f.name) { + fld = &agg.flds[i]; + break; + } } + if fld == #null { fatal(P, tok.loc, "%t has no such field %qT", ty, tok); } + if fld.ty == #null { fatal(P, tok.loc, "field %qT has no type", tok); } + ex = { tok.loc, konst ? constify(fld.ty) : fld.ty, :Dot { exprdup(P.alloc, ex), fld }}; + case BitF *bitf; + let fld *BitFField = #null; + foreach(f, i, bitf.flds) { + if streq(name, f.name) { + fld = &bitf.flds[i]; + break; + } + } + if fld == #null { fatal(P, tok.loc, "%t has no such field %qT", ty, tok); } + ex = { tok.loc, konst ? constify(fld.ty) : fld.ty, :BitDot { exprdup(P.alloc, ex), fld }}; + case else + fatal(P, tok.loc, "left-hand-side is not an aggregate (%t)", ty); } - if fld == #null { - fatal(P, tok.loc, "%t has no such field %qT", ty, tok); - } - if fld.ty == #null { - fatal(P, tok.loc, "field %qT has no type", tok); - } - ex = { tok.loc, konst ? constify(fld.ty) : fld.ty, :Dot { exprdup(P.alloc, ex), fld }}; case lexmatch(P, &tok, '#ptr'); let ty = ex.ty; @@ -1658,6 +1750,17 @@ fn pexpostfix(P *Parser) Expr { let enumty = ty.u.Agg.enumty; ex = { tok.loc, ty.konst ? constify(enumty) : enumty, :EUTag(exprdup(P.alloc, ex)) }; + case lexmatch(P, &tok, '#raw'); + let ty = ex.ty; + if ty->is(:Ptr) { + ty = ty.u.Ptr; + } + if !ty->is(:BitF) { + fatal(P, ex.loc, "invalid operand to #raw (%t)", ex.ty); + } + let intty = ty.u.BitF.intty; + ex = { tok.loc, ty.konst ? constify(intty) : intty, :BitRaw(exprdup(P.alloc, ex)) }; + case lexpeek(P).t == '['; // sugar: expr.[idx] -> (*expr)[idx] if !ex.ty->is(:Ptr) { @@ -1709,7 +1812,7 @@ fn pexpostfix(P *Parser) Expr { ex = { ex.loc, ty, :UnOp{:deref, exprdup(P.alloc, ex)}}; case !exptr and metptr; - if !islvalue(ex) { + if !islvalue(&ex) { err(P, tok.loc, "cannot call `->%s' by reference, lhs is not an lvalue", name); } else if ty.konst and !recv.konst { err(P, tok.loc, "constness mismatch: method takes %t but got %t", recv0, ex.ty); @@ -1773,12 +1876,16 @@ fn pexprefix(P *Parser) Expr { if !isnumtype(ex.ty) and !ex.ty->is(:Ptr) { fatal(P, ex.loc, "invalid operand to unary operator %qT (%t)", tok, ex.ty); } - if !islvalue(ex) { + if !islvalue(&ex) { err(P, ex.loc, "left operand to prefix %qT operator is not lvalue", tok); } if ex.ty.konst { err(P, ex.loc, "left operand to prefix %qT operator is const", tok); } + if ex.u.#tag == :BitDot { + err(P, ex.loc, "cannot apply pre-%srement operator to bitfield value", + tok.t == '++' ? "inc" : "dec"); + } return { tok.loc, ex.ty, .u: :UnOp { tok.t == '++' ? :preinc : :predec, exprdup(P.alloc, ex) @@ -1805,7 +1912,7 @@ fn pexprefix(P *Parser) Expr { case lexmatch(P, &tok, '&'); let ex = pexprefix(P); let ty2 = interntype({ g_targ.ptrsize, .u: :Ptr(ex.ty) }); - if !islvalue(ex) and !(ex.u.#tag == :Symbol and ex.u.Symbol.u.#tag == :Fn) + if !islvalue(&ex) and !(ex.u.#tag == :Symbol and ex.u.Symbol.u.#tag == :Fn) and !(ex.u.#tag == :ZeroIni or ex.u.#tag == :AggIni or ex.u.#tag == :ArrIni) { err(P, ex.loc, "invalid operand to `&': not an lvalue"); } @@ -2027,7 +2134,7 @@ fn pexassign(P *Parser) Expr { } let rhs = pexcond(P); switch { - case !islvalue(ex); + 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) @@ -2035,6 +2142,8 @@ fn pexassign(P *Parser) Expr { err(P, ex.loc, "operands %t and %t to assignment operator %qT have incompatible types", ex.ty, rhs.ty, tok); + case okind != :Set and ex.u.#tag == :BitDot; + err(P, ex.loc, "cannot apply compound assignment operator to bitfield value"); case ex.ty.konst; err(P, ex.loc, "left operand to assignment is const"); } @@ -2289,7 +2398,7 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { seen->put(c.variant, tok.loc); if c.fld.ty != #null and lexmatch(P, &tok, '*') { - if !islvalue(test) { + if !islvalue(&test) { fatal(P, tok.loc, "cannot capture by pointer, test expression is not lvalue"); } c.captptr = #t; @@ -2320,7 +2429,7 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { } - return { loc, :EUSwitch { islvalue(test), test, cs->move(P.alloc), f }}; + return { loc, :EUSwitch { islvalue(&test), test, cs->move(P.alloc), f }}; } fn pstcswitch(P *Parser, loc Loc) Stmt { @@ -2914,6 +3023,11 @@ fn parsedecls(P *Parser, loc Loc, yield DeclYielder, yarg *void, toplevel bool) { name, tok.loc, .u: :Tepl(parsetepl(P, tok.loc, :Union, name)) }); } + case lexmatch(P, &tok, :kw_bitfield); + let name = lexexpect(P, :ident).u.ident; + let ty = parsebitfield(P, name); + decl = putdecl(P, loc, { name, loc, .u: :Ty(ty) }); + case lexmatch(P, &tok, :kw_static); struct Arg { P *Parser, diff --git a/src/type.cff b/src/type.cff index 214bda8..c7e76cc 100644 --- a/src/type.cff +++ b/src/type.cff @@ -43,6 +43,9 @@ struct TypeTraits { case Enum enu; h = fnv1a_i(h, enu.id); + + case BitF bitf; + h = fnv1a_i(h, bitf.id); } return h; @@ -97,6 +100,9 @@ struct TypeTraits { case Enum enu; return enu.id == b.u.Enum.id; + + case BitF bitf; + return bitf.id == b.u.BitF.id; } return #f; } diff --git a/test/2.cff b/test/2.cff new file mode 100644 index 0000000..8b512ea --- /dev/null +++ b/test/2.cff @@ -0,0 +1,17 @@ +import "libc.hff"; + +bitfield Foo : uint { + tag 3, + flag (3, 1) bool, + num 10 signed, +} + +extern fn main() int { + let foo Foo = {}; + printf("0x%X: %d, %d, %d\n", foo.#raw, foo.tag, foo.flag, foo.num); + foo.tag = 3; + foo.#raw += 1; + foo.flag = #t; + foo.num = -2; + printf("0x%X: %d, %d, %d\n", foo.#raw, foo.tag, foo.flag, foo.num); +} @@ -1,309 +0,0 @@ -target triple = "x86_64-pc-linux-gnu" -%.type.opaque = type opaque - -@xs.2 = internal global ptr zeroinitializer -define internal i32 @icmp.4(ptr %lhs, ptr %rhs, ptr %_) { -%lhs.0 = alloca ptr store ptr %lhs, ptr %lhs.0 -%rhs.1 = alloca ptr store ptr %rhs, ptr %rhs.1 -%_.2 = alloca ptr store ptr %_, ptr %_.2 - %lhs.3 = alloca i32 - %t1 = load ptr, ptr %lhs.0 - %t0 = bitcast ptr %t1 to ptr - %t2 = load i32, ptr %t0 - store i32 %t2, ptr %lhs.3 - %rhs.4 = alloca i32 - %t4 = load ptr, ptr %rhs.1 - %t3 = bitcast ptr %t4 to ptr - %t5 = load i32, ptr %t3 - store i32 %t5, ptr %rhs.4 - %t6 = load i32, ptr %lhs.3 - %t7 = load i32, ptr %rhs.4 - %t8 = sub i32 %t6, %t7 - ret i32 %t8 - ret i32 undef -} -define internal void @foo.5() { - ret void -} -define internal void @isort.3(ptr %xs, i64 %n) { -%xs.0 = alloca ptr store ptr %xs, ptr %xs.0 -%n.1 = alloca i64 store i64 %n, ptr %n.1 - %t1 = load ptr, ptr %xs.0 - %t0 = bitcast ptr %t1 to ptr - %t2 = load i64, ptr %n.1 - %t3 = sext i32 4 to i64 - call void(ptr, i64, i64, ptr) @qsort(ptr %t0, i64 %t2, i64 %t3, ptr @icmp.4) - %x.2 = alloca ptr - store ptr @foo.5, ptr %x.2 - %t4 = load ptr, ptr %x.2 - call ptr %t4() - ret void -} -define internal i64 @length.7(ptr %l) { -%l.0 = alloca ptr store ptr %l, ptr %l.0 - %n.1 = alloca i64 - store i64 0, ptr %n.1 - %t0 = load ptr, ptr %l.0 - %t1 = load { ptr, i32 }, ptr %t0 - call void({ ptr, i32 }) @ok.6({ ptr, i32 } %t1) - br label %Cont1 -Cont1: %t2 = bitcast i8 0 to i8 ; NOP - %t3 = load ptr, ptr %l.0 - %t4 = icmp ne ptr %t3, null - br i1 %t4, label %Next1, label %Brk1 -Next1: %t5 = bitcast i8 0 to i8 ; NOP - %t6 = load i64, ptr %n.1 - %t7 = add i64 %t6, 1 - store i64 %t7, ptr %n.1 - %t9 = load ptr, ptr %l.0 - %t10 = getelementptr { ptr, i32 }, ptr %t9, i32 0, i32 0 - %t8 = load ptr, ptr %t10 - store ptr %t8, ptr %l.0 - br label %Cont1 -Brk1: %t11 = bitcast i8 0 to i8 ; NOP - %t12 = load i64, ptr %n.1 - ret i64 %t12 - ret i64 undef -} -define internal void @ok.8({ ptr, i32 } %l) { -%l.0 = alloca { ptr, i32 } store { ptr, i32 } %l, ptr %l.0 - ret void -} -define internal float @mag.9({ float, float } %v) { -%v.0 = alloca { float, float } store { float, float } %v, ptr %v.0 - %t1 = getelementptr { float, float }, ptr %v.0, i32 0, i32 0 - %t0 = load float, ptr %t1 - %t3 = getelementptr { float, float }, ptr %v.0, i32 0, i32 0 - %t2 = load float, ptr %t3 - %t4 = fmul float %t0, %t2 - %t6 = getelementptr { float, float }, ptr %v.0, i32 0, i32 1 - %t5 = load float, ptr %t6 - %t8 = getelementptr { float, float }, ptr %v.0, i32 0, i32 1 - %t7 = load float, ptr %t8 - %t9 = fmul float %t5, %t7 - %t10 = fadd float %t4, %t9 - %t11 = call float(float) @sqrtf(float %t10) - ret float %t11 - ret float undef -} -define internal void @zero.11(ptr %v) { -%v.0 = alloca ptr store ptr %v, ptr %v.0 - %t0 = load ptr, ptr %v.0 - %t1 = getelementptr { float, float }, ptr %t0, i32 0, i32 0 - %t2 = sitofp i32 0 to float - store float %t2, ptr %t1 - %t3 = load ptr, ptr %v.0 - %t4 = getelementptr { float, float }, ptr %t3, i32 0, i32 1 - %t5 = sitofp i32 0 to float - store float %t5, ptr %t4 - ret void -} -define internal { ptr, i64 } @spanz.12(ptr %cstr) { -%cstr.0 = alloca ptr store ptr %cstr, ptr %cstr.0 - %t0 = load ptr, ptr %cstr.0 - %t1 = sext i32 0 to i64 - %t2 = load ptr, ptr %cstr.0 - %t3 = call i64(ptr) @strlen(ptr %t2) - %t4 = sub i64 %t3, %t1 - %t5 = insertvalue { ptr, i64 } undef, ptr %t0, 0 - %t6 = insertvalue { ptr, i64 } %t5, i64 %t4, 1 - ret { ptr, i64 } %t6 - ret { ptr, i64 } undef -} -define i32 @main(i32 %argc, ptr %argv) { -%argc.0 = alloca i32 store i32 %argc, ptr %argc.0 -%argv.1 = alloca ptr store ptr %argv, ptr %argv.1 - %colors.2 = alloca [3 x i16] - %t0 = alloca [3 x i16] - store [3 x i16] zeroinitializer, ptr %t0 - %t1 = getelementptr [3 x i16], ptr %t0, i32 0, i32 0 - store i16 0, ptr %t1 - %t2 = getelementptr [3 x i16], ptr %t0, i32 0, i32 1 - store i16 1, ptr %t2 - %t3 = getelementptr [3 x i16], ptr %t0, i32 0, i32 2 - store i16 2, ptr %t3 - %t4 = load [3 x i16], ptr %t0 - store [3 x i16] %t4, ptr %colors.2 - %x.3 = alloca { float, float } - %t5 = alloca { float, float } - store { float, float } zeroinitializer, ptr %t5 - %t6 = getelementptr { float, float }, ptr %t5, i32 0, i32 1 - %t7 = sitofp i32 1 to float - store float %t7, ptr %t6 - %t8 = getelementptr { float, float }, ptr %t5, i32 0, i32 0 - %t9 = fptrunc double 2.39999999999999991118216 to float - store float %t9, ptr %t8 - %t10 = load { float, float }, ptr %t5 - store { float, float } %t10, ptr %x.3 - %p.4 = alloca ptr - %t11 = bitcast ptr %x.3 to ptr - store ptr %t11, ptr %p.4 - %t12 = getelementptr [16 x i8], ptr @.str.0, i64 0, i64 0 - %t14 = getelementptr { float, float }, ptr %x.3, i32 0, i32 0 - %t13 = load float, ptr %t14 - %t16 = load ptr, ptr %p.4 - %t17 = getelementptr { float, float }, ptr %t16, i32 0, i32 1 - %t15 = load float, ptr %t17 - %t18 = call i32(ptr, ...) @printf(ptr %t12, float %t13, float %t15) - %t19 = getelementptr [10 x i8], ptr @.str.1, i64 0, i64 0 - %t20 = load { float, float }, ptr %x.3 - %t21 = call float({ float, float }) @mag.9({ float, float } %t20) - %t22 = call i32(ptr, ...) @printf(ptr %t19, float %t21) - call void(ptr) @zero.11(ptr %x.3) - %t23 = getelementptr [10 x i8], ptr @.str.2, i64 0, i64 0 - %t24 = load { float, float }, ptr %x.3 - %t25 = call float({ float, float }) @mag.9({ float, float } %t24) - %t26 = call i32(ptr, ...) @printf(ptr %t23, float %t25) - %x.5 = alloca { i8, i64 } - %t27 = alloca { i8, i64 } - store { i8, i64 } zeroinitializer, ptr %t27 - store i8 0, ptr %t27 - %t28 = load { i8, i64 }, ptr %t27 - store { i8, i64 } %t28, ptr %x.5 - %x.6 = alloca { i8, i64 } - %t29 = alloca { i8, i64 } - store { i8, i64 } zeroinitializer, ptr %t29 - store i8 1, ptr %t29 - %t30 = bitcast ptr %t29 to ptr - %t31 = getelementptr i64, ptr %t30, i32 1 - store i64 zeroinitializer, ptr %t31 - %t32 = load { i8, i64 }, ptr %t29 - store { i8, i64 } %t32, ptr %x.6 - %is.7 = alloca [6 x i32] - %t33 = alloca [6 x i32] - store [6 x i32] zeroinitializer, ptr %t33 - %t34 = getelementptr [6 x i32], ptr %t33, i32 0, i32 4 - store i32 1, ptr %t34 - %t35 = getelementptr [6 x i32], ptr %t33, i32 0, i32 5 - store i32 2, ptr %t35 - %t36 = getelementptr [6 x i32], ptr %t33, i32 0, i32 0 - store i32 3, ptr %t36 - %t37 = load [6 x i32], ptr %t33 - store [6 x i32] %t37, ptr %is.7 - %t38 = getelementptr [6 x i32], ptr %is.7, i64 0, i64 0 - call void(ptr, i64) @isort.3(ptr %t38, i64 6) - %i.8 = alloca i64 - store i64 0, ptr %i.8 - br label %Cont1 -Cont1: %t39 = bitcast i8 0 to i8 ; NOP - %t40 = load i64, ptr %i.8 - %t41 = icmp ult i64 %t40, 6 - %t42 = zext i1 %t41 to i8 - %t43 = icmp ne i8 %t42, 0 - br i1 %t43, label %Next1, label %Brk1 -Next1: %t44 = bitcast i8 0 to i8 ; NOP - %x.9 = alloca i32 - %t46 = getelementptr [6 x i32], ptr %is.7, i32 0, i32 0 - %t47 = load i64, ptr %i.8 - %t48 = getelementptr i32, ptr %t46, i64 %t47 - %t45 = load i32, ptr %t48 - store i32 %t45, ptr %x.9 - %t49 = getelementptr [4 x i8], ptr @.str.3, i64 0, i64 0 - %t50 = load i32, ptr %x.9 - %t51 = call i32(ptr, ...) @printf(ptr %t49, i32 %t50) - %t52 = load i64, ptr %i.8 - %t53 = add i64 %t52, 1 - store i64 %t53, ptr %i.8 - br label %Cont1 -Brk1: %t54 = bitcast i8 0 to i8 ; NOP - %i.10 = alloca i64 - store i64 0, ptr %i.10 - br label %Cont2 -Cont2: %t55 = bitcast i8 0 to i8 ; NOP - %t56 = load i64, ptr %i.10 - %t57 = icmp ult i64 %t56, 6 - %t58 = zext i1 %t57 to i8 - %t59 = icmp ne i8 %t58, 0 - br i1 %t59, label %Next2, label %Brk2 -Next2: %t60 = bitcast i8 0 to i8 ; NOP - %x.11 = alloca i32 - %t62 = getelementptr [6 x i32], ptr %is.7, i32 0, i32 0 - %t63 = load i64, ptr %i.10 - %t64 = getelementptr i32, ptr %t62, i64 %t63 - %t61 = load i32, ptr %t64 - store i32 %t61, ptr %x.11 - %t65 = getelementptr [4 x i8], ptr @.str.4, i64 0, i64 0 - %t66 = load i32, ptr %x.11 - %t67 = call i32(ptr, ...) @printf(ptr %t65, i32 %t66) - %t68 = load i64, ptr %i.10 - %t69 = add i64 %t68, 1 - store i64 %t69, ptr %i.10 - br label %Cont2 -Brk2: %t70 = bitcast i8 0 to i8 ; NOP - %slice.12 = alloca { ptr, i64 } - %t71 = sext i32 3 to i64 - %t72 = sext i32 5 to i64 - %t73 = sub i64 %t72, %t71 - %t74 = insertvalue { ptr, i64 } undef, ptr %is.7, 0 - %t75 = insertvalue { ptr, i64 } %t74, i64 %t73, 1 - store { ptr, i64 } %t75, ptr %slice.12 - %t76 = getelementptr [7 x i8], ptr @.str.5, i64 0, i64 0 - %t78 = load { ptr, i64 }, ptr %slice.12 - %t79 = extractvalue { ptr, i64 } %t78, 0 - %t80 = getelementptr i32, ptr %t79, i32 0 - %t77 = load i32, ptr %t80 - %t81 = call i32(ptr, ...) @printf(ptr %t76, i32 %t77) - %t82 = load { ptr, i64 }, ptr %slice.12 - %t83 = sext i32 1 to i64 - %t84 = sext i32 4 to i64 - %t85 = extractvalue { ptr, i64 } %t82, 0 %t86 = sub i64 %t84, %t83 - %t87 = insertvalue { ptr, i64 } undef, ptr %t85, 0 - %t88 = insertvalue { ptr, i64 } %t87, i64 %t86, 1 - store { ptr, i64 } %t88, ptr %slice.12 - %t89 = getelementptr [7 x i8], ptr @.str.6, i64 0, i64 0 - %t91 = load { ptr, i64 }, ptr %slice.12 - %t92 = extractvalue { ptr, i64 } %t91, 0 - %t93 = getelementptr i32, ptr %t92, i32 0 - %t90 = load i32, ptr %t93 - %t94 = call i32(ptr, ...) @printf(ptr %t89, i32 %t90) - %t95 = load { ptr, i64 }, ptr %slice.12 - %t96 = extractvalue { ptr, i64 } %t95, 1 - %v.13 = alloca { float, float } - store { float, float } zeroinitializer, ptr %v.13 - %t97 = getelementptr [18 x i8], ptr @.str.7, i64 0, i64 0 - %t98 = call i32(ptr, ...) @printf(ptr %t97, i64 24) - %t99 = getelementptr [20 x i8], ptr @.str.8, i64 0, i64 0 - %t100 = call i32(ptr, ...) @printf(ptr %t99, i64 8) - %t101 = getelementptr [18 x i8], ptr @.str.9, i64 0, i64 0 - %t102 = call i32(ptr, ...) @printf(ptr %t101, i64 8) - %t103 = getelementptr [14 x i8], ptr @.str.10, i64 0, i64 0 - %t105 = alloca { float } - store { float } zeroinitializer, ptr %t105 - %t106 = bitcast ptr %t105 to ptr - store float 1.19999999999999995559108, ptr %t106 - %t107 = bitcast ptr %t105 to ptr %t104 = load i32, ptr %t107 - %t108 = call i32(ptr, ...) @printf(ptr %t103, i32 %t104) - switch i64 6, label %ISx0 [ i64 0, label %IS0.0 i64 1, label %IS0.0 i64 3, label %IS0.1 ] -IS0.0: %t109 = icmp ult i64 6, 2 - %t110 = zext i1 %t109 to i8 - br label %ISe0 -IS0.1: br label %ISe0 -ISx0: br label %ISe0 -ISe0: %t111 = bitcast i8 0 to i8 ; NOP - %t113 = getelementptr [3 x i16], ptr %colors.2, i32 0, i32 0 - %t114 = getelementptr i16, ptr %t113, i32 0 - %t112 = load i16, ptr %t114 - switch i16 %t112, label %ISx0 [ i16 0, label %IS1.0 ] -IS1.0: br label %ISe1 -ISx1: br label %ISe1 -ISe1: %t115 = bitcast i8 0 to i8 ; NOP - ret i32 0 - ret i32 undef -} -@.str.0 = internal constant [16 x i8] c"v = { %g, %g }\0A\00"; -@.str.1 = internal constant [10 x i8] c"mag = %g\0A\00"; -@.str.2 = internal constant [10 x i8] c"mag = %g\0A\00"; -@.str.3 = internal constant [4 x i8] c"%d\0A\00"; -@.str.4 = internal constant [4 x i8] c"%d\0A\00"; -@.str.5 = internal constant [7 x i8] c"sl %d\0A\00"; -@.str.6 = internal constant [7 x i8] c"sl %d\0A\00"; -@.str.7 = internal constant [18 x i8] c"sizeof(is) = %zu\0A\00"; -@.str.8 = internal constant [20 x i8] c"sizeof *void = %zu\0A\00"; -@.str.9 = internal constant [18 x i8] c"alignof f64= %zu\0A\00"; -@.str.10 = internal constant [14 x i8] c"1.2 -> %#.8x\0A\00"; -declare float @sqrtf(float); -@stderr = external global ptr -declare i32 @printf(ptr, ...); -declare i64 @strlen(ptr); -@stdin = external global ptr -declare void @qsort(ptr, i64, i64, ptr); |