Change trans::common::block to be a class

And replace trans::common::block_parent with option<block>. To handle
the recursive self-reference in the block_ class, I had to add a
newtype-like enum "block" which is equivalent to @block_ -- which due
to an interaction with borrowck, resulted in having to change a few
functions in trans::base to take their block argument in ++ mode,
irritatingly enough (but not that irritatingly, since we're supposed to
get rid of modes).
This commit is contained in:
Tim Chevalier 2012-06-12 14:55:44 -07:00
parent d1ec1d4abb
commit 72360970fc
3 changed files with 69 additions and 60 deletions

View File

@ -50,6 +50,7 @@ import type_of::type_of; // Issue #1873
import syntax::ast_map::{path, path_mod, path_name};
import std::smallintmap;
import option::is_none;
// Destinations
@ -1207,7 +1208,8 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
}
}
fn call_tydesc_glue_full(cx: block, v: ValueRef, tydesc: ValueRef,
// See [Note-arg-mode]
fn call_tydesc_glue_full(++cx: block, v: ValueRef, tydesc: ValueRef,
field: uint, static_ti: option<@tydesc_info>) {
let _icx = cx.insn_ctxt("call_tydesc_glue_full");
lazily_emit_tydesc_glue(cx.ccx(), field, static_ti);
@ -1245,8 +1247,9 @@ fn call_tydesc_glue_full(cx: block, v: ValueRef, tydesc: ValueRef,
C_null(T_ptr(T_ptr(cx.ccx().tydesc_type))), llrawptr]);
}
fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint) ->
block {
// See [Note-arg-mode]
fn call_tydesc_glue(++cx: block, v: ValueRef, t: ty::t, field: uint)
-> block {
let _icx = cx.insn_ctxt("call_tydesc_glue");
let mut ti = none;
let td = get_tydesc(cx.ccx(), t, ti);
@ -3111,8 +3114,9 @@ fn body_contains_ret(body: ast::blk) -> bool {
cx.found
}
// See [Note-arg-mode]
fn trans_call_inner(
in_cx: block,
++in_cx: block,
call_info: option<node_info>,
fn_expr_ty: ty::t,
ret_ty: ty::t,
@ -3240,8 +3244,8 @@ fn need_invoke(bcx: block) -> bool {
_ { }
}
cur = alt cur.parent {
parent_some(next) { next }
parent_none { ret false; }
some(next) { next }
none { ret false; }
}
}
}
@ -3262,7 +3266,7 @@ fn in_lpad_scope_cx(bcx: block, f: fn(scope_info)) {
loop {
alt bcx.kind {
block_scope(inf) {
if inf.cleanups.len() > 0u || bcx.parent == parent_none {
if inf.cleanups.len() > 0u || is_none(bcx.parent) {
f(inf); ret;
}
}
@ -3471,11 +3475,11 @@ fn add_root_cleanup(bcx: block, scope_id: ast::node_id,
some({id, _}) if id == scope_id { ret bcx_sid; }
_ {
alt bcx_sid.parent {
parent_none {
none {
bcx.tcx().sess.bug(
#fmt["no enclosing scope with id %d", scope_id]);
}
parent_some(bcx_par) { bcx_par }
some(bcx_par) { bcx_par }
}
}
}
@ -3785,7 +3789,10 @@ fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef {
// Since this function does *not* root, it is the caller's responsibility to
// ensure that the referent is pointed to by a root.
fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef {
// [Note-arg-mode]
// ++ mode is temporary, due to how borrowck treats enums. With hope,
// will go away anyway when we get rid of modes.
fn do_spill_noroot(++cx: block, v: ValueRef) -> ValueRef {
let llptr = alloca(cx, val_ty(v));
Store(cx, v, llptr);
ret llptr;
@ -3970,9 +3977,9 @@ fn trans_break_cont(bcx: block, to_end: bool)
_ {}
}
unwind = alt unwind.parent {
parent_some(cx) { cx }
some(cx) { cx }
// This is a return from a loop body block
parent_none {
none {
Store(bcx, C_bool(!to_end), bcx.fcx.llretptr);
cleanup_and_leave(bcx, none, some(bcx.fcx.llreturn));
Unreachable(bcx);
@ -4090,7 +4097,7 @@ fn trans_stmt(cx: block, s: ast::stmt) -> block {
// You probably don't want to use this one. See the
// next three functions instead.
fn new_block(cx: fn_ctxt, parent: block_parent, +kind: block_kind,
fn new_block(cx: fn_ctxt, parent: option<block>, +kind: block_kind,
name: str, opt_node_info: option<node_info>) -> block {
let s = if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo {
@ -4099,19 +4106,10 @@ fn new_block(cx: fn_ctxt, parent: block_parent, +kind: block_kind,
let llbb: BasicBlockRef = str::as_c_str(s, {|buf|
llvm::LLVMAppendBasicBlock(cx.llfn, buf)
});
let bcx = @{llbb: llbb,
mut terminated: false,
mut unreachable: false,
parent: parent,
kind: kind,
node_info: opt_node_info,
fcx: cx};
alt parent {
parent_some(cx) {
let bcx = mk_block(llbb, parent, kind, opt_node_info, cx);
option::iter(parent) {|cx|
if cx.unreachable { Unreachable(bcx); }
}
_ {}
}
};
ret bcx;
}
@ -4122,20 +4120,20 @@ fn simple_block_scope() -> block_kind {
// Use this when you're at the top block of a function or the like.
fn top_scope_block(fcx: fn_ctxt, opt_node_info: option<node_info>) -> block {
ret new_block(fcx, parent_none, simple_block_scope(),
ret new_block(fcx, none, simple_block_scope(),
"function top level", opt_node_info);
}
fn scope_block(bcx: block,
opt_node_info: option<node_info>,
n: str) -> block {
ret new_block(bcx.fcx, parent_some(bcx), simple_block_scope(),
ret new_block(bcx.fcx, some(bcx), simple_block_scope(),
n, opt_node_info);
}
fn loop_scope_block(bcx: block, loop_break: block, n: str,
opt_node_info: option<node_info>) -> block {
ret new_block(bcx.fcx, parent_some(bcx), block_scope({
ret new_block(bcx.fcx, some(bcx), block_scope({
loop_break: some(loop_break),
mut cleanups: [],
mut cleanup_paths: [],
@ -4146,17 +4144,11 @@ fn loop_scope_block(bcx: block, loop_break: block, n: str,
// Use this when you're making a general CFG BB within a scope.
fn sub_block(bcx: block, n: str) -> block {
ret new_block(bcx.fcx, parent_some(bcx), block_non_scope, n, none);
new_block(bcx.fcx, some(bcx), block_non_scope, n, none)
}
fn raw_block(fcx: fn_ctxt, llbb: BasicBlockRef) -> block {
ret @{llbb: llbb,
mut terminated: false,
mut unreachable: false,
parent: parent_none,
kind: block_non_scope,
node_info: none,
fcx: fcx};
mk_block(llbb, none, block_non_scope, none, fcx)
}
@ -4231,8 +4223,8 @@ fn cleanup_and_leave(bcx: block, upto: option<BasicBlockRef>,
_ {}
}
cur = alt cur.parent {
parent_some(next) { next }
parent_none { assert option::is_none(upto); break; }
some(next) { next }
none { assert is_none(upto); break; }
};
}
alt leave {

View File

@ -350,32 +350,44 @@ type node_info = {
// code. Each basic block we generate is attached to a function, typically
// with many basic blocks per function. All the basic blocks attached to a
// function are organized as a directed graph.
type block = @{
class block_ {
// The BasicBlockRef returned from a call to
// llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic
// block to the function pointed to by llfn. We insert
// instructions into that block by way of this block context.
// The block pointing to this one in the function's digraph.
llbb: BasicBlockRef,
mut terminated: bool,
mut unreachable: bool,
parent: block_parent,
let llbb: BasicBlockRef;
let mut terminated: bool;
let mut unreachable: bool;
let parent: option<block>;
// The 'kind' of basic block this is.
kind: block_kind,
let kind: block_kind;
// info about the AST node this block originated from, if any
node_info: option<node_info>,
let node_info: option<node_info>;
// The function context for the function to which this block is
// attached.
fcx: fn_ctxt
};
let fcx: fn_ctxt;
new(llbb: BasicBlockRef, parent: option<block>, -kind: block_kind,
node_info: option<node_info>, fcx: fn_ctxt) {
// sigh
self.llbb = llbb; self.terminated = false; self.unreachable = false;
self.parent = parent; self.kind = kind; self.node_info = node_info;
self.fcx = fcx;
}
}
/* This must be enum and not type, or trans goes into an infinite loop (#2572)
*/
enum block = @block_;
fn mk_block(llbb: BasicBlockRef, parent: option<block>, -kind: block_kind,
node_info: option<node_info>, fcx: fn_ctxt) -> block {
block(@block_(llbb, parent, kind, node_info, fcx))
}
// First two args are retptr, env
const first_real_arg: uint = 2u;
// FIXME move blocks to a class once those are finished, and simply use
// option<block> for this. (#2532)
enum block_parent { parent_none, parent_some(block), }
type result = {bcx: block, val: ValueRef};
type result_t = {bcx: block, val: ValueRef, ty: ty::t};
@ -412,7 +424,11 @@ fn in_scope_cx(cx: block, f: fn(scope_info)) {
}
fn block_parent(cx: block) -> block {
alt check cx.parent { parent_some(b) { b } }
alt cx.parent {
some(b) { b }
none { cx.sess().bug(#fmt("block_parent called on root block %?",
cx)); }
}
}
// Accessors

View File

@ -236,8 +236,8 @@ fn create_block(cx: block) -> @metadata<block_md> {
let mut cx = cx;
while option::is_none(cx.node_info) {
alt cx.parent {
parent_some(b) { cx = b; }
parent_none { fail; }
some(b) { cx = b; }
none { fail; }
}
}
let sp = option::get(cx.node_info).span;
@ -254,8 +254,8 @@ fn create_block(cx: block) -> @metadata<block_md> {
}*/
let parent = alt cx.parent {
parent_none { create_function(cx.fcx).node }
parent_some(bcx) { create_block(bcx).node }
none { create_function(cx.fcx).node }
some(bcx) { create_block(bcx).node }
};
let file_node = create_file(cx.ccx(), fname);
let unique_id = alt cache.find(LexicalBlockTag) {
@ -658,8 +658,8 @@ fn create_local_var(bcx: block, local: @ast::local)
let tymd = create_ty(cx, ty, local.node.ty);
let filemd = create_file(cx, loc.file.name);
let context = alt bcx.parent {
parent_none { create_function(bcx.fcx).node }
parent_some(_) { create_block(bcx).node }
none { create_function(bcx.fcx).node }
some(_) { create_block(bcx).node }
};
let mdnode = create_var(tg, context, name, filemd.node,
loc.line as int, tymd.node);
@ -761,9 +761,10 @@ fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
(nm, decl.output, ctor_id)
}
ast_map::class_ctor(ctor,_) {
fcx.ccx.sess.span_bug(ctor.span, "create_function: \
expected a resource ctor here"); }
// FIXME: output type may be wrong (#2194)
(nm, ctor.node.dec.output, ctor.node.id)
}
}
}
ast_map::node_expr(expr) {
alt expr.node {