Teach rustc about phi nodes, block relationships. Translate if- and block-expressions.
This commit is contained in:
parent
a87e81b929
commit
44e4b2d63a
@ -1,7 +1,10 @@
|
||||
|
||||
import std.util.option;
|
||||
import util.common.option;
|
||||
import std.map.hashmap;
|
||||
import util.common.span;
|
||||
import util.common.option;
|
||||
import util.common.some;
|
||||
import util.common.none;
|
||||
|
||||
type ident = str;
|
||||
|
||||
@ -40,10 +43,10 @@ tag unop {
|
||||
}
|
||||
|
||||
tag stmt {
|
||||
stmt_block(block);
|
||||
stmt_decl(@decl);
|
||||
stmt_ret(option[@expr]);
|
||||
stmt_log(@expr);
|
||||
stmt_expr(@expr);
|
||||
}
|
||||
|
||||
tag decl {
|
||||
@ -63,6 +66,8 @@ tag expr {
|
||||
expr_field(@expr, ident);
|
||||
expr_index(@expr, @expr);
|
||||
expr_cast(@expr, ty);
|
||||
expr_if(@expr, block, option[block]);
|
||||
expr_block(block);
|
||||
}
|
||||
|
||||
tag lit {
|
||||
|
@ -2,15 +2,9 @@ import std._io;
|
||||
import driver.session;
|
||||
import util.common;
|
||||
import util.common.new_str_hash;
|
||||
|
||||
// FIXME: import std.util.option and use it here.
|
||||
// import std.util.option;
|
||||
|
||||
tag option[T] {
|
||||
none;
|
||||
some(T);
|
||||
}
|
||||
|
||||
import util.common.option;
|
||||
import util.common.some;
|
||||
import util.common.none;
|
||||
|
||||
state type parser =
|
||||
state obj {
|
||||
@ -414,8 +408,35 @@ io fn parse_or_expr(parser p) -> @ast.expr {
|
||||
ret parse_binary_exprs(p, sub, vec(tup(token.OROR, ast.or)));
|
||||
}
|
||||
|
||||
io fn parse_if_expr(parser p) -> @ast.expr {
|
||||
expect(p, token.IF);
|
||||
expect(p, token.LPAREN);
|
||||
auto cond = parse_expr(p);
|
||||
expect(p, token.RPAREN);
|
||||
auto thn = parse_block(p);
|
||||
let option[ast.block] els = none[ast.block];
|
||||
alt (p.peek()) {
|
||||
case (token.ELSE) {
|
||||
p.bump();
|
||||
els = some(parse_block(p));
|
||||
}
|
||||
}
|
||||
ret @ast.expr_if(cond, thn, els);
|
||||
}
|
||||
|
||||
io fn parse_expr(parser p) -> @ast.expr {
|
||||
ret parse_or_expr(p);
|
||||
alt (p.peek()) {
|
||||
case (token.LBRACE) {
|
||||
ret @ast.expr_block(parse_block(p));
|
||||
}
|
||||
case (token.IF) {
|
||||
ret parse_if_expr(p);
|
||||
}
|
||||
case (_) {
|
||||
ret parse_or_expr(p);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
io fn parse_stmt(parser p) -> @ast.stmt {
|
||||
@ -426,6 +447,25 @@ io fn parse_stmt(parser p) -> @ast.stmt {
|
||||
expect(p, token.SEMI);
|
||||
ret @ast.stmt_log(e);
|
||||
}
|
||||
|
||||
// Handle the (few) block-expr stmts first.
|
||||
|
||||
case (token.IF) {
|
||||
ret @ast.stmt_expr(parse_expr(p));
|
||||
}
|
||||
|
||||
case (token.LBRACE) {
|
||||
ret @ast.stmt_expr(parse_expr(p));
|
||||
}
|
||||
|
||||
|
||||
// Remainder are line-expr stmts.
|
||||
|
||||
case (_) {
|
||||
auto e = parse_expr(p);
|
||||
expect(p, token.SEMI);
|
||||
ret @ast.stmt_expr(e);
|
||||
}
|
||||
}
|
||||
p.err("expected statement");
|
||||
fail;
|
||||
|
@ -1006,8 +1006,14 @@ obj builder(BuilderRef B) {
|
||||
|
||||
|
||||
/* Miscellaneous instructions */
|
||||
fn Phi(TypeRef Ty) -> ValueRef {
|
||||
ret llvm.LLVMBuildPhi(B, Ty, _str.buf(""));
|
||||
fn Phi(TypeRef Ty, vec[ValueRef] vals, vec[BasicBlockRef] bbs) -> ValueRef {
|
||||
auto phi = llvm.LLVMBuildPhi(B, Ty, _str.buf(""));
|
||||
check (_vec.len[ValueRef](vals) == _vec.len[BasicBlockRef](bbs));
|
||||
llvm.LLVMAddIncoming(phi,
|
||||
_vec.buf[ValueRef](vals),
|
||||
_vec.buf[BasicBlockRef](bbs),
|
||||
_vec.len[ValueRef](vals));
|
||||
ret phi;
|
||||
}
|
||||
|
||||
fn Call(ValueRef Fn, vec[ValueRef] Args) -> ValueRef {
|
||||
|
@ -11,6 +11,9 @@ import back.abi;
|
||||
|
||||
import util.common.istr;
|
||||
import util.common.new_str_hash;
|
||||
import util.common.option;
|
||||
import util.common.some;
|
||||
import util.common.none;
|
||||
|
||||
import lib.llvm.llvm;
|
||||
import lib.llvm.builder;
|
||||
@ -51,7 +54,7 @@ state type fn_ctxt = rec(ValueRef llfn,
|
||||
type terminator = fn(@fn_ctxt cx, builder build);
|
||||
|
||||
tag cleanup {
|
||||
clean(fn(@block_ctxt cx) -> @block_ctxt);
|
||||
clean(fn(@block_ctxt cx) -> result);
|
||||
}
|
||||
|
||||
state type block_ctxt = rec(BasicBlockRef llbb,
|
||||
@ -61,6 +64,14 @@ state type block_ctxt = rec(BasicBlockRef llbb,
|
||||
@fn_ctxt fcx);
|
||||
|
||||
|
||||
state type result = rec(mutable @block_ctxt bcx,
|
||||
mutable ValueRef val);
|
||||
|
||||
fn res(@block_ctxt bcx, ValueRef val) -> result {
|
||||
ret rec(mutable bcx = bcx,
|
||||
mutable val = val);
|
||||
}
|
||||
|
||||
fn ty_str(TypeRef t) -> str {
|
||||
ret lib.llvm.type_to_str(t);
|
||||
}
|
||||
@ -76,10 +87,25 @@ fn val_str(ValueRef v) -> str {
|
||||
|
||||
// LLVM type constructors.
|
||||
|
||||
fn T_nil() -> TypeRef {
|
||||
fn T_void() -> TypeRef {
|
||||
// Note: For the time being llvm is kinda busted here, it has the notion
|
||||
// of a 'void' type that can only occur as part of the signature of a
|
||||
// function, but no general unit type of 0-sized value. This is, afaict,
|
||||
// vestigial from its C heritage, and we'll be attempting to submit a
|
||||
// patch upstream to fix it. In the mean time we only model function
|
||||
// outputs (Rust functions and C functions) using T_void, and model the
|
||||
// Rust general purpose nil type you can construct as 1-bit (always
|
||||
// zero). This makes the result incorrect for now -- things like a tuple
|
||||
// of 10 nil values will have 10-bit size -- but it doesn't seem like we
|
||||
// have any other options until it's fixed upstream.
|
||||
ret llvm.LLVMVoidType();
|
||||
}
|
||||
|
||||
fn T_nil() -> TypeRef {
|
||||
// NB: See above in T_void().
|
||||
ret llvm.LLVMInt1Type();
|
||||
}
|
||||
|
||||
fn T_i1() -> TypeRef {
|
||||
ret llvm.LLVMInt1Type();
|
||||
}
|
||||
@ -196,6 +222,11 @@ fn C_integral(int i, TypeRef t) -> ValueRef {
|
||||
ret llvm.LLVMConstIntOfString(t, _str.buf(istr(i)), 10);
|
||||
}
|
||||
|
||||
fn C_nil() -> ValueRef {
|
||||
// NB: See comment above in T_void().
|
||||
ret C_integral(0, T_i1());
|
||||
}
|
||||
|
||||
fn C_bool(bool b) -> ValueRef {
|
||||
if (b) {
|
||||
ret C_integral(1, T_i1());
|
||||
@ -233,7 +264,7 @@ fn decl_cdecl_fn(ModuleRef llmod, str name,
|
||||
}
|
||||
|
||||
fn decl_glue(ModuleRef llmod, str s) -> ValueRef {
|
||||
ret decl_cdecl_fn(llmod, s, vec(T_taskptr()), T_nil());
|
||||
ret decl_cdecl_fn(llmod, s, vec(T_taskptr()), T_void());
|
||||
}
|
||||
|
||||
fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
|
||||
@ -263,7 +294,7 @@ fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef {
|
||||
ret f;
|
||||
}
|
||||
|
||||
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> ValueRef {
|
||||
fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> result {
|
||||
let int n = _vec.len[ValueRef](args) as int;
|
||||
let ValueRef llupcall = get_upcall(cx.fcx.tcx, name, n);
|
||||
llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());
|
||||
@ -281,171 +312,239 @@ fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> ValueRef {
|
||||
log "emitting call to llglue of type: " + val_str(llglue);
|
||||
*/
|
||||
|
||||
ret cx.build.Call(llglue, call_args);
|
||||
ret res(cx, cx.build.Call(llglue, call_args));
|
||||
}
|
||||
|
||||
fn build_non_gc_free(@block_ctxt cx, ValueRef v) {
|
||||
trans_upcall(cx, "upcall_free", vec(cx.build.PtrToInt(v, T_int()),
|
||||
C_int(0)));
|
||||
fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
|
||||
ret trans_upcall(cx, "upcall_free", vec(cx.build.PtrToInt(v, T_int()),
|
||||
C_int(0)));
|
||||
}
|
||||
|
||||
fn decr_refcnt_and_if_zero(@block_ctxt cx,
|
||||
ValueRef box_ptr,
|
||||
fn(@block_ctxt cx) inner) -> @block_ctxt {
|
||||
fn(@block_ctxt cx) -> result inner,
|
||||
TypeRef t_else, ValueRef v_else) -> result {
|
||||
auto rc_ptr = cx.build.GEP(box_ptr, vec(C_int(0),
|
||||
C_int(abi.box_rc_field_refcnt)));
|
||||
auto rc = cx.build.Load(rc_ptr);
|
||||
rc = cx.build.Sub(rc, C_int(1));
|
||||
cx.build.Store(rc, rc_ptr);
|
||||
auto test = cx.build.ICmp(lib.llvm.LLVMIntEQ, C_int(0), rc);
|
||||
auto next_cx = new_block_ctxt(cx.fcx, cx.term);
|
||||
// We terminate the then-block ourselves here with a Br, so
|
||||
// the terminator we pass in to the inner call is the no-op.
|
||||
auto then_term = terminate_no_op;
|
||||
auto then_cx = new_block_ctxt(cx.fcx, then_term);
|
||||
inner(then_cx);
|
||||
then_cx.build.Br(next_cx.llbb);
|
||||
cx.build.CondBr(test, then_cx.llbb, next_cx.llbb);
|
||||
ret next_cx;
|
||||
auto next_cx = new_extension_block_ctxt(cx);
|
||||
auto then_cx = new_empty_block_ctxt(cx.fcx);
|
||||
auto then_res = inner(then_cx);
|
||||
then_res.bcx.build.Br(next_cx.llbb);
|
||||
cx.build.CondBr(test, then_res.bcx.llbb, next_cx.llbb);
|
||||
auto phi = next_cx.build.Phi(t_else,
|
||||
vec(v_else, then_res.val),
|
||||
vec(cx.llbb, then_res.bcx.llbb));
|
||||
ret res(next_cx, phi);
|
||||
}
|
||||
|
||||
fn drop_str(@block_ctxt cx, ValueRef v) -> @block_ctxt {
|
||||
ret decr_refcnt_and_if_zero(cx, v, bind build_non_gc_free(_, v));
|
||||
fn trans_drop_str(@block_ctxt cx, ValueRef v) -> result {
|
||||
ret decr_refcnt_and_if_zero(cx, v,
|
||||
bind trans_non_gc_free(_, v),
|
||||
T_int(), C_int(0));
|
||||
}
|
||||
|
||||
fn trans_lit(@block_ctxt cx, &ast.lit lit) -> ValueRef {
|
||||
fn trans_lit(@block_ctxt cx, &ast.lit lit) -> result {
|
||||
alt (lit) {
|
||||
case (ast.lit_int(?i)) {
|
||||
ret C_int(i);
|
||||
ret res(cx, C_int(i));
|
||||
}
|
||||
case (ast.lit_uint(?u)) {
|
||||
ret C_int(u as int);
|
||||
ret res(cx, C_int(u as int));
|
||||
}
|
||||
case (ast.lit_char(?c)) {
|
||||
ret C_integral(c as int, T_i32());
|
||||
ret res(cx, C_integral(c as int, T_i32()));
|
||||
}
|
||||
case (ast.lit_bool(?b)) {
|
||||
ret C_bool(b);
|
||||
ret res(cx, C_bool(b));
|
||||
}
|
||||
case (ast.lit_nil) {
|
||||
ret res(cx, C_nil());
|
||||
}
|
||||
case (ast.lit_str(?s)) {
|
||||
auto len = (_str.byte_len(s) as int) + 1;
|
||||
auto v = trans_upcall(cx, "upcall_new_str",
|
||||
vec(p2i(C_str(cx.fcx.tcx, s)),
|
||||
C_int(len)));
|
||||
v = cx.build.IntToPtr(v, T_ptr(T_str(len as uint)));
|
||||
cx.cleanups += vec(clean(bind drop_str(_, v)));
|
||||
ret v;
|
||||
auto sub = trans_upcall(cx, "upcall_new_str",
|
||||
vec(p2i(C_str(cx.fcx.tcx, s)),
|
||||
C_int(len)));
|
||||
sub.val = sub.bcx.build.IntToPtr(sub.val,
|
||||
T_ptr(T_str(len as uint)));
|
||||
cx.cleanups += vec(clean(bind trans_drop_str(_, sub.val)));
|
||||
ret sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> ValueRef {
|
||||
fn trans_unary(@block_ctxt cx, ast.unop op, &ast.expr e) -> result {
|
||||
|
||||
auto sub = trans_expr(cx, e);
|
||||
|
||||
alt (op) {
|
||||
case (ast.bitnot) {
|
||||
ret cx.build.Not(trans_expr(cx, e));
|
||||
sub.val = cx.build.Not(sub.val);
|
||||
ret sub;
|
||||
}
|
||||
case (ast.not) {
|
||||
ret cx.build.Not(trans_expr(cx, e));
|
||||
sub.val = cx.build.Not(sub.val);
|
||||
ret sub;
|
||||
}
|
||||
case (ast.neg) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.Neg(trans_expr(cx, e));
|
||||
sub.val = cx.build.Neg(sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("expr variant in trans_unary");
|
||||
fail;
|
||||
}
|
||||
|
||||
fn trans_binary(@block_ctxt cx, ast.binop op,
|
||||
&ast.expr a, &ast.expr b) -> ValueRef {
|
||||
&ast.expr a, &ast.expr b) -> result {
|
||||
|
||||
auto lhs = trans_expr(cx, a);
|
||||
auto sub = trans_expr(lhs.bcx, b);
|
||||
|
||||
alt (op) {
|
||||
case (ast.add) {
|
||||
ret cx.build.Add(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.Add(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.sub) {
|
||||
ret cx.build.Sub(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.Sub(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.mul) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.Mul(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.Mul(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.div) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.SDiv(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.SDiv(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.rem) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.SRem(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.SRem(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.bitor) {
|
||||
ret cx.build.Or(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.Or(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.bitand) {
|
||||
ret cx.build.And(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.And(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.bitxor) {
|
||||
ret cx.build.Xor(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.Xor(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.lsl) {
|
||||
ret cx.build.Shl(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.Shl(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.lsr) {
|
||||
ret cx.build.LShr(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.LShr(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.asr) {
|
||||
ret cx.build.AShr(trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.AShr(lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.eq) {
|
||||
ret cx.build.ICmp(lib.llvm.LLVMIntEQ,
|
||||
trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.ICmp(lib.llvm.LLVMIntEQ, lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.ne) {
|
||||
ret cx.build.ICmp(lib.llvm.LLVMIntNE,
|
||||
trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.ICmp(lib.llvm.LLVMIntNE, lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.lt) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.ICmp(lib.llvm.LLVMIntSLT,
|
||||
trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLT, lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.le) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.ICmp(lib.llvm.LLVMIntSLE,
|
||||
trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.ICmp(lib.llvm.LLVMIntSLE, lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.ge) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.ICmp(lib.llvm.LLVMIntSGE,
|
||||
trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGE, lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
|
||||
case (ast.gt) {
|
||||
// FIXME: switch by signedness.
|
||||
ret cx.build.ICmp(lib.llvm.LLVMIntSGT,
|
||||
trans_expr(cx, a), trans_expr(cx, b));
|
||||
sub.val = cx.build.ICmp(lib.llvm.LLVMIntSGT, lhs.val, sub.val);
|
||||
ret sub;
|
||||
}
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("expr variant in trans_binary");
|
||||
fail;
|
||||
}
|
||||
|
||||
fn trans_expr(@block_ctxt cx, &ast.expr e) -> ValueRef {
|
||||
fn trans_if(@block_ctxt cx, &ast.expr cond,
|
||||
&ast.block thn, &option[ast.block] els) -> result {
|
||||
|
||||
auto cond_res = trans_expr(cx, cond);
|
||||
|
||||
auto then_cx = new_empty_block_ctxt(cx.fcx);
|
||||
auto then_res = trans_block(then_cx, thn);
|
||||
|
||||
auto next_cx = new_extension_block_ctxt(cx);
|
||||
then_res.bcx.build.Br(next_cx.llbb);
|
||||
auto phi;
|
||||
|
||||
alt (els) {
|
||||
case (some[ast.block](?eblk)) {
|
||||
auto else_cx = new_empty_block_ctxt(cx.fcx);
|
||||
auto else_res = trans_block(else_cx, eblk);
|
||||
cond_res.bcx.build.CondBr(cond_res.val,
|
||||
then_cx.llbb,
|
||||
else_cx.llbb);
|
||||
else_res.bcx.build.Br(next_cx.llbb);
|
||||
phi = next_cx.build.Phi(T_nil(),
|
||||
vec(then_res.val,
|
||||
else_res.val),
|
||||
vec(then_res.bcx.llbb,
|
||||
else_res.bcx.llbb));
|
||||
}
|
||||
|
||||
case (_) {
|
||||
cond_res.bcx.build.CondBr(cond_res.val,
|
||||
then_cx.llbb,
|
||||
next_cx.llbb);
|
||||
phi = next_cx.build.Phi(T_nil(),
|
||||
vec(then_res.val, C_nil()),
|
||||
vec(then_res.bcx.llbb,
|
||||
cond_res.bcx.llbb));
|
||||
}
|
||||
}
|
||||
|
||||
ret res(next_cx, phi);
|
||||
}
|
||||
|
||||
fn trans_expr(@block_ctxt cx, &ast.expr e) -> result {
|
||||
alt (e) {
|
||||
case (ast.expr_lit(?lit)) {
|
||||
ret trans_lit(cx, *lit);
|
||||
@ -458,54 +557,70 @@ fn trans_expr(@block_ctxt cx, &ast.expr e) -> ValueRef {
|
||||
case (ast.expr_binary(?op, ?x, ?y)) {
|
||||
ret trans_binary(cx, op, *x, *y);
|
||||
}
|
||||
|
||||
case (ast.expr_if(?cond, ?thn, ?els)) {
|
||||
ret trans_if(cx, *cond, thn, els);
|
||||
}
|
||||
|
||||
case (ast.expr_block(?blk)) {
|
||||
auto sub_cx = new_empty_block_ctxt(cx.fcx);
|
||||
auto next_cx = new_extension_block_ctxt(cx);
|
||||
auto sub = trans_block(sub_cx, blk);
|
||||
|
||||
cx.build.Br(sub_cx.llbb);
|
||||
sub.bcx.build.Br(next_cx.llbb);
|
||||
|
||||
ret res(next_cx, sub.val);
|
||||
}
|
||||
}
|
||||
cx.fcx.tcx.sess.unimpl("expr variant in trans_expr");
|
||||
fail;
|
||||
}
|
||||
|
||||
fn trans_log(@block_ctxt cx, &ast.expr e) {
|
||||
fn trans_log(@block_ctxt cx, &ast.expr e) -> result {
|
||||
alt (e) {
|
||||
case (ast.expr_lit(?lit)) {
|
||||
alt (*lit) {
|
||||
case (ast.lit_str(_)) {
|
||||
auto v = trans_expr(cx, e);
|
||||
trans_upcall(cx, "upcall_log_str",
|
||||
vec(cx.build.PtrToInt(v, T_int())));
|
||||
auto sub = trans_expr(cx, e);
|
||||
auto v = sub.bcx.build.PtrToInt(sub.val, T_int());
|
||||
ret trans_upcall(sub.bcx,
|
||||
"upcall_log_str",
|
||||
vec(v));
|
||||
}
|
||||
|
||||
case (_) {
|
||||
auto v = trans_expr(cx, e);
|
||||
trans_upcall(cx, "upcall_log_int", vec(v));
|
||||
auto sub = trans_expr(cx, e);
|
||||
ret trans_upcall(sub.bcx,
|
||||
"upcall_log_int",
|
||||
vec(sub.val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (_) {
|
||||
auto v = trans_expr(cx, e);
|
||||
trans_upcall(cx, "upcall_log_int", vec(v));
|
||||
auto sub = trans_expr(cx, e);
|
||||
ret trans_upcall(sub.bcx, "upcall_log_int", vec(sub.val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_stmt(@block_ctxt cx, &ast.stmt s) {
|
||||
fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
|
||||
auto sub = res(cx, C_nil());
|
||||
alt (s) {
|
||||
case (ast.stmt_log(?a)) {
|
||||
trans_log(cx, *a);
|
||||
sub.bcx = trans_log(cx, *a).bcx;
|
||||
}
|
||||
|
||||
case (ast.stmt_expr(?e)) {
|
||||
sub.bcx = trans_expr(cx, *e).bcx;
|
||||
}
|
||||
|
||||
case (_) {
|
||||
cx.fcx.tcx.sess.unimpl("stmt variant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn terminate_ret_void(@fn_ctxt cx, builder build) {
|
||||
build.RetVoid();
|
||||
}
|
||||
|
||||
|
||||
fn terminate_branch_to(@fn_ctxt cx, builder build, BasicBlockRef bb) {
|
||||
build.Br(bb);
|
||||
}
|
||||
|
||||
fn terminate_no_op(@fn_ctxt cx, builder build) {
|
||||
ret sub;
|
||||
}
|
||||
|
||||
fn new_builder(BasicBlockRef llbb) -> builder {
|
||||
@ -514,10 +629,12 @@ fn new_builder(BasicBlockRef llbb) -> builder {
|
||||
ret builder(llbuild);
|
||||
}
|
||||
|
||||
fn new_block_ctxt(@fn_ctxt cx, terminator term) -> @block_ctxt {
|
||||
// You probably don't want to use this one. See the
|
||||
// next three functions instead.
|
||||
fn new_block_ctxt(@fn_ctxt cx, terminator term,
|
||||
vec[cleanup] cleanups) -> @block_ctxt {
|
||||
let BasicBlockRef llbb =
|
||||
llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf(""));
|
||||
let vec[cleanup] cleanups = vec();
|
||||
ret @rec(llbb=llbb,
|
||||
build=new_builder(llbb),
|
||||
term=term,
|
||||
@ -525,21 +642,59 @@ fn new_block_ctxt(@fn_ctxt cx, terminator term) -> @block_ctxt {
|
||||
fcx=cx);
|
||||
}
|
||||
|
||||
fn trans_block(@fn_ctxt cx, &ast.block b, terminator term) {
|
||||
auto bcx = (new_block_ctxt(cx, term));
|
||||
for (@ast.stmt s in b) {
|
||||
trans_stmt(bcx, *s);
|
||||
}
|
||||
// Use this when you are making a block_ctxt to replace the
|
||||
// current one, i.e. when chaining together sequences of stmts
|
||||
// or making sub-blocks you will branch back out of and wish to
|
||||
// "carry on" in the parent block's context.
|
||||
fn new_extension_block_ctxt(@block_ctxt bcx) -> @block_ctxt {
|
||||
ret new_block_ctxt(bcx.fcx, bcx.term, bcx.cleanups);
|
||||
}
|
||||
|
||||
for (cleanup c in bcx.cleanups) {
|
||||
// Use this when you're at the top block of a function or the like.
|
||||
fn new_top_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
|
||||
fn terminate_ret_void(@fn_ctxt cx, builder build) {
|
||||
build.RetVoid();
|
||||
}
|
||||
auto term = terminate_ret_void;
|
||||
let vec[cleanup] cleanups = vec();
|
||||
ret new_block_ctxt(fcx, term, cleanups);
|
||||
|
||||
}
|
||||
|
||||
// Use this when you are making a block_ctxt to replace the
|
||||
// current one, i.e. when chaining together sequences of stmts
|
||||
// or making sub-blocks you will branch back out of and wish to
|
||||
// "carry on" in the parent block's context.
|
||||
fn new_empty_block_ctxt(@fn_ctxt fcx) -> @block_ctxt {
|
||||
fn terminate_no_op(@fn_ctxt cx, builder build) {
|
||||
}
|
||||
auto term = terminate_no_op;
|
||||
let vec[cleanup] cleanups = vec();
|
||||
ret new_block_ctxt(fcx, term, cleanups);
|
||||
}
|
||||
|
||||
fn trans_block_cleanups(@block_ctxt cx) -> @block_ctxt {
|
||||
auto bcx = cx;
|
||||
for (cleanup c in cx.cleanups) {
|
||||
alt (c) {
|
||||
case (clean(?cfn)) {
|
||||
bcx = cfn(bcx);
|
||||
bcx = cfn(bcx).bcx;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret bcx;
|
||||
}
|
||||
|
||||
bcx.term(cx, bcx.build);
|
||||
fn trans_block(@block_ctxt cx, &ast.block b) -> result {
|
||||
auto bcx = cx;
|
||||
|
||||
for (@ast.stmt s in b) {
|
||||
bcx = trans_stmt(bcx, *s).bcx;
|
||||
}
|
||||
|
||||
bcx = trans_block_cleanups(bcx);
|
||||
bcx.term(bcx.fcx, bcx.build);
|
||||
ret res(bcx, C_nil());
|
||||
}
|
||||
|
||||
fn new_fn_ctxt(@trans_ctxt cx,
|
||||
@ -550,7 +705,7 @@ fn new_fn_ctxt(@trans_ctxt cx,
|
||||
T_taskptr() // taskptr
|
||||
);
|
||||
args += T_explicit_args;
|
||||
let ValueRef llfn = decl_cdecl_fn(cx.llmod, name, args, T_nil());
|
||||
let ValueRef llfn = decl_cdecl_fn(cx.llmod, name, args, T_void());
|
||||
cx.fns.insert(cx.path, llfn);
|
||||
let ValueRef lloutptr = llvm.LLVMGetParam(llfn, 0u);
|
||||
let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 1u);
|
||||
@ -565,9 +720,8 @@ fn trans_fn(@trans_ctxt cx, &ast._fn f) {
|
||||
let vec[TypeRef] args = vec();
|
||||
|
||||
auto fcx = new_fn_ctxt(cx, cx.path, out, args);
|
||||
auto term = terminate_ret_void;
|
||||
|
||||
trans_block(fcx, f.body, term);
|
||||
trans_block(new_top_block_ctxt(fcx), f.body);
|
||||
}
|
||||
|
||||
fn trans_item(@trans_ctxt cx, &str name, &ast.item item) {
|
||||
@ -596,7 +750,6 @@ fn p2i(ValueRef v) -> ValueRef {
|
||||
fn trans_exit_task_glue(@trans_ctxt cx) {
|
||||
let vec[TypeRef] T_args = vec();
|
||||
let vec[ValueRef] V_args = vec();
|
||||
auto term = terminate_ret_void;
|
||||
|
||||
auto llfn = cx.glues.exit_task_glue;
|
||||
let ValueRef lloutptr = C_null(T_int());
|
||||
@ -606,7 +759,7 @@ fn trans_exit_task_glue(@trans_ctxt cx) {
|
||||
lltaskptr=lltaskptr,
|
||||
tcx=cx);
|
||||
|
||||
auto bcx = new_block_ctxt(fcx, term);
|
||||
auto bcx = new_top_block_ctxt(fcx);
|
||||
trans_upcall(bcx, "upcall_exit", V_args);
|
||||
bcx.term(fcx, bcx.build);
|
||||
}
|
||||
@ -705,7 +858,7 @@ fn trans_crate(session.session sess, ast.crate crate) {
|
||||
*/
|
||||
exit_task_glue =
|
||||
decl_cdecl_fn(llmod, abi.exit_task_glue_name(),
|
||||
vec(T_taskptr()), T_nil()),
|
||||
vec(T_taskptr()), T_void()),
|
||||
|
||||
upcall_glues =
|
||||
_vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
|
||||
|
@ -4,6 +4,14 @@ import std._int;
|
||||
type pos = rec(uint line, uint col);
|
||||
type span = rec(str filename, pos lo, pos hi);
|
||||
|
||||
// FIXME: import std.util.option and use it here.
|
||||
// import std.util.option;
|
||||
|
||||
tag option[T] {
|
||||
none;
|
||||
some(T);
|
||||
}
|
||||
|
||||
tag ty_mach {
|
||||
ty_i8;
|
||||
ty_i16;
|
||||
|
Loading…
Reference in New Issue
Block a user