<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.


use back::link;
use lib;
use lib::llvm::*;
use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
use middle::lang_items::LogTypeFnLangItem;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::debuginfo;
use middle::trans::expr;
use middle::trans::type_of::*;
use middle::ty;
use util::common::indenter;
use util::ppaux;

use middle::trans::type_::Type;

use syntax::ast;
use syntax::ast::ident;
use syntax::ast_map::path_mod;
use syntax::ast_util;
use syntax::codemap::span;

pub fn trans_block(bcx: @mut Block, b: &ast::Block, dest: expr::Dest) -> @mut Block {
    let _icx = push_ctxt("trans_block");
    let mut bcx = bcx;
    for b.stmts.iter().advance |s| {
        debuginfo::update_source_pos(bcx, b.span);
        bcx = trans_stmt(bcx, *s);
    }
    match b.expr {
        Some(e) => {
            debuginfo::update_source_pos(bcx, e.span);
            bcx = expr::trans_into(bcx, e, dest);
        }
        None => {
            assert!(dest == expr::Ignore || bcx.unreachable);
        }
    }
    return bcx;
}

pub fn trans_if(bcx: @mut Block,
            cond: @ast::expr,
            thn: &ast::Block,
            els: Option<@ast::expr>,
            dest: expr::Dest)
         -> @mut Block {
    debug!("trans_if(bcx=%s, cond=%s, thn=%?, dest=%s)",
           bcx.to_str(), bcx.expr_to_str(cond), thn.id,
           dest.to_str(bcx.ccx()));
    let _indenter = indenter();

    let _icx = push_ctxt("trans_if");

    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 { .. }]
            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;
        } else {
            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;
                }
                // if false { .. }
                None => return bcx,
            }
        }
    }

    let then_bcx_in = scope_block(bcx, thn.info(), "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));

    // Calling trans_block directly instead of trans_expr
    // because trans_expr will create another scope block
    // context for the block, but we've already got the
    // '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");
          (else_bcx_in, join_blocks(bcx, [then_bcx_out, else_bcx_out]))
      }
      _ => {
          let next_bcx = sub_block(bcx, "next");
          Br(then_bcx_out, next_bcx.llbb);

          (next_bcx, next_bcx)
      }
    };

    debug!("then_bcx_in=%s, else_bcx_in=%s",
           then_bcx_in.to_str(), else_bcx_in.to_str());

    CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
    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);
        let else_bcx_out = match elexpr.node {
            ast::expr_if(_, _, _) => {
                let elseif_blk = ast_util::block_from_expr(elexpr);
                trans_block(else_bcx_in, &elseif_blk, dest)
            }
            ast::expr_block(ref blk) => {
                trans_block(else_bcx_in, blk, dest)
            }
            // would be nice to have a constraint on ifs
            _ => bcx.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)
    }
}

pub fn join_blocks(parent_bcx: @mut Block, in_cxs: &[@mut Block]) -> @mut Block {
    let out = sub_block(parent_bcx, "join");
    let mut reachable = false;
    for in_cxs.iter().advance |bcx| {
        if !bcx.unreachable {
            Br(*bcx, out.llbb);
            reachable = true;
        }
    }
    if !reachable {
        Unreachable(out);<commit_msg>Generate branchless code when "if" can be evaluated at compile time<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.


use back::link;
use lib;
use lib::llvm::*;
use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
use middle::lang_items::LogTypeFnLangItem;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::debuginfo;
use middle::trans::expr;
use middle::trans::type_of::*;
use middle::ty;
use util::common::indenter;
use util::ppaux;

use middle::trans::type_::Type;

use syntax::ast;
use syntax::ast::ident;
use syntax::ast_map::path_mod;
use syntax::ast_util;
use syntax::codemap::span;

pub fn trans_block(bcx: @mut Block, b: &ast::Block, dest: expr::Dest) -> @mut Block {
    let _icx = push_ctxt("trans_block");
    let mut bcx = bcx;
    for b.stmts.iter().advance |s| {
        debuginfo::update_source_pos(bcx, b.span);
        bcx = trans_stmt(bcx, *s);
    }
    match b.expr {
        Some(e) => {
            debuginfo::update_source_pos(bcx, e.span);
            bcx = expr::trans_into(bcx, e, dest);
        }
        None => {
            assert!(dest == expr::Ignore || bcx.unreachable);
        }
    }
    return bcx;
}

pub fn trans_if(bcx: @mut Block,
            cond: @ast::expr,
            thn: &ast::Block,
            els: Option<@ast::expr>,
            dest: expr::Dest)
         -> @mut Block {
    debug!("trans_if(bcx=%s, cond=%s, thn=%?, dest=%s)",
           bcx.to_str(), bcx.expr_to_str(cond), thn.id,
           dest.to_str(bcx.ccx()));
    let _indenter = indenter();

    let _icx = push_ctxt("trans_if");

    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))
            }
        } 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,
            }
        }
    }

    let then_bcx_in = scope_block(bcx, thn.info(), "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));

    // Calling trans_block directly instead of trans_expr
    // because trans_expr will create another scope block
    // context for the block, but we've already got the
    // 'else' context
    let (else_bcx_in, next_bcx) = match els {
      Some(elexpr) => {
          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]))
      }
      _ => {
          let next_bcx = sub_block(bcx, "next");
          Br(then_bcx_out, next_bcx.llbb);

          (next_bcx, next_bcx)
      }
    };

    debug!("then_bcx_in=%s, else_bcx_in=%s",
           then_bcx_in.to_str(), else_bcx_in.to_str());

    CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
    return next_bcx;

    // trans `else [ if { .. } ... | { .. } ]`
    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);
                trans_block(else_bcx_in, &elseif_blk, dest)
            }
            ast::expr_block(ref blk) => {
                trans_block(else_bcx_in, blk, dest)
            }
            // would be nice to have a constraint on ifs
            _ => else_bcx_in.tcx().sess.bug("strange alternative in if")
        };
        trans_block_cleanups(else_bcx_out, block_cleanups(else_bcx_in))
    }
}

pub fn join_blocks(parent_bcx: @mut Block, in_cxs: &[@mut Block]) -> @mut Block {
    let out = sub_block(parent_bcx, "join");
    let mut reachable = false;
    for in_cxs.iter().advance |bcx| {
        if !bcx.unreachable {
            Br(*bcx, out.llbb);
            reachable = true;
        }
    }
    if !reachable {
        Unreachable(out);
{'fraction_non_alphanumeric': 0.13565638684431194, 'fraction_numerical': 0.001863411907202087, 'mean_word_length': 2.233132530120482, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6332252', 'n_tokens_mistral': 3716, 'n_tokens_neox': 3669, 'n_words': 790}