diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 985c1048bc45d..690e488d21973 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -850,6 +850,12 @@ pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint]) } } +pub fn is_const(v: ValueRef) -> bool { + unsafe { + llvm::LLVMIsConstant(v) == True + } +} + pub fn const_to_int(v: ValueRef) -> c_longlong { unsafe { llvm::LLVMConstIntGetSExtValue(v) diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 2b6c1d8241860..8c87766bbbe1f 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -65,44 +65,36 @@ pub fn trans_if(bcx: @mut Block, let _icx = push_ctxt("trans_if"); - match cond.node { - // `if true` and `if false` can be trans'd more efficiently, - // by dropping branches that are known to be impossible. - ast::expr_lit(@ref l) => match l.node { - ast::lit_bool(true) => { - // if true { .. } [else { .. }] - let then_bcx_in = scope_block(bcx, thn.info(), "if_true_then"); - let then_bcx_out = trans_block(then_bcx_in, thn, dest); - let then_bcx_out = trans_block_cleanups(then_bcx_out, - block_cleanups(then_bcx_in)); - Br(bcx, then_bcx_in.llbb); - return then_bcx_out; + let Result {bcx, val: cond_val} = + expr::trans_to_datum(bcx, cond).to_result(); + + let cond_val = bool_to_i1(bcx, cond_val); + + // Drop branches that are known to be impossible + if is_const(cond_val) && !is_undef(cond_val) { + if const_to_uint(cond_val) == 1 { + // if true { .. } [else { .. }] + return do with_scope(bcx, thn.info(), "if_true_then") |bcx| { + let bcx_out = trans_block(bcx, thn, dest); + trans_block_cleanups(bcx_out, block_cleanups(bcx)) } - ast::lit_bool(false) => { - match els { - // if false { .. } else { .. } - Some(elexpr) => { - let (else_bcx_in, else_bcx_out) = - trans_if_else(bcx, elexpr, dest, "if_false_else"); - Br(bcx, else_bcx_in.llbb); - return else_bcx_out; + } else { + match els { + // if false { .. } else { .. } + Some(elexpr) => { + return do with_scope(bcx, elexpr.info(), "if_false_then") |bcx| { + let bcx_out = trans_if_else(bcx, elexpr, dest); + trans_block_cleanups(bcx_out, block_cleanups(bcx)) } - // if false { .. } - None => return bcx, } + // if false { .. } + None => return bcx, } - _ => {} - }, - _ => {} + } } - let Result {bcx, val: cond_val} = - expr::trans_to_datum(bcx, cond).to_result(); - let then_bcx_in = scope_block(bcx, thn.info(), "then"); - let cond_val = bool_to_i1(bcx, cond_val); - let then_bcx_out = trans_block(then_bcx_in, thn, dest); let then_bcx_out = trans_block_cleanups(then_bcx_out, block_cleanups(then_bcx_in)); @@ -113,7 +105,8 @@ pub fn trans_if(bcx: @mut Block, // 'else' context let (else_bcx_in, next_bcx) = match els { Some(elexpr) => { - let (else_bcx_in, else_bcx_out) = trans_if_else(bcx, elexpr, dest, "else"); + let else_bcx_in = scope_block(bcx, elexpr.info(), "else"); + let else_bcx_out = trans_if_else(else_bcx_in, elexpr, dest); (else_bcx_in, join_blocks(bcx, [then_bcx_out, else_bcx_out])) } _ => { @@ -131,9 +124,8 @@ pub fn trans_if(bcx: @mut Block, return next_bcx; // trans `else [ if { .. } ... | { .. } ]` - fn trans_if_else(bcx: @mut Block, elexpr: @ast::expr, - dest: expr::Dest, scope_name: &str) -> (@mut Block, @mut Block) { - let else_bcx_in = scope_block(bcx, elexpr.info(), scope_name); + fn trans_if_else(else_bcx_in: @mut Block, elexpr: @ast::expr, + dest: expr::Dest) -> @mut Block { let else_bcx_out = match elexpr.node { ast::expr_if(_, _, _) => { let elseif_blk = ast_util::block_from_expr(elexpr); @@ -143,11 +135,9 @@ pub fn trans_if(bcx: @mut Block, trans_block(else_bcx_in, blk, dest) } // would be nice to have a constraint on ifs - _ => bcx.tcx().sess.bug("strange alternative in if") + _ => else_bcx_in.tcx().sess.bug("strange alternative in if") }; - let else_bcx_out = trans_block_cleanups(else_bcx_out, - block_cleanups(else_bcx_in)); - (else_bcx_in, else_bcx_out) + trans_block_cleanups(else_bcx_out, block_cleanups(else_bcx_in)) } }