aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-23 10:21:19 +0200
committerlemon <lsof@mailbox.org>2022-08-23 10:21:19 +0200
commit039ab20bbf6b68c423f420be2481b447d85c606b (patch)
treeb3443baf8990c14e54332a4ee5844765256f4d59 /src
parent09ea9f98e696235bf637c1df723d5796b4c9d185 (diff)
collatz!
Diffstat (limited to 'src')
-rw-r--r--src/cffc.hff2
-rw-r--r--src/llvm.cff225
-rw-r--r--src/parse.cff6
3 files changed, 200 insertions, 33 deletions
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");