]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #8270 : dotdash/rust/ret_alloca_elim, r=pcwalton
authorbors <bors@rust-lang.org>
Sat, 10 Aug 2013 11:44:13 +0000 (04:44 -0700)
committerbors <bors@rust-lang.org>
Sat, 10 Aug 2013 11:44:13 +0000 (04:44 -0700)
When there is only a single store to the ret slot that dominates the
load that gets the value for the "ret" instruction, we can elide the
ret slot and directly return the operand of the dominating store
instruction. This is the same thing that clang does, except for a
special case that doesn't seem to affect us.

Fixes #8238

1  2 
src/librustc/lib/llvm.rs
src/librustc/middle/trans/base.rs

diff --combined src/librustc/lib/llvm.rs
index e879168eabff2d55d69e0095ed4bfd4038564abe,11a2429cb8372be1e2a2bc8cad68802ac1cd62d6..5801e43a54cd2ba0bfd7d02757a35909b18ee931
@@@ -8,7 -8,7 +8,7 @@@
  // option. This file may not be copied, modified, or distributed
  // except according to those terms.
  
 -
 +use std::c_str::ToCStr;
  use std::hashmap::HashMap;
  use std::libc::{c_uint, c_ushort};
  use std::option;
@@@ -1553,6 -1553,8 +1553,8 @@@ pub mod llvm 
          /* Selected entries from the downcasts. */
          #[fast_ffi]
          pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef;
+         #[fast_ffi]
+         pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef;
  
          /** Writes a module to the specified path. Returns 0 on success. */
          #[fast_ffi]
