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.
This commit is contained in:
commit
7a3eaf8f27
src
librustc
lib
middle/trans
rustllvm
@ -984,6 +984,8 @@ pub mod llvm {
|
||||
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::_match;
|
||||
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 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
|
||||
// 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 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
|
||||
let args = ~[llenvarg];
|
||||
Call(bcx, main_llfn, args);
|
||||
|
||||
finish_fn(fcx, lltop, bcx);
|
||||
finish_fn(fcx, bcx);
|
||||
return llfdecl;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
947
src/librustc/middle/trans/builder.rs
Normal file
947
src/librustc/middle/trans/builder.rs
Normal file
@ -0,0 +1,947 @@
|
||||
// Copyright 2013 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 lib;
|
||||
use lib::llvm::llvm;
|
||||
use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
|
||||
use lib::llvm::{Opcode, IntPredicate, RealPredicate, False};
|
||||
use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
|
||||
use middle::trans::base;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::machine::llalign_of_min;
|
||||
use middle::trans::type_::Type;
|
||||
use std::cast;
|
||||
use std::hashmap::HashMap;
|
||||
use std::libc::{c_uint, c_ulonglong, c_char};
|
||||
use std::str;
|
||||
use std::vec;
|
||||
use syntax::codemap::span;
|
||||
|
||||
pub struct Builder {
|
||||
llbuilder: BuilderRef,
|
||||
ccx: @mut CrateContext,
|
||||
}
|
||||
|
||||
// This is a really awful way to get a zero-length c-string, but better (and a
|
||||
// lot more efficient) than doing str::as_c_str("", ...) every time.
|
||||
pub fn noname() -> *c_char {
|
||||
unsafe {
|
||||
static cnull: uint = 0u;
|
||||
cast::transmute(&cnull)
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new(ccx: @mut CrateContext) -> Builder {
|
||||
Builder {
|
||||
llbuilder: ccx.builder.B,
|
||||
ccx: ccx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count_insn(&self, category: &str) {
|
||||
if self.ccx.sess.trans_stats() {
|
||||
self.ccx.stats.n_llvm_insns += 1;
|
||||
}
|
||||
if self.ccx.sess.count_llvm_insns() {
|
||||
do base::with_insn_ctxt |v| {
|
||||
let h = &mut self.ccx.stats.llvm_insns;
|
||||
|
||||
// Build version of path with cycles removed.
|
||||
|
||||
// Pass 1: scan table mapping str -> rightmost pos.
|
||||
let mut mm = HashMap::new();
|
||||
let len = v.len();
|
||||
let mut i = 0u;
|
||||
while i < len {
|
||||
mm.insert(v[i], i);
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
// Pass 2: concat strings for each elt, skipping
|
||||
// forwards over any cycles by advancing to rightmost
|
||||
// occurrence of each element in path.
|
||||
let mut s = ~".";
|
||||
i = 0u;
|
||||
while i < len {
|
||||
i = *mm.get(&v[i]);
|
||||
s.push_char('/');
|
||||
s.push_str(v[i]);
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
s.push_char('/');
|
||||
s.push_str(category);
|
||||
|
||||
let n = match h.find(&s) {
|
||||
Some(&n) => n,
|
||||
_ => 0u
|
||||
};
|
||||
h.insert(s, n+1u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position_before(&self, insn: ValueRef) {
|
||||
unsafe {
|
||||
llvm::LLVMPositionBuilderBefore(self.llbuilder, insn);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position_at_end(&self, llbb: BasicBlockRef) {
|
||||
unsafe {
|
||||
llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ret_void(&self) {
|
||||
self.count_insn("retvoid");
|
||||
unsafe {
|
||||
llvm::LLVMBuildRetVoid(self.llbuilder);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ret(&self, v: ValueRef) {
|
||||
self.count_insn("ret");
|
||||
unsafe {
|
||||
llvm::LLVMBuildRet(self.llbuilder, v);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn aggregate_ret(&self, ret_vals: &[ValueRef]) {
|
||||
unsafe {
|
||||
llvm::LLVMBuildAggregateRet(self.llbuilder,
|
||||
vec::raw::to_ptr(ret_vals),
|
||||
ret_vals.len() as c_uint);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn br(&self, dest: BasicBlockRef) {
|
||||
self.count_insn("br");
|
||||
unsafe {
|
||||
llvm::LLVMBuildBr(self.llbuilder, dest);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cond_br(&self, cond: ValueRef, then_llbb: BasicBlockRef, else_llbb: BasicBlockRef) {
|
||||
self.count_insn("condbr");
|
||||
unsafe {
|
||||
llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn switch(&self, v: ValueRef, else_llbb: BasicBlockRef, num_cases: uint) -> ValueRef {
|
||||
unsafe {
|
||||
llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indirect_br(&self, addr: ValueRef, num_dests: uint) {
|
||||
self.count_insn("indirectbr");
|
||||
unsafe {
|
||||
llvm::LLVMBuildIndirectBr(self.llbuilder, addr, num_dests as c_uint);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invoke(&self,
|
||||
llfn: ValueRef,
|
||||
args: &[ValueRef],
|
||||
then: BasicBlockRef,
|
||||
catch: BasicBlockRef)
|
||||
-> ValueRef {
|
||||
self.count_insn("invoke");
|
||||
unsafe {
|
||||
llvm::LLVMBuildInvoke(self.llbuilder,
|
||||
llfn,
|
||||
vec::raw::to_ptr(args),
|
||||
args.len() as c_uint,
|
||||
then,
|
||||
catch,
|
||||
noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fast_invoke(&self,
|
||||
llfn: ValueRef,
|
||||
args: &[ValueRef],
|
||||
then: BasicBlockRef,
|
||||
catch: BasicBlockRef) {
|
||||
self.count_insn("fastinvoke");
|
||||
let v = self.invoke(llfn, args, then, catch);
|
||||
lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
|
||||
}
|
||||
|
||||
pub fn unreachable(&self) {
|
||||
self.count_insn("unreachable");
|
||||
unsafe {
|
||||
llvm::LLVMBuildUnreachable(self.llbuilder);
|
||||
}
|
||||
}
|
||||
|
||||
/* Arithmetic */
|
||||
pub fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("add");
|
||||
unsafe {
|
||||
llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nswadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("nswadd");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNSWAdd(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nuwadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("nuwadd");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNUWAdd(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("fadd");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("sub");
|
||||
unsafe {
|
||||
llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("nwsub");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nuwsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("nuwsub");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNUWSub(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("sub");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("mul");
|
||||
unsafe {
|
||||
llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nswmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("nswmul");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNSWMul(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nuwmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("nuwmul");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNUWMul(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("fmul");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn udiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("udiv");
|
||||
unsafe {
|
||||
llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("sdiv");
|
||||
unsafe {
|
||||
llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exactsdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("exactsdiv");
|
||||
unsafe {
|
||||
llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("fdiv");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn urem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("urem");
|
||||
unsafe {
|
||||
llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn srem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("srem");
|
||||
unsafe {
|
||||
llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("frem");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shl(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("shl");
|
||||
unsafe {
|
||||
llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lshr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("lshr");
|
||||
unsafe {
|
||||
llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ashr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("ashr");
|
||||
unsafe {
|
||||
llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("and");
|
||||
unsafe {
|
||||
llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("or");
|
||||
unsafe {
|
||||
llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("xor");
|
||||
unsafe {
|
||||
llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binop(&self, op: Opcode, lhs: ValueRef, rhs: ValueRef)
|
||||
-> ValueRef {
|
||||
self.count_insn("binop");
|
||||
unsafe {
|
||||
llvm::LLVMBuildBinOp(self.llbuilder, op, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn neg(&self, V: ValueRef) -> ValueRef {
|
||||
self.count_insn("neg");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNeg(self.llbuilder, V, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nswneg(&self, V: ValueRef) -> ValueRef {
|
||||
self.count_insn("nswneg");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNSWNeg(self.llbuilder, V, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nuwneg(&self, V: ValueRef) -> ValueRef {
|
||||
self.count_insn("nuwneg");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNUWNeg(self.llbuilder, V, noname())
|
||||
}
|
||||
}
|
||||
pub fn fneg(&self, V: ValueRef) -> ValueRef {
|
||||
self.count_insn("fneg");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFNeg(self.llbuilder, V, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not(&self, V: ValueRef) -> ValueRef {
|
||||
self.count_insn("not");
|
||||
unsafe {
|
||||
llvm::LLVMBuildNot(self.llbuilder, V, noname())
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory */
|
||||
pub fn malloc(&self, ty: Type) -> ValueRef {
|
||||
self.count_insn("malloc");
|
||||
unsafe {
|
||||
llvm::LLVMBuildMalloc(self.llbuilder, ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_malloc(&self, ty: Type, val: ValueRef) -> ValueRef {
|
||||
self.count_insn("arraymalloc");
|
||||
unsafe {
|
||||
llvm::LLVMBuildArrayMalloc(self.llbuilder, ty.to_ref(), val, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
|
||||
self.count_insn("alloca");
|
||||
unsafe {
|
||||
if name.is_empty() {
|
||||
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
|
||||
} else {
|
||||
str::as_c_str(
|
||||
name,
|
||||
|c| llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_alloca(&self, ty: Type, val: ValueRef) -> ValueRef {
|
||||
self.count_insn("arrayalloca");
|
||||
unsafe {
|
||||
llvm::LLVMBuildArrayAlloca(self.llbuilder, ty.to_ref(), val, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn free(&self, ptr: ValueRef) {
|
||||
self.count_insn("free");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFree(self.llbuilder, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(&self, ptr: ValueRef) -> ValueRef {
|
||||
self.count_insn("load");
|
||||
unsafe {
|
||||
llvm::LLVMBuildLoad(self.llbuilder, ptr, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering) -> ValueRef {
|
||||
self.count_insn("load.atomic");
|
||||
unsafe {
|
||||
let align = llalign_of_min(self.ccx, self.ccx.int_type);
|
||||
llvm::LLVMBuildAtomicLoad(self.llbuilder, ptr, noname(), order, align as c_uint)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn load_range_assert(&self, ptr: ValueRef, lo: c_ulonglong,
|
||||
hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
|
||||
let value = self.load(ptr);
|
||||
|
||||
unsafe {
|
||||
let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(ptr));
|
||||
let min = llvm::LLVMConstInt(t, lo, signed);
|
||||
let max = llvm::LLVMConstInt(t, hi, signed);
|
||||
|
||||
do [min, max].as_imm_buf |ptr, len| {
|
||||
llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
|
||||
llvm::LLVMMDNodeInContext(self.ccx.llcx,
|
||||
ptr, len as c_uint));
|
||||
}
|
||||
}
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
pub fn store(&self, val: ValueRef, ptr: ValueRef) {
|
||||
debug!("Store %s -> %s",
|
||||
self.ccx.tn.val_to_str(val),
|
||||
self.ccx.tn.val_to_str(ptr));
|
||||
self.count_insn("store");
|
||||
unsafe {
|
||||
llvm::LLVMBuildStore(self.llbuilder, val, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
|
||||
debug!("Store %s -> %s",
|
||||
self.ccx.tn.val_to_str(val),
|
||||
self.ccx.tn.val_to_str(ptr));
|
||||
self.count_insn("store.atomic");
|
||||
let align = llalign_of_min(self.ccx, self.ccx.int_type);
|
||||
unsafe {
|
||||
llvm::LLVMBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
|
||||
self.count_insn("gep");
|
||||
unsafe {
|
||||
llvm::LLVMBuildGEP(self.llbuilder, ptr, vec::raw::to_ptr(indices),
|
||||
indices.len() as c_uint, noname())
|
||||
}
|
||||
}
|
||||
|
||||
// Simple wrapper around GEP that takes an array of ints and wraps them
|
||||
// in C_i32()
|
||||
#[inline]
|
||||
pub fn gepi(&self, base: ValueRef, ixs: &[uint]) -> ValueRef {
|
||||
// Small vector optimization. This should catch 100% of the cases that
|
||||
// we care about.
|
||||
if ixs.len() < 16 {
|
||||
let mut small_vec = [ C_i32(0), ..16 ];
|
||||
for small_vec.mut_iter().zip(ixs.iter()).advance |(small_vec_e, &ix)| {
|
||||
*small_vec_e = C_i32(ix as i32);
|
||||
}
|
||||
self.inbounds_gep(base, small_vec.slice(0, ixs.len()))
|
||||
} else {
|
||||
let v = do ixs.iter().transform |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>();
|
||||
self.count_insn("gepi");
|
||||
self.inbounds_gep(base, v)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inbounds_gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
|
||||
self.count_insn("inboundsgep");
|
||||
unsafe {
|
||||
llvm::LLVMBuildInBoundsGEP(
|
||||
self.llbuilder, ptr, vec::raw::to_ptr(indices), indices.len() as c_uint, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_gep(&self, ptr: ValueRef, idx: uint) -> ValueRef {
|
||||
self.count_insn("structgep");
|
||||
unsafe {
|
||||
llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn global_string(&self, _Str: *c_char) -> ValueRef {
|
||||
self.count_insn("globalstring");
|
||||
unsafe {
|
||||
llvm::LLVMBuildGlobalString(self.llbuilder, _Str, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn global_string_ptr(&self, _Str: *c_char) -> ValueRef {
|
||||
self.count_insn("globalstringptr");
|
||||
unsafe {
|
||||
llvm::LLVMBuildGlobalStringPtr(self.llbuilder, _Str, noname())
|
||||
}
|
||||
}
|
||||
|
||||
/* Casts */
|
||||
pub fn trunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("trunc");
|
||||
unsafe {
|
||||
llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("zext");
|
||||
unsafe {
|
||||
llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("sext");
|
||||
unsafe {
|
||||
llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fptoui(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("fptoui");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fptosi(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("fptosi");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty.to_ref(),noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("uitofp");
|
||||
unsafe {
|
||||
llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("sitofp");
|
||||
unsafe {
|
||||
llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fptrunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("fptrunc");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fpext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("fpext");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptrtoint(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("ptrtoint");
|
||||
unsafe {
|
||||
llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inttoptr(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("inttoptr");
|
||||
unsafe {
|
||||
llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("bitcast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("zextorbitcast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildZExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("sextorbitcast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildSExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trunc_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("truncorbitcast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildTruncOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cast(&self, op: Opcode, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("cast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildCast(self.llbuilder, op, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pointercast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("pointercast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("intcast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fpcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
|
||||
self.count_insn("fpcast");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFPCast(self.llbuilder, val, dest_ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Comparisons */
|
||||
pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("icmp");
|
||||
unsafe {
|
||||
llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fcmp(&self, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("fcmp");
|
||||
unsafe {
|
||||
llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
/* Miscellaneous instructions */
|
||||
pub fn empty_phi(&self, ty: Type) -> ValueRef {
|
||||
self.count_insn("emptyphi");
|
||||
unsafe {
|
||||
llvm::LLVMBuildPhi(self.llbuilder, ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn phi(&self, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
|
||||
assert_eq!(vals.len(), bbs.len());
|
||||
let phi = self.empty_phi(ty);
|
||||
self.count_insn("addincoming");
|
||||
unsafe {
|
||||
llvm::LLVMAddIncoming(phi, vec::raw::to_ptr(vals),
|
||||
vec::raw::to_ptr(bbs),
|
||||
vals.len() as c_uint);
|
||||
phi
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_span_comment(&self, sp: span, text: &str) {
|
||||
if self.ccx.sess.asm_comments() {
|
||||
let s = fmt!("%s (%s)", text, self.ccx.sess.codemap.span_to_str(sp));
|
||||
debug!("%s", s);
|
||||
self.add_comment(s);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_comment(&self, text: &str) {
|
||||
if self.ccx.sess.asm_comments() {
|
||||
let sanitized = text.replace("$", "");
|
||||
let comment_text = fmt!("# %s", sanitized.replace("\n", "\n\t# "));
|
||||
self.count_insn("inlineasm");
|
||||
let asm = do comment_text.as_c_str |c| {
|
||||
unsafe {
|
||||
llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(),
|
||||
c, noname(), False, False)
|
||||
}
|
||||
};
|
||||
self.call(asm, []);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline_asm_call(&self, asm: *c_char, cons: *c_char,
|
||||
inputs: &[ValueRef], output: Type,
|
||||
volatile: bool, alignstack: bool,
|
||||
dia: AsmDialect) -> ValueRef {
|
||||
self.count_insn("inlineasm");
|
||||
|
||||
let volatile = if volatile { lib::llvm::True }
|
||||
else { lib::llvm::False };
|
||||
let alignstack = if alignstack { lib::llvm::True }
|
||||
else { lib::llvm::False };
|
||||
|
||||
let argtys = do inputs.map |v| {
|
||||
debug!("Asm Input Type: %?", self.ccx.tn.val_to_str(*v));
|
||||
val_ty(*v)
|
||||
};
|
||||
|
||||
debug!("Asm Output Type: %?", self.ccx.tn.type_to_str(output));
|
||||
let fty = Type::func(argtys, &output);
|
||||
unsafe {
|
||||
let v = llvm::LLVMInlineAsm(
|
||||
fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint);
|
||||
self.call(v, inputs)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
|
||||
self.count_insn("call");
|
||||
|
||||
debug!("Call(llfn=%s, args=%?)",
|
||||
self.ccx.tn.val_to_str(llfn),
|
||||
args.map(|arg| self.ccx.tn.val_to_str(*arg)));
|
||||
|
||||
do args.as_imm_buf |ptr, len| {
|
||||
unsafe {
|
||||
llvm::LLVMBuildCall(self.llbuilder, llfn, ptr, len as c_uint, noname())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fastcall(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
|
||||
self.count_insn("fastcall");
|
||||
unsafe {
|
||||
let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
|
||||
args.len() as c_uint, noname());
|
||||
lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
|
||||
conv: CallConv) -> ValueRef {
|
||||
self.count_insn("callwithconv");
|
||||
unsafe {
|
||||
let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
|
||||
args.len() as c_uint, noname());
|
||||
lib::llvm::SetInstructionCallConv(v, conv);
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef {
|
||||
self.count_insn("select");
|
||||
unsafe {
|
||||
llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn va_arg(&self, list: ValueRef, ty: Type) -> ValueRef {
|
||||
self.count_insn("vaarg");
|
||||
unsafe {
|
||||
llvm::LLVMBuildVAArg(self.llbuilder, list, ty.to_ref(), noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_element(&self, vec: ValueRef, idx: ValueRef) -> ValueRef {
|
||||
self.count_insn("extractelement");
|
||||
unsafe {
|
||||
llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_element(&self, vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef {
|
||||
self.count_insn("insertelement");
|
||||
unsafe {
|
||||
llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shuffle_vector(&self, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef {
|
||||
self.count_insn("shufflevector");
|
||||
unsafe {
|
||||
llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vector_splat(&self, num_elts: uint, elt: ValueRef) -> ValueRef {
|
||||
unsafe {
|
||||
let elt_ty = val_ty(elt);
|
||||
let Undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, num_elts as u64).to_ref());
|
||||
let vec = self.insert_element(Undef, elt, C_i32(0));
|
||||
self.shuffle_vector(vec, Undef, C_null(Type::vector(&Type::i32(), num_elts as u64)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_value(&self, agg_val: ValueRef, idx: uint) -> ValueRef {
|
||||
self.count_insn("extractvalue");
|
||||
unsafe {
|
||||
llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
|
||||
idx: uint) {
|
||||
self.count_insn("insertvalue");
|
||||
unsafe {
|
||||
llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
|
||||
noname());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_null(&self, val: ValueRef) -> ValueRef {
|
||||
self.count_insn("isnull");
|
||||
unsafe {
|
||||
llvm::LLVMBuildIsNull(self.llbuilder, val, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_not_null(&self, val: ValueRef) -> ValueRef {
|
||||
self.count_insn("isnotnull");
|
||||
unsafe {
|
||||
llvm::LLVMBuildIsNotNull(self.llbuilder, val, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptrdiff(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
||||
self.count_insn("ptrdiff");
|
||||
unsafe {
|
||||
llvm::LLVMBuildPtrDiff(self.llbuilder, lhs, rhs, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trap(&self) {
|
||||
unsafe {
|
||||
let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
|
||||
let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
|
||||
let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
|
||||
let T: ValueRef = str::as_c_str("llvm.trap", |buf| {
|
||||
llvm::LLVMGetNamedFunction(M, buf)
|
||||
});
|
||||
assert!((T as int != 0));
|
||||
let args: &[ValueRef] = [];
|
||||
self.count_insn("trap");
|
||||
llvm::LLVMBuildCall(
|
||||
self.llbuilder, T, vec::raw::to_ptr(args), args.len() as c_uint, noname());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef, num_clauses: uint) -> ValueRef {
|
||||
self.count_insn("landingpad");
|
||||
unsafe {
|
||||
llvm::LLVMBuildLandingPad(
|
||||
self.llbuilder, ty.to_ref(), pers_fn, num_clauses as c_uint, noname())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_cleanup(&self, landing_pad: ValueRef) {
|
||||
self.count_insn("setcleanup");
|
||||
unsafe {
|
||||
llvm::LLVMSetCleanup(landing_pad, lib::llvm::True);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resume(&self, exn: ValueRef) -> ValueRef {
|
||||
self.count_insn("resume");
|
||||
unsafe {
|
||||
llvm::LLVMBuildResume(self.llbuilder, exn)
|
||||
}
|
||||
}
|
||||
|
||||
// Atomic Operations
|
||||
pub fn atomic_cmpxchg(&self, dst: ValueRef,
|
||||
cmp: ValueRef, src: ValueRef,
|
||||
order: AtomicOrdering) -> ValueRef {
|
||||
unsafe {
|
||||
llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, order)
|
||||
}
|
||||
}
|
||||
pub fn atomic_rmw(&self, op: AtomicBinOp,
|
||||
dst: ValueRef, src: ValueRef,
|
||||
order: AtomicOrdering) -> ValueRef {
|
||||
unsafe {
|
||||
llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order)
|
||||
}
|
||||
}
|
||||
}
|
@ -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 util::ppaux::ty_to_str;
|
||||
|
||||
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 @@ impl fn_ctxt_ {
|
||||
}
|
||||
}
|
||||
|
||||
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::astencode;
|
||||
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 @@ impl CrateContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ pub fn trans_foreign_mod(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 @@ pub fn trans_foreign_mod(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 @@ pub fn trans_foreign_mod(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 @@ pub fn trans_foreign_mod(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 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
|
||||
output_type,
|
||||
true,
|
||||
Some(substs),
|
||||
None,
|
||||
Some(item.span));
|
||||
|
||||
set_always_inline(fcx.llfn);
|
||||
@ -628,7 +618,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
|
||||
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 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
|
||||
}
|
||||
}
|
||||
|
||||
fcx.cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -942,6 +933,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
|
||||
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 context;
|
||||
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 @@ impl Reflector {
|
||||
//
|
||||
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 @@ impl Reflector {
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user