diff options
| -rw-r--r-- | examples/hello-world.cff | 3 | ||||
| -rw-r--r-- | src/cffc.hff | 2 | ||||
| -rw-r--r-- | src/llvm.cff | 225 | ||||
| -rw-r--r-- | src/parse.cff | 6 |
4 files changed, 202 insertions, 34 deletions
diff --git a/examples/hello-world.cff b/examples/hello-world.cff index fca5817..998b5c2 100644 --- a/examples/hello-world.cff +++ b/examples/hello-world.cff @@ -1,6 +1,7 @@ import "libc.hff"; extern fn main(argc int, argv **u8) int { - printf("hello %d", argc + 42); + argc += 1; + printf("hello %d %s\n", argc, *((argv + 2) - 1)); } diff --git a/src/cffc.hff b/src/cffc.hff index f78c61c..1c80b3a 100644 --- a/src/cffc.hff +++ b/src/cffc.hff @@ -460,8 +460,8 @@ extern fn ir_free(*IRCtx) void; extern static g_asmbackend Backend; // llvm.cff -extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void; extern fn llvm_addfn(*Decl) void; +extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void; extern fn llvm_addtype(*const Type) void; extern fn llvm_init(*FILE) void; extern fn llvm_fini() void; diff --git a/src/llvm.cff b/src/llvm.cff index c07ab4a..4ea469d 100644 --- a/src/llvm.cff +++ b/src/llvm.cff @@ -137,19 +137,38 @@ static arena Arena = {}; static alloc Allocator = {}; static strs Vec<[#]const u8> = {}; -fn genaddr(f *Fn, e *Expr) Value { - switch e.u { +fn genaddr(f *Fn, ex *Expr) Value { + switch ex.u { case StrLit s; let p *u8 = alloc->alloc(s.#len + 1, 1); memcpy(p, s.#ptr, s.#len + 1); let s = p[0::s.#len]; strs->push(s); - return {mkptrtype(e.ty), :StrConstRef(strs.len - 1)}; + return {mkptrtype(ex.ty), :StrConstRef(strs.len - 1)}; case Symbol decl; switch decl.u { - case Let *var; return {var.ty, :LocalRef(var)}; - case Static *var; return {var.ty, :GlobalRef(var)}; + case Let *var; return {mkptrtype(var.ty), :LocalRef(var)}; + case Static *var; return {mkptrtype(var.ty), :GlobalRef(var)}; + } + case UnOp un; + switch un.op { + case :deref; + return genexpr(f, un.ex); + } + case Index idx; + let lhs Value #?; + if idx.lhs.ty->is(:Arr) { + let arr = genaddr(f, idx.lhs); + lhs = mktmp(ex.ty); + gen("\t%v = getelementptr %t, %t %v, i32 0, i32 0\n", lhs, arr.ty.u.Arr.child, arr.ty, arr); + } else { + lhs = genexpr(f, idx.lhs); } + let rhs = genexpr(f, idx.rhs), + addr = mktmp(ex.ty), + val = mktmp(ex.ty); + gen("\t%v = getelementptr %t, %t* %v, %t %v\n", addr, ex.ty, ex.ty, lhs, rhs.ty, rhs); + return addr; } assert(#f, "genaddr"); } @@ -207,6 +226,10 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value { gen("\t%v = getelementptr %t, %t %v, %t 0, %t 0\n", t, addr.ty.u.Ptr, addr.ty, addr, ty_usize, ty_usize); return t; + + case to->is(:Arr) and from->is(:Arr); + return genexpr(f, ex); + case else assert(#f, "convert"); } @@ -224,13 +247,15 @@ fn genexpr(f *Fn, ex *Expr) Value { case ZeroIni; return {ex.ty, :ZeroIni}; case StrLit s; return {ex.ty, :StrLit(s)}; case BinOp b; - defmacro genbinop(inst) [ { - let lhs = convert(f, ex.ty, b.lhs), - rhs = convert(f, ex.ty, b.rhs), - t = mktmp(ex.ty); - gen("\t%v = %s %t %v, %v\n", t, inst, ex.ty, lhs, rhs); - return t; - } ] + defmacro genbinop(a, b, inst) [ + (do + let lhs = convert(f, ex.ty, a), + rhs = convert(f, ex.ty, b), + t = mktmp(ex.ty); + gen("\t%v = %s %t %v, %v\n", t, inst, ex.ty, lhs, rhs); + t; + ) + ] let ty2 = typeof2(b.lhs.ty, b.rhs.ty); defmacro gencmp(op) [ { let lhs = convert(f, ty2, b.lhs), @@ -242,27 +267,123 @@ fn genexpr(f *Fn, ex *Expr) Value { gen("\t%v = zext i1 %v to %t\n", t1, t0, ex.ty); return t1; } ] + defmacro genadd(type, lhs, rhs) [ + (do + let res Value #?; + if isnumtype(type) { + let $t = mktmp(type); + gen("\t%v = %s %t %v, %v\n", $t, ex.ty->is(:Flo) ? "fadd" : "add", ex.ty, lhs, rhs); + res = $t; + } 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, lhs.ty, lhs, rhs.ty, rhs); + res = $t; + } else if rhs.ty->is(:Ptr) { + } else { + assert(#f, "bad sub"); + } + res; + ) + ] + defmacro gensub(type, lhs, rhs) [ + (do + let res Value #?; + if isnumtype(type) { + let $t = mktmp(type); + gen("\t%v = %s %t %v, %v\n", $t, ex.ty->is(:Flo) ? "fsub" : "sub", ex.ty, lhs, rhs); + res = $t; + } else if lhs.ty->is(:Ptr) and rhs.ty->is(:Int) { + let $off = mktmp(rhs.ty); + gen("\t%v = sub %t 0, %v\n", $off, rhs.ty, rhs); + let $t = mktmp(type); + gen("\t%v = getelementptr %t, %t %v, %t %v\n", + $t, lhs.ty.u.Ptr, lhs.ty, lhs, $off.ty, $off); + res = $t; + } else { + assert(#f, "bad add"); + } + res; + ) + ] + defmacro genassignop(inst, type, a, b) [ + (do + let addr = genaddr(f, a); + let rhs = convert(f, a.ty, b); + let lhs0 = mktmp(type); + gen("\t%v = load %t, %t %v\n", lhs0, type, addr.ty, addr); + let tmp = (do + let t = mktmp(ex.ty); + gen("\t%v = %s %t %v, %v\n", t, inst, ex.ty, lhs0, rhs); + t; + ); + gen("\tstore %t %v, %t* %v\n", tmp.ty, tmp, ex.ty, addr); + rhs; + ) + ] switch b.op { case '+'; - // TODO ptr arithmetic - genbinop(!ex.ty->is(:Flo) ? "add" : "fadd"); + let ty2 = typeof2(b.lhs.ty, b.rhs.ty); + let lhs = b.lhs.ty->is(:Ptr) ? genexpr(f, b.lhs) : convert(f, ty2 ?? b.lhs.ty, b.lhs), + rhs = b.rhs.ty->is(:Ptr) ? genexpr(f, b.rhs) : convert(f, ty2 ?? b.rhs.ty, b.rhs); + return genadd(ex.ty, lhs, rhs); case '-'; - genbinop(!ex.ty->is(:Flo) ? "sub" : "fsub"); - case '*'; genbinop(!ex.ty->is(:Flo) ? "mul" : "fmul"); - case '/'; genbinop(ex.ty->is(:Flo) ? "fdiv" : ex.ty.u.Int.sgn ? "sdiv" : "udiv"); - case '%'; genbinop(ex.ty.u.Int.sgn ? "srem" : "urem"); - case '&'; genbinop("and"); - case '|'; genbinop("or"); - case '^'; genbinop("or"); - case '<<'; genbinop("shl"); - case '>>'; genbinop(ex.ty.u.Int.sgn ? "ashr" : "lshr"); + let ty2 = typeof2(b.lhs.ty, b.rhs.ty); + let lhs = b.lhs.ty->is(:Ptr) ? genexpr(f, b.lhs) : convert(f, ty2 ?? b.lhs.ty, b.lhs), + rhs = b.rhs.ty->is(:Ptr) ? genexpr(f, b.rhs) : convert(f, ty2 ?? b.rhs.ty, b.rhs); + return gensub(ex.ty, lhs, rhs); + case '*'; return genbinop(b.lhs, b.rhs, !ex.ty->is(:Flo) ? "mul" : "fmul"); + case '/'; return genbinop(b.lhs, b.rhs, ex.ty->is(:Flo) ? "fdiv" + : ex.ty.u.Int.sgn ? "sdiv" : "udiv"); + case '%'; return genbinop(b.lhs, b.rhs, ex.ty.u.Int.sgn ? "srem" : "urem"); + case '&'; return genbinop(b.lhs, b.rhs, "and"); + case '|'; return genbinop(b.lhs, b.rhs, "or"); + case '^'; return genbinop(b.lhs, b.rhs, "xor"); + case '<<'; return genbinop(b.lhs, b.rhs, "shl"); + case '>>'; return genbinop(b.lhs, b.rhs, ex.ty.u.Int.sgn ? "ashr" : "lshr"); case '=='; gencmp("eq"); + case '!='; gencmp("ne"); case '<'; gencmp(ty2->is(:Flo) ? "olt" : ty2.u.Int.sgn ? "slt" : "ult"); case '<='; gencmp(ty2->is(:Flo) ? "ole" : ty2.u.Int.sgn ? "sle" : "ule"); 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, ex.ty, addr); + return rhs; + case '+='; + let addr = genaddr(f, b.lhs); + let rhs = convert(f, b.lhs.ty, b.rhs); + let lhs0 = mktmp(ex.ty); + gen("\t%v = load %t, %t %v\n", lhs0, ex.ty, addr.ty, addr); + let tmp = genadd(ex.ty, lhs0, rhs); + gen("\tstore %t %v, %t* %v\n", tmp.ty, tmp, ex.ty, addr); + return rhs; + + case '-='; + let addr = genaddr(f, b.lhs); + let rhs = convert(f, b.lhs.ty, b.rhs); + let lhs0 = mktmp(ex.ty); + gen("\t%v = load %t, %t %v\n", lhs0, ex.ty, addr.ty, addr); + let tmp = gensub(ex.ty, lhs0, rhs); + gen("\tstore %t %v, %t* %v\n", tmp.ty, tmp, ex.ty, addr); + return rhs; + case '*='; + return genassignop(ex.ty->is(:Flo) ? "fdiv" : "mul", ex.ty, b.lhs, b.rhs); + case '/='; + return genassignop(ex.ty->is(:Flo) ? "fdiv" : ex.ty.u.Int.sgn ? "sdiv" : "udiv", + ex.ty, b.lhs, b.rhs); + case '%='; + return genassignop(ex.ty.u.Int.sgn ? "srem" : "urem", ex.ty, b.lhs, b.rhs); + case '&='; return genassignop("and", ex.ty, b.lhs, b.rhs); + case '|='; return genassignop("or", ex.ty, b.lhs, b.rhs); + case '^='; return genassignop("xor", ex.ty, b.lhs, b.rhs); + case '<<='; return genassignop("shl", ex.ty, b.lhs, b.rhs); + case '>>='; return genassignop(ex.ty.u.Int.sgn ? "ashr" : "lshr", ex.ty, b.lhs, b.rhs); + case else - assert(#f, "binop? %d", b.op); + assert(#f, "binop? %c", b.op); } case UnOp un; switch un.op { @@ -275,10 +396,45 @@ fn genexpr(f *Fn, ex *Expr) Value { gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one); gen("\tstore %t %v, %t* %v\n", ex.ty, val, ex.ty, addr); return val; + + case :postinc, :postdec; + let one = Value{ex.ty, :IImm(un.op == :postinc ? 1 : -1)}; + let addr = genaddr(f, un.ex); + let var = mktmp(ex.ty); + let val = mktmp(ex.ty); + gen("\t%v = load %t, %t* %v\n", var, ex.ty, ex.ty, addr); + gen("\t%v = add %t %v, %v\n", val, ex.ty, var, one); + gen("\tstore %t %v, %t* %v\n", ex.ty, val, ex.ty, addr); + return var; + + case :deref; + let rhs = genexpr(f, un.ex); + let val = mktmp(ex.ty); + gen("\t%v = load %t, %t* %v\n", val, ex.ty, ex.ty, rhs); + return val; + case else assert(#f, "unop?"); } + case Index idx; + let lhs Value #?; + if idx.lhs.ty->is(:Arr) { + let arr = genaddr(f, idx.lhs); + lhs = mktmp(ex.ty); + gen("\t%v = getelementptr %t, %t %v, i32 0, i32 0\n", lhs, arr.ty.u.Arr.child, arr.ty, arr); + } else { + lhs = genexpr(f, idx.lhs); + } + let rhs = genexpr(f, idx.rhs), + addr = mktmp(ex.ty), + val = mktmp(ex.ty); + gen("\t%v = getelementptr %t, %t* %v, %t %v\n", addr, ex.ty, ex.ty, lhs, rhs.ty, rhs); + gen("\t%v = load %t, %t* %v\n", val, ex.ty, ex.ty, addr); + return val; + case Cast it; + return convert(f, ex.ty, it); + case Symbol decl; switch decl.u { case Let *var; @@ -307,8 +463,14 @@ fn genexpr(f *Fn, ex *Expr) Value { let ty = i < fnty.params.#len ? fnty.params[i] : typeof2(arg.ty, arg.ty); args[i] = convert(f, ty, arg); } - let t = mktmp(ex.ty); - gen("\t%v = call %t %v(", t, call.lhs.ty, lhs); + let t Value #?; + if fnty.ret->is(:Void) { + t = {ty_void}; + gen("call %t %v(", call.lhs.ty, lhs); + } else { + t = mktmp(ex.ty); + gen("\t%v = call %t %v(", t, call.lhs.ty, lhs); + } foreach_ptr(arg, i, call.args) { let ty = i < fnty.params.#len ? fnty.params[i] : typeof2(arg.ty, arg.ty); gen("%t %v", ty, args[i]); @@ -366,14 +528,17 @@ fn genstmt(f *Fn, st *Stmt) void { if cnd.f.#ptr { gen("\tbr label %%IfSk%d\n", id); } + gen("\tbr label %%IfF%d\n", id); gen("IfF%d:", id); nop(); genblock(f, cnd.f); if cnd.f.#ptr { + gen("\tbr label %%IfSk%d\n", id); gen("IfSk%d:", id); nop(); } case While loop; + gen("\tbr label %%Cont%d\n", loop.id); gen("Cont%d:", loop.id); nop(); gen("\tbr i1 %v, label %%Next%d, label %%Brk%d\n", @@ -384,6 +549,7 @@ fn genstmt(f *Fn, st *Stmt) void { gen("\tbr label %%Cont%d\n", loop.id); gen("Brk%d:",loop.id); nop(); + case For loop; genblock(f, loop.ini); gen("\tbr label %%Cont%d\n", loop.id); @@ -400,6 +566,13 @@ fn genstmt(f *Fn, st *Stmt) void { gen("\tbr label %%Cont%d\n", loop.id); gen("Brk%d:",loop.id); nop(); + + case Break loopid; + gen("\tbr label %%Brk%d\n", loopid); + + case Continue loopid; + gen("\tbr label %%Cont%d\n", loopid); + case Return *e; switch *e { case None; diff --git a/src/parse.cff b/src/parse.cff index 699762c..760c0f9 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -1605,9 +1605,6 @@ fn pexpostfix(P *Parser) Expr { case lexmatch(P, &tok, '#ptr'); let ty = ex.ty; - if ty->is(:Ptr) { - ty = ty.u.Ptr; - } switch ty.u { case Slice sl; ex = { tok.loc, mkptrtype(sl), :SPtr(exprdup(P.alloc, ex)) }; @@ -1616,9 +1613,6 @@ fn pexpostfix(P *Parser) Expr { } case lexmatch(P, &tok, '#len'); let ty = ex.ty; - if ty->is(:Ptr) { - ty = ty.u.Ptr; - } switch ty.u { case Arr arr; assert(arr.length >= 0, "arr len"); |