@@@ -2259,7 -2261,7 +2261,7 @@@ pub struct TargetData 
  }
  
  pub fn mk_target_data(string_rep: &str) -> TargetData {
 -    let lltd = do string_rep.as_c_str |buf| {
 +    let lltd = do string_rep.to_c_str().with_ref |buf| {
          unsafe { llvm::LLVMCreateTargetData(buf) }
      };
  
index 6b51832e8e337d1cdff995b9f94266cf8003b5c6,170c6dc33520233eefb0e88a47ba28694ad038b9..cbb338a1e2425ec82afdd7c336a86865b8e81b3b
@@@ -59,13 -59,13 +59,14 @@@ use middle::trans::monomorphize
  use middle::trans::tvec;
  use middle::trans::type_of;
  use middle::trans::type_of::*;
+ use middle::trans::value::Value;
  use middle::ty;
  use util::common::indenter;
  use util::ppaux::{Repr, ty_to_str};
  
  use middle::trans::type_::Type;
  
 +use std::c_str::ToCStr;
  use std::hash;
  use std::hashmap::HashMap;
  use std::io;
@@@ -180,7 -180,7 +181,7 @@@ impl<'self> Drop for StatRecorder<'self
  }
  
  pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
 -    let llfn: ValueRef = do name.as_c_str |buf| {
 +    let llfn: ValueRef = do name.to_c_str().with_ref |buf| {
          unsafe {
              llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref())
          }
@@@ -220,7 -220,7 +221,7 @@@ pub fn get_extern_const(externs: &mut E
          None => ()
      }
      unsafe {
 -        let c = do name.as_c_str |buf| {
 +        let c = do name.to_c_str().with_ref |buf| {
              llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf)
          };
          externs.insert(name, c);
@@@ -522,7 -522,7 +523,7 @@@ pub fn get_res_dtor(ccx: @mut CrateCont
  // Structural comparison: a rather involved form of glue.
  pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
      if cx.sess.opts.save_temps {
 -        do s.as_c_str |buf| {
 +        do s.to_c_str().with_ref |buf| {
              unsafe {
                  llvm::LLVMSetValueName(v, buf)
              }
@@@ -1136,7 -1136,7 +1137,7 @@@ pub fn new_block(cx: @mut FunctionConte
                   opt_node_info: Option<NodeInfo>)
                -> @mut Block {
      unsafe {
 -        let llbb = do name.as_c_str |buf| {
 +        let llbb = do name.to_c_str().with_ref |buf| {
              llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf)
          };
          let bcx = @mut Block::new(llbb,
@@@ -1553,7 -1553,7 +1554,7 @@@ pub struct BasicBlocks 
  pub fn mk_staticallocas_basic_block(llfn: ValueRef) -> BasicBlockRef {
      unsafe {
          let cx = task_llcx();
 -        do "static_allocas".as_c_str | buf| {
 +        do "static_allocas".to_c_str().with_ref | buf| {
              llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)
          }
      }
  pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef {
      unsafe {
          let cx = task_llcx();
 -        do "return".as_c_str |buf| {
 +        do "return".to_c_str().with_ref |buf| {
              llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)
          }
      }
@@@ -1792,11 -1792,30 +1793,30 @@@ pub fn finish_fn(fcx: @mut FunctionCont
  // Builds the return block for a function.
  pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
      // Return the value if this function immediate; otherwise, return void.
-     if fcx.llretptr.is_some() && fcx.has_immediate_return_value {
-         Ret(ret_cx, Load(ret_cx, fcx.llretptr.unwrap()))
-     } else {
-         RetVoid(ret_cx)
+     if fcx.llretptr.is_none() || !fcx.has_immediate_return_value {
+         return RetVoid(ret_cx);
      }
+     let retptr = Value(fcx.llretptr.unwrap());
+     let retval = match retptr.get_dominating_store(ret_cx) {
+         // If there's only a single store to the ret slot, we can directly return
+         // the value that was stored and omit the store and the alloca
+         Some(s) => {
+             let retval = *s.get_operand(0).unwrap();
+             s.erase_from_parent();
+             if retptr.has_no_uses() {
+                 retptr.erase_from_parent();
+             }
+             retval
+         }
+         // Otherwise, load the return value from the ret slot
+         None => Load(ret_cx, fcx.llretptr.unwrap())
+     };
+     Ret(ret_cx, retval);
  }
  
  pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
@@@ -2313,7 -2332,7 +2333,7 @@@ pub fn create_entry_wrapper(ccx: @mut C
              };
              decl_cdecl_fn(ccx.llmod, main_name, llfty)
          };
 -        let llbb = do "top".as_c_str |buf| {
 +        let llbb = do "top".to_c_str().with_ref |buf| {
              unsafe {
                  llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
              }
              llvm::LLVMPositionBuilderAtEnd(bld, llbb);
  
              let crate_map = ccx.crate_map;
 -            let opaque_crate_map = do "crate_map".as_c_str |buf| {
 +            let opaque_crate_map = do "crate_map".to_c_str().with_ref |buf| {
                  llvm::LLVMBuildPointerCast(bld, crate_map, Type::i8p().to_ref(), buf)
              };
  
                  };
  
                  let args = {
 -                    let opaque_rust_main = do "rust_main".as_c_str |buf| {
 +                    let opaque_rust_main = do "rust_main".to_c_str().with_ref |buf| {
                          llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p().to_ref(), buf)
                      };
  
                  (rust_main, args)
              };
  
 -            let result = llvm::LLVMBuildCall(bld,
 -                                             start_fn,
 -                                             &args[0],
 -                                             args.len() as c_uint,
 -                                             noname());
 +            let result = do args.as_imm_buf |buf, len| {
 +                llvm::LLVMBuildCall(bld, start_fn, buf, len as c_uint, noname())
 +            };
 +
              llvm::LLVMBuildRet(bld, result);
          }
      }
@@@ -2428,7 -2448,7 +2448,7 @@@ pub fn get_item_val(ccx: @mut CrateCont
  
                              unsafe {
                                  let llty = llvm::LLVMTypeOf(v);
 -                                let g = do sym.as_c_str |buf| {
 +                                let g = do sym.to_c_str().with_ref |buf| {
                                      llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
                                  };
  
  
                      match (attr::first_attr_value_str_by_name(i.attrs, "link_section")) {
                          Some(sect) => unsafe {
 -                            do sect.as_c_str |buf| {
 +                            do sect.to_c_str().with_ref |buf| {
                                  llvm::LLVMSetSection(v, buf);
                              }
                          },
                          }
                          ast::foreign_item_static(*) => {
                              let ident = token::ident_to_str(&ni.ident);
 -                            let g = do ident.as_c_str |buf| {
 +                            let g = do ident.to_c_str().with_ref |buf| {
                                  unsafe {
                                      let ty = type_of(ccx, ty);
                                      llvm::LLVMAddGlobal(ccx.llmod, ty.to_ref(), buf)
@@@ -2600,7 -2620,7 +2620,7 @@@ pub fn trans_constant(ccx: &mut CrateCo
              let s = mangle_exported_name(ccx, p, ty::mk_int()).to_managed();
              let disr_val = vi[i].disr_val;
              note_unique_llvm_symbol(ccx, s);
 -            let discrim_gvar = do s.as_c_str |buf| {
 +            let discrim_gvar = do s.to_c_str().with_ref |buf| {
                  unsafe {
                      llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)
                  }
@@@ -2741,7 -2761,7 +2761,7 @@@ pub fn decl_gc_metadata(ccx: &mut Crate
      }
  
      let gc_metadata_name = ~"_gc_module_metadata_" + llmod_id;
 -    let gc_metadata = do gc_metadata_name.as_c_str |buf| {
 +    let gc_metadata = do gc_metadata_name.to_c_str().with_ref |buf| {
          unsafe {
              llvm::LLVMAddGlobal(ccx.llmod, Type::i32().to_ref(), buf)
          }
  pub fn create_module_map(ccx: &mut CrateContext) -> ValueRef {
      let elttype = Type::struct_([ccx.int_type, ccx.int_type], false);
      let maptype = Type::array(&elttype, (ccx.module_data.len() + 1) as u64);
 -    let map = do "_rust_mod_map".as_c_str |buf| {
 +    let map = do "_rust_mod_map".to_c_str().with_ref |buf| {
          unsafe {
              llvm::LLVMAddGlobal(ccx.llmod, maptype.to_ref(), buf)
          }
@@@ -2804,7 -2824,7 +2824,7 @@@ pub fn decl_crate_map(sess: session::Se
      let sym_name = ~"_rust_crate_map_" + mapname;
      let arrtype = Type::array(&int_type, n_subcrates as u64);
      let maptype = Type::struct_([Type::i32(), Type::i8p(), int_type, arrtype], false);
 -    let map = do sym_name.as_c_str |buf| {
 +    let map = do sym_name.to_c_str().with_ref |buf| {
          unsafe {
              llvm::LLVMAddGlobal(llmod, maptype.to_ref(), buf)
          }
@@@ -2823,7 -2843,7 +2843,7 @@@ pub fn fill_crate_map(ccx: @mut CrateCo
                        cdata.name,
                        cstore::get_crate_vers(cstore, i),
                        cstore::get_crate_hash(cstore, i));
 -        let cr = do nm.as_c_str |buf| {
 +        let cr = do nm.to_c_str().with_ref |buf| {
              unsafe {
                  llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf)
              }
@@@ -2886,21 -2906,21 +2906,21 @@@ pub fn write_metadata(cx: &mut CrateCon
      let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item);
      let llmeta = C_bytes(encoder::encode_metadata(encode_parms, crate));
      let llconst = C_struct([llmeta]);
 -    let mut llglobal = do "rust_metadata".as_c_str |buf| {
 +    let mut llglobal = do "rust_metadata".to_c_str().with_ref |buf| {
          unsafe {
              llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst).to_ref(), buf)
          }
      };
      unsafe {
          llvm::LLVMSetInitializer(llglobal, llconst);
 -        do cx.sess.targ_cfg.target_strs.meta_sect_name.as_c_str |buf| {
 +        do cx.sess.targ_cfg.target_strs.meta_sect_name.to_c_str().with_ref |buf| {
              llvm::LLVMSetSection(llglobal, buf)
          };
          lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
  
          let t_ptr_i8 = Type::i8p();
          llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8.to_ref());
 -        let llvm_used = do "llvm.used".as_c_str |buf| {
 +        let llvm_used = do "llvm.used".to_c_str().with_ref |buf| {
              llvm::LLVMAddGlobal(cx.llmod, Type::array(&t_ptr_i8, 1).to_ref(), buf)
          };
          lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage);
@@@ -2914,7 -2934,7 +2934,7 @@@ fn mk_global(ccx: &CrateContext
               internal: bool)
            -> ValueRef {
      unsafe {
 -        let llglobal = do name.as_c_str |buf| {
 +        let llglobal = do name.to_c_str().with_ref |buf| {
              llvm::LLVMAddGlobal(ccx.llmod, val_ty(llval).to_ref(), buf)
          };
          llvm::LLVMSetInitializer(llglobal, llval);