aboutsummaryrefslogtreecommitdiff
path: root/src/llvm.cff
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm.cff')
-rw-r--r--src/llvm.cff164
1 files changed, 121 insertions, 43 deletions
diff --git a/src/llvm.cff b/src/llvm.cff
index eb13919..1a7f24a 100644
--- a/src/llvm.cff
+++ b/src/llvm.cff
@@ -23,7 +23,7 @@ struct Value {
}
}
-static ty_i1 *Type = as(*void)&outfp; // dummy
+static ty_i1 Type = {}; // dummy
fn gen(fmt *const u8, ...) void;
extern fn genagg(ty *const Type) void {
@@ -87,7 +87,7 @@ fn gen(fmt *const u8, ...) void {
ap->start(fmt);
fn pritype(ty *const Type) void {
- if ty == ty_i1 {
+ if ty == &ty_i1 {
gen("i1");
return;
}
@@ -121,7 +121,8 @@ fn gen(fmt *const u8, ...) void {
}
}
gen(") ");
- case VaList; gen("%s", g_targ.valistllvmty);
+ case VaList; gen("%%.type.valist");
+ case else assert(#f, "type?");
}
}
@@ -142,7 +143,7 @@ fn gen(fmt *const u8, ...) void {
fputc('"', outfp);
foreach(c, _, str) {
extern fn isprint(int) int;
- if isprint(c) == 0 {
+ if isprint(c) == 0 or c == '"' or c == '\\' {
fprintf(outfp, "\\%.2X", c);
} else {
fputc(c, outfp);
@@ -344,6 +345,12 @@ fn genref(f *Fn, ex *Expr) Ref {
gen("\tstore %t %v, %t %v\n", fex.ty, convert(f, ty.u.Arr.child, fex), ptr.ty, ptr);
}
return :Addr(tmp);
+
+ case else
+ let it = genexpr(f, ex);
+ let tmp = gentmp(mkptrtype(ex.ty), "alloca %t", ex.ty);
+ gen("store %t %v, %t %v", it.ty, it, tmp.ty, tmp);
+ return :Addr(tmp);
}
assert(#f, "genref %d", ex.u.#tag);
}
@@ -362,7 +369,7 @@ fn genload(f *Fn, ref Ref) Value {
let res = mktmp(fld.ty);
switch {
case dot.fld.ty->is(:Bool);
- let tmp = gentmp(ty_i1, "icmp ne i%d %v, 0", fld.size, truncd);
+ let tmp = gentmp(&ty_i1, "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,
@@ -402,21 +409,18 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
if from->is(:Enum) { from = from.u.Enum.intty; }
defmacro cvt(inst) [
- (do let t = mktmp(to),
+ (do let $t = mktmp(to),
val = genexpr(f, ex);
- gen("\t%v = %s %t %v to %t\n", t, inst, from, val, to);
- t;
+ gen("\t%v = %s %t %v to %t\n", $t, inst, from, val, to);
+ $t;
)
]
switch {
case from == to;
return genexpr(f, ex);
- case to->is(:Int) and from->is(:Int) and to.size == from.size and to.u.Int.sgn != from.u.Int.sgn;
- return genexpr(f, ex);
-
case to->is(:Int) and from->is(:Int) and to.size == from.size;
- return cvt("bitcast");
+ return genexpr(f, ex);
case to->is(:Int) and from->is(:Int) and to.size < from.size;
return cvt("trunc");
@@ -454,25 +458,24 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
return cvt(to.u.Int.sgn ? "fptosi" : "fptoui");
case to->is(:Int) and from->is(:Bool);
- let t0 = mktmp(ty_i1);
+ let t0 = mktmp(&ty_i1);
gen("\t%v = icmp ne %t %v, 0\n", t0, ex.ty, genexpr(f, ex));
let t1 = mktmp(to);
gen("\t%v = zext %t %v to %t\n", t1, t0.ty, t0, t1.ty);
return t1;
case to->is(:Bool) and from->is(:Int);
- let t0 = mktmp(ty_i1);
+ let t0 = mktmp(&ty_i1);
gen("\t%v = icmp ne %t %v, 0\n", t0, ex.ty, genexpr(f, ex));
let t1 = mktmp(to);
gen("\t%v = zext %t %v to %t\n", t1, t0.ty, t0, t1.ty);
return t1;
-
case to->is(:Ptr) and from->is(:Ptr);
- let t = mktmp(to),
- val = genexpr(f, ex);
- gen("\t%v = bitcast %t %v to %t\n", t, from, val, to);
- return t;
+ return genexpr(f, ex);
+
+ case to->is(:Slice) and from->is(:Slice);
+ return genexpr(f, ex);
case to->is(:Ptr) and from->is(:Arr);
let addr = genref(f, ex).Addr;
@@ -483,11 +486,9 @@ fn convert(f *Fn, to *const Type, ex *Expr) Value {
case to->is(:Arr) and from->is(:Arr);
return genexpr(f, ex);
-
- case else
- efmt("%t %t\n",from,to);
- assert(#f, "convert");
}
+ efmt("%t %t\n",from,to);
+ assert(#f, "convert");
}
fn genblock(f *Fn, block Block) Option<Value>;
@@ -537,8 +538,12 @@ fn genexpr(f *Fn, ex *Expr) Value {
$t, lhs.ty.u.Ptr, lhs.ty, lhs, rhs.ty, rhs);
res = $t;
} else if rhs.ty->is(:Ptr) {
+ let $t = mktmp(type);
+ gen("\t%v = getelementptr %t, %t %v, %t %v\n",
+ $t, rhs.ty.u.Ptr, rhs.ty, rhs, rhs.ty, lhs);
+ res = $t;
} else {
- assert(#f, "bad sub");
+ assert(#f, "bad ad");
}
res;
)
@@ -546,7 +551,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
defmacro gensub(type, lhs, rhs) [
(do
let res Value #?;
- if isnumtype(type) {
+ if isnumtype(type) and !lhs.ty->is(:Ptr) {
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;
@@ -555,10 +560,16 @@ fn genexpr(f *Fn, ex *Expr) Value {
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);
+ $t, lhs.ty.u.Ptr == ty_void ? ty_i8 : lhs.ty.u.Ptr, lhs.ty, lhs, $off.ty, $off);
res = $t;
+ } else if lhs.ty->is(:Ptr) and rhs.ty->is(:Ptr) {
+ let $l = gentmp(ty_isize, "ptrtoint ptr %v to %t", lhs, ty_isize);
+ let $r = gentmp(ty_isize, "ptrtoint ptr %v to %t", rhs, ty_isize);
+ let $diff = gentmp(ty_isize, "sub %t %v, %v", ty_isize, $l, $r);
+ let $res = gentmp(ty_isize, "sdiv %t %v, %v", ty_isize, $l, $r);
+ return $res;
} else {
- assert(#f, "bad add");
+ assert(#f, "bad sub");
}
res;
)
@@ -637,7 +648,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
static orid int = {};
let id = orid++;
let lhs = genexpr(f, b.lhs);
- let cnd = mktmp(ty_i1);
+ let cnd = mktmp(&ty_i1);
let tmpvar = mktmp(mkptrtype(ex.ty));
let res = mktmp(ex.ty);
gen("\t%v = alloca %t\n", tmpvar, ex.ty);
@@ -656,7 +667,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
static andid int = {};
let id = andid++;
let lhs = genexpr(f, b.lhs);
- let cnd = mktmp(ty_i1);
+ let cnd = mktmp(&ty_i1);
let tmpvar = mktmp(mkptrtype(ex.ty));
let res = mktmp(ex.ty);
gen("\t%v = alloca %t\n", tmpvar, ex.ty);
@@ -670,6 +681,25 @@ fn genexpr(f *Fn, ex *Expr) Value {
gen("AndF%d: ", id);
gen("\t%v = load %t, %t %v\n", res, ex.ty, tmpvar.ty, tmpvar);
return res;
+
+ case '??';
+ static orid int = {};
+ let id = orid++;
+ let lhs = genexpr(f, b.lhs);
+ let cnd = mktmp(&ty_i1);
+ let tmpvar = mktmp(mkptrtype(ex.ty));
+ let res = mktmp(ex.ty);
+ gen("\t%v = alloca %t\n", tmpvar, ex.ty);
+ gen("\tstore %t %v, %t %v\n", ex.ty, lhs, tmpvar.ty, tmpvar);
+ gen("\t%v = icmp ne %t %v, null\n", cnd, lhs.ty, lhs);
+ gen("\tbr i1 %v, label %%OrT%d, label %%OrF%d\n", cnd, id, id);
+ gen("OrF%d: ", id);
+ let rhs = genexpr(f, b.rhs);
+ gen("\tstore %t %v, %t %v\n", ex.ty, rhs, tmpvar.ty, tmpvar);
+ gen("\tbr label %%OrT%d\n", cnd, id, id);
+ gen("OrT%d: ", id);
+ gen("\t%v = load %t, %t %v\n", res, ex.ty, tmpvar.ty, tmpvar);
+ return res;
case else
assert(#f, "binop? %c", b.op);
@@ -678,7 +708,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
static condid int = {};
let id = condid++;
let lhs = genexpr(f, cond.test);
- let cnd = mktmp(ty_i1);
+ let cnd = mktmp(&ty_i1);
let tmpvar = mktmp(mkptrtype(ex.ty));
let res = mktmp(ex.ty);
gen("\t%v = alloca %t\n", tmpvar, ex.ty);
@@ -713,7 +743,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
return tmp;
case :not;
- let tmp = mktmp(ty_i1);
+ let tmp = mktmp(&ty_i1);
gen("\t%v = xor i1 1, %v\n", tmp, ex.ty, llvmbool(f, un.ex));
let res = mktmp(ex.ty);
gen("\t%v = zext i1 %v to %t\n", res, tmp, res.ty);
@@ -863,13 +893,12 @@ fn genexpr(f *Fn, ex *Expr) Value {
let ty = i < fnty.params.#len ? fnty.params[i] : varargpromote(arg.ty);
args[i] = convert(f, ty, arg);
}
- let t Value #?;
+ let t Value = mktmp(ex.ty);
if fnty.ret->is(:Void) {
- t = {ty_void};
- gen("\tcall %t %v(", call.lhs.ty, lhs);
+ gen("\tcall void %v(", lhs);
} else {
t = mktmp(ex.ty);
- gen("\t%v = call %t %v(", t, call.lhs.ty, lhs);
+ gen("\t%v = call %t %v(", t, call.lhs.ty->is(:Ptr) ? call.lhs.ty.u.Ptr : call.lhs.ty, lhs);
}
foreach_ptr(arg, i, call.args) {
let ty = i < fnty.params.#len ? fnty.params[i] : varargpromote(arg.ty);
@@ -910,6 +939,17 @@ fn genexpr(f *Fn, ex *Expr) Value {
gen("\t%v = load %t, %t %v\n", res, res.ty, t0.ty, t0);
return res;
+ case VaStart ap;
+ gen("\tcall void @llvm.va_start(ptr %v)\n", genref(f, ap).Addr);
+ return mktmp(ty_void);
+
+ case VaArg ap;
+ return gentmp(ex.ty, "va_arg ptr %v, %t", genref(f, ap).Addr, ex.ty);
+
+ case VaEnd ap;
+ gen("\tcall void @llvm.va_end(ptr %v)\n", genref(f, ap).Addr);
+ return mktmp(ty_void);
+
case Stmt block;
switch genblock(f, block) {
case Some val; return val;
@@ -923,7 +963,7 @@ fn genexpr(f *Fn, ex *Expr) Value {
fn llvmbool(f *Fn, ex *Expr) Value {
let v = genexpr(f, ex);
- let t = mktmp(ty_i1);
+ let t = mktmp(&ty_i1);
if v.ty->is(:Bool) or v.ty->is(:Int) {
gen("\t%v = icmp ne %t %v, 0\n", t, v.ty, v);
} else {
@@ -951,9 +991,10 @@ fn genstmt(f *Fn, block *Block, st *Stmt) void {
let nam = decl.name,
ty = var.ty;
gen("\t%%%s.%d = alloca %t\n", nam, var.id, ty);
- if !var.ini->empty() {
+ switch var.ini {
+ case Some *ex;
gen("\tstore %t %v, %t %%%s.%d\n",
- ty, convert(f, ty, &var.ini.Some), mkptrtype(ty), nam, var.id);
+ ty, convert(f, ty, ex), mkptrtype(ty), nam, var.id);
}
}
case If *cnd;
@@ -1234,9 +1275,9 @@ extern fn llvm_genfn(externp bool, name *const u8, f *Fn) void {
gen("}\n");
}
-struct I64Traits {
- fn hash(x i64) u32 { return x ^ 7; }
- fn eq(a i64, b i64) bool { return a == b; }
+struct IntTraits<T> {
+ fn hash(x T) u32 { return x ^ 7; }
+ fn eq(a T, b T) bool { return a == b; }
}
fn gendata(ty *const Type, ex *Expr) void {
@@ -1249,6 +1290,10 @@ fn gendata(ty *const Type, ex *Expr) void {
if !decl.externp { gen("@%s.%d", decl.name, f.id);
} else { gen("@%s", decl.name); }
return;
+ case Static v;
+ if !decl.externp { gen("@%s.%d", decl.name, v.id);
+ } else { gen("@%s", decl.name); }
+ return;
}
}
assert(#f, "bad static addr");
@@ -1276,7 +1321,7 @@ fn gendata(ty *const Type, ex *Expr) void {
case ArrIni ini;
assert(ty->is(:Arr), "not arr arr ini");
- let map Map<i64, *Expr, I64Traits> = {};
+ let map Map<i64, *Expr, IntTraits<i64>,> = {};
defer map->clear();
foreach (idx, i, ini.idxs) {
map->put(idx, &ini.exs[i]);
@@ -1295,7 +1340,36 @@ fn gendata(ty *const Type, ex *Expr) void {
}
}
gen(" ]");
- return;
+ return;
+
+ case AggIni ini;
+ assert(ty->is(:Agg), "not agg agg ini");
+
+ let map Map<u16, *Expr, IntTraits<u16>,> = {};
+ defer map->clear();
+ if ty.u.Agg.kind == :Struct {
+ foreach (fld, i, ini.flds) {
+ let idx = fld - ty.u.Agg.flds.#ptr;
+ map->put(idx, &ini.exs[i]);
+ }
+ gen("{ ");
+ for let i = 0z; i < ty.u.Agg.flds.#len; ++i {
+ gen("%t ", ty.u.Agg.flds[i].ty);
+ let ex **Expr = map->get(i);
+ if ex {
+ gendata(ty.u.Agg.flds[i].ty, *ex);
+ } else {
+ gen("zeroinitializer");
+ }
+ if i < ty.u.Agg.flds.#len - 1 {
+ gen(", ");
+ }
+ }
+ gen(" }");
+ } else {
+ assert(#f, "NYI static");
+ }
+ return;
}
assert(#f, "bad static %d", ex.u.#tag);
}
@@ -1312,6 +1386,9 @@ extern fn llvm_genstatic(externp bool, name *const u8, var *Var) void {
}
extern fn llvm_fini() void {
+ gen("declare void @llvm.va_start(ptr)\n");
+ gen("declare void @llvm.va_copy(ptr, ptr)\n");
+ gen("declare void @llvm.va_end(ptr)\n");
vec_each(s, i, strs) {
gen("@.str.%z = private unnamed_addr constant [%z x i8] c%S;\n", i, s.#len + 1, s);
}
@@ -1356,5 +1433,6 @@ extern fn llvm_init(out *FILE) void {
outfp = out;
gen("target triple = \"%s\"\n", g_targ.triple);
gen("%%.type.opaque = type opaque\n");
+ gen("%%.type.valist = type %s\n", g_targ.valistllvmty);
gen("\n");
}