提交 7a3eaf8f 编写于 作者: B bors

auto merge of #7941 : dotdash/rust/codegen, r=huonw

These changes remove unnecessary basic blocks and the associated branches from
the LLVM IR that we emit. Together, they reduce the time for unoptimized builds
in stage2 by about 10% on my box.
......@@ -984,6 +984,8 @@ pub unsafe fn LLVMGetInstructionParent(Inst: ValueRef)
pub unsafe fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef;
#[fast_ffi]
pub unsafe fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef;
#[fast_ffi]
pub unsafe fn LLVMInstructionEraseFromParent(Inst: ValueRef);
/* Operations on call sites */
#[fast_ffi]
......
......@@ -41,6 +41,7 @@
use middle::trans::adt;
use middle::trans::base;
use middle::trans::build::*;
use middle::trans::builder::{Builder, noname};
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::consts;
......@@ -1499,11 +1500,12 @@ pub fn memcpy_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) {
}
pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) {
if cx.unreachable { return; }
let _icx = push_ctxt("zero_mem");
let bcx = cx;
let ccx = cx.ccx();
let llty = type_of::type_of(ccx, t);
memzero(bcx, llptr, llty);
memzero(&B(bcx), llptr, llty);
}
// Always use this function instead of storing a zero constant to the memory
......@@ -1511,9 +1513,9 @@ pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) {
// allocation for large data structures, and the generated code will be
// awful. (A telltale sign of this is large quantities of
// `mov [byte ptr foo],0` in the generated code.)
pub fn memzero(cx: block, llptr: ValueRef, ty: Type) {
pub fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
let _icx = push_ctxt("memzero");
let ccx = cx.ccx();
let ccx = b.ccx;
let intrinsic_key = match ccx.sess.targ_cfg.arch {
X86 | Arm | Mips => "llvm.memset.p0i8.i32",
......@@ -1521,12 +1523,12 @@ pub fn memzero(cx: block, llptr: ValueRef, ty: Type) {
};
let llintrinsicfn = ccx.intrinsics.get_copy(&intrinsic_key);
let llptr = PointerCast(cx, llptr, Type::i8().ptr_to());
let llptr = b.pointercast(llptr, Type::i8().ptr_to());
let llzeroval = C_u8(0);
let size = IntCast(cx, machine::llsize_of(ccx, ty), ccx.int_type);
let size = machine::llsize_of(ccx, ty);
let align = C_i32(llalign_of_min(ccx, ty) as i32);
let volatile = C_i1(false);
Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
}
pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef {
......@@ -1549,9 +1551,12 @@ pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> Value
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
}
}
let initcx = base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas());
let p = Alloca(initcx, ty, name);
if zero { memzero(initcx, p, ty); }
let p = Alloca(cx, ty, name);
if zero {
let b = cx.fcx.ccx.builder();
b.position_before(cx.fcx.alloca_insert_pt.get());
memzero(&b, p, ty);
}
p
}
......@@ -1562,7 +1567,7 @@ pub fn arrayalloca(cx: block, ty: Type, v: ValueRef) -> ValueRef {
return llvm::LLVMGetUndef(ty.to_ref());
}
}
return ArrayAlloca(base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas()), ty, v);
return ArrayAlloca(cx, ty, v);
}
pub struct BasicBlocks {
......@@ -1593,8 +1598,8 @@ pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
alloca(raw_block(fcx, false, fcx.get_llstaticallocas()), lloutputtype,
"__make_return_pointer")
let bcx = fcx.entry_bcx.get();
Alloca(bcx, lloutputtype, "__make_return_pointer")
}
}
}
......@@ -1612,6 +1617,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
output_type: ty::t,
skip_retptr: bool,
param_substs: Option<@param_substs>,
opt_node_info: Option<NodeInfo>,
sp: Option<span>)
-> fn_ctxt {
for param_substs.iter().advance |p| { p.validate(); }
......@@ -1635,8 +1641,8 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
llvm::LLVMGetUndef(Type::i8p().to_ref())
},
llretptr: None,
llstaticallocas: None,
llloadenv: None,
entry_bcx: None,
alloca_insert_pt: None,
llreturn: None,
llself: None,
personality: None,
......@@ -1654,6 +1660,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
fcx.llenv = unsafe {
llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
};
unsafe {
let entry_bcx = top_scope_block(fcx, opt_node_info);
Load(entry_bcx, C_null(Type::i8p()));
fcx.entry_bcx = Some(entry_bcx);
fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
}
if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
}
......@@ -1666,7 +1681,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
output_type: ty::t,
sp: Option<span>)
-> fn_ctxt {
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, sp)
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, None, sp)
}
// NB: must keep 4 fns in sync:
......@@ -1781,9 +1796,8 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
// and builds the return block.
pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
pub fn finish_fn(fcx: fn_ctxt, last_bcx: block) {
let _icx = push_ctxt("finish_fn");
tie_up_header_blocks(fcx, lltop);
let ret_cx = match fcx.llreturn {
Some(llreturn) => {
......@@ -1795,6 +1809,7 @@ pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
None => last_bcx
};
build_return_block(fcx, ret_cx);
fcx.cleanup();
}
// Builds the return block for a function.
......@@ -1807,29 +1822,6 @@ pub fn build_return_block(fcx: fn_ctxt, ret_cx: block) {
}
}
pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
let _icx = push_ctxt("tie_up_header_blocks");
let llnext = match fcx.llloadenv {
Some(ll) => {
unsafe {
llvm::LLVMMoveBasicBlockBefore(ll, lltop);
}
Br(raw_block(fcx, false, ll), lltop);
ll
}
None => lltop
};
match fcx.llstaticallocas {
Some(ll) => {
unsafe {
llvm::LLVMMoveBasicBlockBefore(ll, llnext);
}
Br(raw_block(fcx, false, ll), llnext);
}
None => ()
}
}
pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
// trans_closure: Builds an LLVM function out of a source function.
......@@ -1862,6 +1854,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
output_type,
false,
param_substs,
body.info(),
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
......@@ -1873,9 +1866,8 @@ pub fn trans_closure(ccx: @mut CrateContext,
// Create the first basic block in the function and keep a handle on it to
// pass to finish_fn later.
let bcx_top = top_scope_block(fcx, body.info());
let bcx_top = fcx.entry_bcx.get();
let mut bcx = bcx_top;
let lltop = bcx.llbb;
let block_ty = node_id_type(bcx, body.id);
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
......@@ -1911,7 +1903,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
}
// Insert the mandatory first few basic blocks before lltop.
finish_fn(fcx, lltop, bcx);
finish_fn(fcx, bcx);
}
// trans_fn: creates an LLVM function corresponding to a source language
......@@ -2081,12 +2073,12 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
result_ty,
false,
param_substs,
None,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let bcx = fcx.entry_bcx.get();
let arg_tys = ty::ty_fn_args(ctor_ty);
insert_synthetic_type_entries(bcx, fn_args, arg_tys);
......@@ -2104,7 +2096,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
let arg_ty = arg_tys[i];
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
}
finish_fn(fcx, lltop, bcx);
finish_fn(fcx, bcx);
}
pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
......@@ -2332,9 +2324,7 @@ fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
// be updated if this assertion starts to fail.
assert!(fcx.has_immediate_return_value);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let bcx = fcx.entry_bcx.get();
// Call main.
let llenvarg = unsafe {
let env_arg = fcx.env_arg_pos();
......@@ -2343,7 +2333,7 @@ fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
let args = ~[llenvarg];
Call(bcx, main_llfn, args);
finish_fn(fcx, lltop, bcx);
finish_fn(fcx, bcx);
return llfdecl;
}
......
此差异已折叠。
此差异已折叠。
......@@ -11,7 +11,7 @@
use back::abi;
use back::link::{mangle_internal_name_by_path_and_seq};
use lib::llvm::{llvm, ValueRef};
use lib::llvm::ValueRef;
use middle::moves;
use middle::trans::base::*;
use middle::trans::build::*;
......@@ -25,7 +25,6 @@
use middle::trans::type_::Type;
use std::str;
use std::vec;
use syntax::ast;
use syntax::ast_map::path_name;
......@@ -326,23 +325,12 @@ pub fn load_environment(fcx: fn_ctxt,
sigil: ast::Sigil) {
let _icx = push_ctxt("closure::load_environment");
let llloadenv = match fcx.llloadenv {
Some(ll) => ll,
None => {
let ll =
str::as_c_str("load_env",
|buf|
unsafe {
llvm::LLVMAppendBasicBlockInContext(fcx.ccx.llcx,
fcx.llfn,
buf)
});
fcx.llloadenv = Some(ll);
ll
}
};
// Don't bother to create the block if there's nothing to load
if cap_vars.len() == 0 && !load_ret_handle {
return;
}
let bcx = raw_block(fcx, false, llloadenv);
let bcx = fcx.entry_bcx.get();
// Load a pointer to the closure data, skipping over the box header:
let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv);
......
......@@ -174,17 +174,14 @@ pub struct fn_ctxt_ {
// always be Some.
llretptr: Option<ValueRef>,
entry_bcx: Option<block>,
// These elements: "hoisted basic blocks" containing
// administrative activities that have to happen in only one place in
// the function, due to LLVM's quirks.
// A block for all the function's static allocas, so that LLVM
// will coalesce them into a single alloca call.
llstaticallocas: Option<BasicBlockRef>,
// A block containing code that copies incoming arguments to space
// already allocated by code in one of the llallocas blocks.
// (LLVM requires that arguments be copied to local allocas before
// allowing most any operation to be performed on them.)
llloadenv: Option<BasicBlockRef>,
// A marker for the place where we want to insert the function's static
// allocas, so that LLVM will coalesce them into a single alloca call.
alloca_insert_pt: Option<ValueRef>,
llreturn: Option<BasicBlockRef>,
// The 'self' value currently in use in this function, if there
// is one.
......@@ -252,12 +249,12 @@ pub fn env_arg_pos(&self) -> uint {
}
}
pub fn get_llstaticallocas(&mut self) -> BasicBlockRef {
if self.llstaticallocas.is_none() {
self.llstaticallocas = Some(base::mk_staticallocas_basic_block(self.llfn));
pub fn cleanup(&mut self) {
unsafe {
llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt.get());
}
self.llstaticallocas.get()
// Remove the cycle between fcx and bcx, so memory can be freed
self.entry_bcx = None;
}
pub fn get_llreturn(&mut self) -> BasicBlockRef {
......
......@@ -19,6 +19,7 @@
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::type_use;
use middle::ty;
......@@ -227,6 +228,10 @@ pub fn new(sess: session::Session,
}
}
}
pub fn builder(@mut self) -> Builder {
Builder::new(self)
}
}
#[unsafe_destructor]
......
......@@ -188,7 +188,7 @@ pub fn create_local_var_metadata(bcx: block, local: @ast::local) -> DIVariable {
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_metadata, bcx.llbb);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
return var_metadata;
......@@ -247,7 +247,7 @@ pub fn create_argument_metadata(bcx: block, arg: &ast::arg, span: span) -> Optio
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx), llptr, var_metadata, bcx.llbb);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
return Some(var_metadata);
}
......
......@@ -149,8 +149,7 @@ fn build_shim_fn_(ccx: @mut CrateContext,
// Declare the body of the shim function:
let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let bcx = fcx.entry_bcx.get();
let llargbundle = get_param(llshimfn, 0u);
let llargvals = arg_builder(bcx, tys, llargbundle);
......@@ -162,13 +161,12 @@ fn build_shim_fn_(ccx: @mut CrateContext,
// Don't finish up the function in the usual way, because this doesn't
// follow the normal Rust calling conventions.
tie_up_header_blocks(fcx, lltop);
let ret_cx = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
None => bcx
};
RetVoid(ret_cx);
fcx.cleanup();
return llshimfn;
}
......@@ -192,19 +190,15 @@ fn build_wrap_fn_(ccx: @mut CrateContext,
ret_builder: wrap_ret_builder) {
let _icx = push_ctxt("foreign::build_wrap_fn_");
let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
let bcx = fcx.entry_bcx.get();
// Patch up the return type if it's not immediate and we're returning via
// the C ABI.
if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output);
fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.get_llstaticallocas()),
lloutputtype,
""));
fcx.llretptr = Some(alloca(bcx, lloutputtype, ""));
}
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
// Allocate the struct and write the arguments into it.
let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle");
arg_builder(bcx, tys, llwrapfn, llargbundle);
......@@ -215,10 +209,6 @@ fn build_wrap_fn_(ccx: @mut CrateContext,
Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]);
ret_builder(bcx, tys, llargbundle);
// Perform a custom version of `finish_fn`. First, tie up the header
// blocks.
tie_up_header_blocks(fcx, lltop);
// Then return according to the C ABI.
let return_context = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
......@@ -239,6 +229,7 @@ fn build_wrap_fn_(ccx: @mut CrateContext,
let llretptr = BitCast(return_context, fcx.llretptr.get(), return_type.ptr_to());
Ret(return_context, Load(return_context, llretptr));
}
fcx.cleanup();
}
// For each foreign function F, we generate a wrapper function W and a shim
......@@ -430,8 +421,7 @@ fn build_direct_fn(ccx: @mut CrateContext,
debug!("build_direct_fn(%s)", link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let bcx = fcx.entry_bcx.get();
let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
let ty = ty::lookup_item_type(ccx.tcx,
ast_util::local_def(item.id)).ty;
......@@ -443,7 +433,7 @@ fn build_direct_fn(ccx: @mut CrateContext,
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
finish_fn(fcx, lltop, bcx);
finish_fn(fcx, bcx);
}
// FIXME (#2535): this is very shaky and probably gets ABIs wrong all
......@@ -456,8 +446,7 @@ fn build_fast_ffi_fn(ccx: @mut CrateContext,
debug!("build_fast_ffi_fn(%s)", link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let bcx = fcx.entry_bcx.get();
let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
set_no_inline(fcx.llfn);
set_fixed_stack_segment(fcx.llfn);
......@@ -471,7 +460,7 @@ fn build_fast_ffi_fn(ccx: @mut CrateContext,
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
finish_fn(fcx, lltop, bcx);
finish_fn(fcx, bcx);
}
fn build_wrap_fn(ccx: @mut CrateContext,
......@@ -619,6 +608,7 @@ fn count_zeros_intrinsic(bcx: block, name: &'static str) {
output_type,
true,
Some(substs),
None,
Some(item.span));
set_always_inline(fcx.llfn);
......@@ -628,7 +618,7 @@ fn count_zeros_intrinsic(bcx: block, name: &'static str) {
set_fixed_stack_segment(fcx.llfn);
}
let mut bcx = top_scope_block(fcx, None);
let mut bcx = fcx.entry_bcx.get();
let first_real_arg = fcx.arg_pos(0u);
let nm = ccx.sess.str_of(item.ident);
......@@ -694,6 +684,7 @@ fn count_zeros_intrinsic(bcx: block, name: &'static str) {
}
}
fcx.cleanup();
return;
}
......@@ -942,6 +933,7 @@ fn count_zeros_intrinsic(bcx: block, name: &'static str) {
ccx.sess.span_bug(item.span, "unknown intrinsic");
}
}
fcx.cleanup();
}
/**
......
......@@ -546,18 +546,23 @@ pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef,
let _icx = push_ctxt("decr_refcnt_maybe_free");
let ccx = bcx.ccx();
do with_cond(bcx, IsNotNull(bcx, box_ptr)) |bcx| {
let rc_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_refcnt]);
let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1));
Store(bcx, rc, rc_ptr);
let zero_test = ICmp(bcx, lib::llvm::IntEQ, C_int(ccx, 0), rc);
do with_cond(bcx, zero_test) |bcx| {
match box_ptr_ptr {
Some(p) => free_ty(bcx, p, t),
None => free_ty_immediate(bcx, box_ptr, t)
}
}
}
let decr_bcx = sub_block(bcx, "decr");
let free_bcx = sub_block(decr_bcx, "free");
let next_bcx = sub_block(bcx, "next");
CondBr(bcx, IsNotNull(bcx, box_ptr), decr_bcx.llbb, next_bcx.llbb);
let rc_ptr = GEPi(decr_bcx, box_ptr, [0u, abi::box_field_refcnt]);
let rc = Sub(decr_bcx, Load(decr_bcx, rc_ptr), C_int(ccx, 1));
Store(decr_bcx, rc, rc_ptr);
CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
let free_bcx = match box_ptr_ptr {
Some(p) => free_ty(free_bcx, p, t),
None => free_ty_immediate(free_bcx, box_ptr, t)
};
Br(free_bcx, next_bcx.llbb);
next_bcx
}
......@@ -610,7 +615,7 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
// Zero out the struct
unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(v));
memzero(bcx, v, ty);
memzero(&B(bcx), v, ty);
}
}
......@@ -702,13 +707,12 @@ pub fn make_generic_glue_inner(ccx: @mut CrateContext,
// llfn is expected be declared to take a parameter of the appropriate
// type, so we don't need to explicitly cast the function parameter.
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let bcx = fcx.entry_bcx.get();
let rawptr0_arg = fcx.arg_pos(0u);
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) };
let bcx = helper(bcx, llrawptr0, t);
finish_fn(fcx, lltop, bcx);
finish_fn(fcx, bcx);
return llfn;
}
......
......@@ -22,6 +22,7 @@
pub mod consts;
pub mod type_of;
pub mod build;
pub mod builder;
pub mod base;
pub mod _match;
pub mod uniq;
......
......@@ -303,7 +303,7 @@ pub fn visit_ty(&mut self, t: ty::t) {
//
llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
};
let mut bcx = top_scope_block(fcx, None);
let mut bcx = fcx.entry_bcx.get();
let arg = BitCast(bcx, arg, llptrty);
let ret = adt::trans_get_discr(bcx, repr, arg);
Store(bcx, ret, fcx.llretptr.get());
......@@ -311,7 +311,7 @@ pub fn visit_ty(&mut self, t: ty::t) {
Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn),
None => bcx = cleanup_block(bcx, Some(bcx.llbb))
};
finish_fn(fcx, bcx.llbb, bcx);
finish_fn(fcx, bcx);
llfdecl
};
......
......@@ -409,6 +409,7 @@ LLVMInsertBasicBlock
LLVMInsertBasicBlockInContext
LLVMInsertIntoBuilder
LLVMInsertIntoBuilderWithName
LLVMInstructionEraseFromParent
LLVMInt16Type
LLVMInt16TypeInContext
LLVMInt1Type
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册