diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 83e775c847d..9d195c44ada 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -251,7 +251,10 @@ options: --time-llvm-passes time the individual phases of the LLVM backend --sysroot override the system root (default: rustc's directory) --no-typestate don't run the typestate pass (unsafe!) - --test build test harness\n\n"); + --test build test harness + --dps translate via destination-passing style (experimental) + +"); } fn get_os(str triple) -> session::os { @@ -352,6 +355,7 @@ fn build_session_options(str binary, getopts::match match, str binary_dir) -> }; auto cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg")); auto test = opt_present(match, "test"); + auto dps = opt_present(match, "dps"); let @session::options sopts = @rec(library=library, static=static, @@ -367,7 +371,8 @@ fn build_session_options(str binary, getopts::match match, str binary_dir) -> library_search_paths=library_search_paths, sysroot=sysroot, cfg=cfg, - test=test); + test=test, + dps=dps); ret sopts; } @@ -398,7 +403,7 @@ fn opts() -> vec[getopts::opt] { optopt("sysroot"), optflag("stats"), optflag("time-passes"), optflag("time-llvm-passes"), optflag("no-typestate"), optflag("noverify"), optmulti("cfg"), optflag("test"), - optflag("lib"), optflag("static")]; + optflag("lib"), optflag("static"), optflag("dps")]; } fn main(vec[str] args) { diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index f07fbc6f859..8c15b8bf0a1 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -40,7 +40,8 @@ type options = // The crate config requested for the session, which may be combined // with additional crate configurations during the compile process ast::crate_cfg cfg, - bool test); + bool test, + bool dps); type crate_metadata = rec(str name, u8[] data); diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 4a1fd810174..02a85383e35 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -7083,19 +7083,27 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ValueRef llfndecl, auto lltop = bcx.llbb; auto block_ty = node_id_type(cx.ccx, f.body.node.id); - // This call to trans_block is the place where we bridge between - // translation calls that don't have a return value (trans_crate, - // trans_mod, trans_item, trans_obj, et cetera) and those that do - // (trans_block, trans_expr, et cetera). - auto rslt = - if (!ty::type_is_nil(cx.ccx.tcx, block_ty) && - !ty::type_is_bot(cx.ccx.tcx, block_ty)) { - trans_block(bcx, f.body, save_in(fcx.llretptr)) - } else { trans_block(bcx, f.body, return) }; - if (!is_terminated(rslt.bcx)) { + if (cx.ccx.sess.get_opts().dps) { + // Call into the new destination-passing-style translation engine. + auto dest = trans_dps::dest_move(cx.ccx.tcx, fcx.llretptr, block_ty); + bcx = trans_dps::trans_block(bcx, dest, f.body); + } else { + // This call to trans_block is the place where we bridge between + // translation calls that don't have a return value (trans_crate, + // trans_mod, trans_item, trans_obj, et cetera) and those that do + // (trans_block, trans_expr, et cetera). + auto rslt = + if (!ty::type_is_nil(cx.ccx.tcx, block_ty) && + !ty::type_is_bot(cx.ccx.tcx, block_ty)) { + trans_block(bcx, f.body, save_in(fcx.llretptr)) + } else { trans_block(bcx, f.body, return) }; + bcx = rslt.bcx; + } + + if (!is_terminated(bcx)) { // FIXME: until LLVM has a unit type, we are moving around // C_nil values rather than their void type. - rslt.bcx.build.RetVoid(); + bcx.build.RetVoid(); } // Insert the mandatory first few basic blocks before lltop. diff --git a/src/comp/middle/trans_dps.rs b/src/comp/middle/trans_dps.rs new file mode 100644 index 00000000000..f118c0ef057 --- /dev/null +++ b/src/comp/middle/trans_dps.rs @@ -0,0 +1,156 @@ +// Translates individual functions in the completed AST to the LLVM IR, using +// destination-passing style. + +import syntax::ast; +import middle::trans; +import middle::ty; +import trans::block_ctxt; +import trans::crate_ctxt; +import trans::fn_ctxt; +import trans::local_ctxt; +import lib::llvm::llvm::TypeRef; +import lib::llvm::llvm::ValueRef; +import std::option::none; +import std::option::some; + +import type_of_node = trans::node_id_type; + + +// LLVM utilities + +fn llelement_type(TypeRef llty) -> TypeRef { + lib::llvm::llvm::LLVMGetElementType(llty) +} + + +// Destination utilities + +tag dest_slot { + dst_nil; + dst_val(ValueRef); +} + +type dest = rec(dest_slot slot, bool move); + +fn dest_slot_for_ptr(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest_slot { + if ty::type_is_nil(tcx, t) { dst_nil } else { dst_val(llptr) } +} + +fn dest_copy(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest { + ret rec(slot=dest_slot_for_ptr(tcx, llptr, t), move=false); +} + +fn dest_move(&ty::ctxt tcx, ValueRef llptr, ty::t t) -> dest { + ret rec(slot=dest_slot_for_ptr(tcx, llptr, t), move=true); +} + +fn dest_tmp(&@block_ctxt bcx, ty::t t) -> tup(@block_ctxt, dest) { + if ty::type_is_nil(bcx_tcx(bcx), t) { + ret tup(bcx, rec(slot=dst_nil, move=true)); + } + auto r = trans::alloc_ty(bcx, t); + ret tup(r.bcx, dest_move(bcx_tcx(bcx), r.val, t)); +} + + +// Accessors +// TODO: When we have overloading, simplify these names! + +fn bcx_tcx(&@block_ctxt bcx) -> ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; } +fn bcx_ccx(&@block_ctxt bcx) -> @crate_ctxt { ret bcx.fcx.lcx.ccx; } +fn bcx_lcx(&@block_ctxt bcx) -> @local_ctxt { ret bcx.fcx.lcx; } +fn bcx_fcx(&@block_ctxt bcx) -> @fn_ctxt { ret bcx.fcx; } + + +// Common operations + +fn store(&@block_ctxt bcx, &dest dest, ValueRef llsrc) -> @block_ctxt { + alt (dest.slot) { + dst_nil { /* no-op */ } + dst_val(?lldest) { bcx.build.Store(llsrc, lldest); } + } + ret bcx; +} + + +// AST substructure translation, with destinations + +fn trans_expr(&@block_ctxt bcx, &dest dest, &@ast::expr expr) -> @block_ctxt { + ret bcx; // TODO +} + +fn trans_recv(&@block_ctxt bcx, &dest dest, &@ast::expr expr) -> @block_ctxt { + ret bcx; // TODO +} + +fn trans_block(&@block_ctxt cx, &dest dest, &ast::block block) + -> @block_ctxt { + auto bcx = cx; + for each (@ast::local local in trans::block_locals(block)) { + bcx = trans::alloc_local(bcx, local).bcx; + } + + for (@ast::stmt stmt in block.node.stmts) { + bcx = trans_stmt(bcx, stmt); + + // If we hit a terminator, control won't go any further so + // we're in dead-code land. Stop here. + if trans::is_terminated(bcx) { ret bcx; } + } + + alt (block.node.expr) { + some(?e) { ret trans_expr(bcx, dest, e); } + none { ret bcx; } + } +} + + +// AST substructure translation, without destinations + +fn trans_init_local(&@block_ctxt bcx, &@ast::local local) -> @block_ctxt { + auto llptr = bcx_fcx(bcx).lllocals.get(local.node.id); + + auto t = type_of_node(bcx_ccx(bcx), local.node.id); + trans::add_clean(bcx, llptr, t); + + alt (local.node.init) { + some(?init) { + alt (init.op) { + ast::init_assign { + ret trans_expr(bcx, dest_copy(bcx_tcx(bcx), llptr, t), init.expr); + } + ast::init_move { + ret trans_expr(bcx, dest_move(bcx_tcx(bcx), llptr, t), init.expr); + } + ast::init_recv { + ret trans_recv(bcx, dest_copy(bcx_tcx(bcx), llptr, t), init.expr); + } + } + } + none { + ret store(bcx, dest_copy(bcx_tcx(bcx), llptr, t), + trans_common::C_null(llelement_type(trans::val_ty(llptr)))); + } + } +} + +fn trans_stmt(&@block_ctxt cx, &@ast::stmt stmt) -> @block_ctxt { + auto bcx = cx; + alt (stmt.node) { + ast::stmt_expr(?e, _) { + auto tmp_r = dest_tmp(bcx, ty::expr_ty(bcx_tcx(bcx), e)); + bcx = tmp_r._0; auto tmp = tmp_r._1; + ret trans_expr(bcx, tmp, e); + } + ast::stmt_decl(?d, _) { + alt (d.node) { + ast::decl_local(?local) { ret trans_init_local(bcx, local); } + ast::decl_item(?item) { + trans::trans_item(bcx_lcx(bcx), *item); + ret bcx; + } + } + } + } +} + diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 2115e872531..a64be9f1686 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -19,6 +19,7 @@ mod middle { mod trans; mod trans_alt; mod trans_comm; + mod trans_dps; mod ty; mod ast_map; mod resolve;