Skip to content

Improve handling of immediate values #27600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,7 @@ extern {
/* Selected entries from the downcasts. */
pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef;
pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef;
pub fn LLVMIsAZExtInst(Inst: ValueRef) -> ValueRef;

/// Writes a module to the specified path. Returns 0 on success.
pub fn LLVMWriteBitcodeToFile(M: ModuleRef, Path: *const c_char) -> c_int;
Expand Down
97 changes: 83 additions & 14 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ use trans::callee;
use trans::cleanup::{self, CleanupMethods, DropHint};
use trans::closure;
use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral};
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef, C_nil};
use trans::common::{CrateContext, DropFlagHintsMap, Field, FunctionContext};
use trans::common::{Result, NodeIdAndSpan, VariantInfo};
use trans::common::{node_id_type, return_type_is_void};
Expand Down Expand Up @@ -699,8 +699,22 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc)
-> (ValueRef, Block<'blk, 'tcx>) {
let _icx = push_ctxt("invoke_");

let ret_ty = match fn_ty.sty {
ty::TyBareFn(_, ref f) => {
let output = bcx.tcx().erase_late_bound_regions(&f.sig.output());
output
}
_ => panic!("expected bare rust fn or closure in trans_call_inner")
};

if bcx.unreachable.get() {
return (C_null(Type::i8(bcx.ccx())), bcx);
if let ty::FnConverging(ty) = ret_ty {
let llty = type_of::arg_type_of(bcx.ccx(), ty);
return (C_undef(llty), bcx);
} else {
return (C_nil(bcx.ccx()), bcx);
}
}

let attributes = attributes::from_fn_type(bcx.ccx(), fn_ty);
Expand All @@ -714,7 +728,7 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}

if need_invoke(bcx) {
let (mut llresult, bcx) = if need_invoke(bcx) {
debug!("invoking {} at {:?}", bcx.val_to_string(llfn), bcx.llbb);
for &llarg in llargs {
debug!("arg: {}", bcx.val_to_string(llarg));
Expand All @@ -729,20 +743,30 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
landing_pad,
Some(attributes),
debug_loc);
return (llresult, normal_bcx);
(llresult, normal_bcx)
} else {
debug!("calling {} at {:?}", bcx.val_to_string(llfn), bcx.llbb);
for &llarg in llargs {
debug!("arg: {}", bcx.val_to_string(llarg));
}

let llresult = Call(bcx,
llfn,
&llargs[..],
Some(attributes),
debug_loc);
return (llresult, bcx);
llfn,
&llargs[..],
Some(attributes),
debug_loc);
(llresult, bcx)
};

if let ty::FnConverging(ty) = ret_ty {
if return_type_is_void(bcx.ccx(), ty) {
llresult = C_nil(bcx.ccx());
}
} else {
llresult = C_nil(bcx.ccx());
}

(llresult, bcx)
}

pub fn need_invoke(bcx: Block) -> bool {
Expand Down Expand Up @@ -783,6 +807,13 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
let align = type_of::align_of(cx.ccx(), t);

if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
if let Some(val) = Value(ptr).get_stored_value_opt(cx) {
debug!("Eliding load from {}", cx.ccx().tn().val_to_string(ptr));
debug!(" Using previous stored value: {}",
cx.ccx().tn().val_to_string(val.get()));
return val.get();
}

let load = Load(cx, ptr);
unsafe {
llvm::LLVMSetAlignment(load, align);
Expand All @@ -800,6 +831,13 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
}
}

if let Some(val) = Value(ptr).get_stored_value_opt(cx) {
debug!("Eliding load from {}", cx.ccx().tn().val_to_string(ptr));
debug!(" Using previous stored value: {}",
cx.ccx().tn().val_to_string(val.get()));
return to_arg_ty(cx, val.get(), t);
}

let val = if t.is_bool() {
LoadRangeAssert(cx, ptr, 0, 2, llvm::False)
} else if t.is_char() {
Expand Down Expand Up @@ -831,7 +869,18 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_ADDR), expr::get_dataptr(cx, dst));
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_EXTRA), expr::get_len(cx, dst));
} else {
let store = Store(cx, from_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
let vty = val_ty(v);
let dstty = val_ty(dst).element_type();

// If the source and destination have the same type, then don't try any conversion,
// this can happen with the return values of functions, as they don't touch an alloca
let (v, dst) = if vty == dstty {
(v, dst)
} else {
(from_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t))
};

let store = Store(cx, v, dst);
unsafe {
llvm::LLVMSetAlignment(store, type_of::align_of(cx.ccx(), t));
}
Expand All @@ -848,7 +897,21 @@ pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {

pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
if ty.is_bool() {
Trunc(bcx, val, Type::i1(bcx.ccx()))
// Look for cases where we're truncating a zext from a bool already and grab the original
// value. This can happen with an elided load from a boolean location. While this can be
// easily optimized out, the indirection can interfere with some intrinsics.
let val = Value(val);
if let Some(zext) = val.as_zext_inst() {
// `val` == zext %foo
if let Some(val) = zext.get_operand(0) {
let valty = val_ty(val.get());
if valty == Type::i1(bcx.ccx()) {
// %foo : i1
return val.get();
}
}
}
Trunc(bcx, val.get(), Type::i1(bcx.ccx()))
} else {
val
}
Expand Down Expand Up @@ -1709,8 +1772,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
disr: ty::Disr,
args: callee::CallArgs,
dest: expr::Dest,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
debug_loc: DebugLoc) -> Result<'blk, 'tcx> {

let ccx = bcx.fcx.ccx;

Expand Down Expand Up @@ -1753,6 +1815,12 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
}
}

let llretval = if type_is_immediate(bcx.ccx(), result_ty) {
load_ty(bcx, llresult, result_ty)
} else {
C_undef(type_of::type_of(bcx.ccx(), result_ty))
};

// If the caller doesn't care about the result
// drop the temporary we made
let bcx = match dest {
Expand All @@ -1766,7 +1834,8 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
}
};

Result::new(bcx, llresult)

Result::new(bcx, llretval)
}

pub fn trans_tuple_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/basic_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use llvm::BasicBlockRef;
use trans::value::{Users, Value};
use std::iter::{Filter, Map};

#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq)]
pub struct BasicBlock(pub BasicBlockRef);

pub type Preds = Map<Filter<Users, fn(&Value) -> bool>, fn(Value) -> BasicBlock>;
Expand Down
23 changes: 20 additions & 3 deletions src/librustc_trans/trans/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use llvm::{Opcode, IntPredicate, RealPredicate, False};
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
use trans::base;
use trans::common::*;
use trans::llrepr::LlvmRepr;
use trans::machine::llalign_of_pref;
use trans::type_::Type;
use util::nodemap::FnvHashMap;
Expand Down Expand Up @@ -158,8 +159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
args: &[ValueRef],
then: BasicBlockRef,
catch: BasicBlockRef,
attributes: Option<AttrBuilder>)
-> ValueRef {
attributes: Option<AttrBuilder>) -> ValueRef {
self.count_insn("invoke");

debug!("Invoke {} with args ({})",
Expand All @@ -169,6 +169,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.collect::<Vec<String>>()
.join(", "));

let llfnty = val_ty(llfn);

for (i, (pty, &a)) in llfnty.func_params().into_iter().zip(args.iter()).enumerate() {
let aty = val_ty(a);
assert!(pty == aty, "Type mismatch for arg {}. {} is not of type {}",
i, self.ccx.tn().val_to_string(a), self.ccx.tn().type_to_string(pty));
}

unsafe {
let v = llvm::LLVMBuildInvoke(self.llbuilder,
llfn,
Expand Down Expand Up @@ -499,7 +507,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}

pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
debug!("Store {} -> {}",
debug!("Volatile Store {} -> {}",
self.ccx.tn().val_to_string(val),
self.ccx.tn().val_to_string(ptr));
assert!(!self.llbuilder.is_null());
Expand All @@ -524,6 +532,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}

pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
debug!("GEP from {}, indices: {}",
self.ccx.tn().val_to_string(ptr),
indices.llrepr(self.ccx));
self.count_insn("gep");
unsafe {
llvm::LLVMBuildGEP(self.llbuilder, ptr, indices.as_ptr(),
Expand All @@ -535,6 +546,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// in C_i32()
#[inline]
pub fn gepi(&self, base: ValueRef, ixs: &[usize]) -> ValueRef {
debug!("GEPi from {}, indices: {:?}",
self.ccx.tn().val_to_string(base),
ixs);
// Small vector optimization. This should catch 100% of the cases that
// we care about.
if ixs.len() < 16 {
Expand All @@ -559,6 +573,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}

pub fn struct_gep(&self, ptr: ValueRef, idx: usize) -> ValueRef {
debug!("Struct GEP from {}, index: {}",
self.ccx.tn().val_to_string(ptr),
idx);
self.count_insn("structgep");
unsafe {
llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname())
Expand Down
60 changes: 42 additions & 18 deletions src/librustc_trans/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub use self::CallArgs::*;
use arena::TypedArena;
use back::link;
use session;
use llvm::{self, ValueRef, get_params};
use llvm::{ValueRef, get_params};
use middle::def;
use middle::subst;
use middle::subst::{Subst, Substs};
Expand All @@ -45,7 +45,6 @@ use trans::foreign;
use trans::intrinsic;
use trans::meth;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
use middle::ty::MethodCall;
Expand Down Expand Up @@ -583,6 +582,23 @@ pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Some(dest)).bcx
}

pub fn trans_datum_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
call_expr: &ast::Expr,
f: &ast::Expr,
args: CallArgs<'a, 'tcx>) -> DatumBlock<'blk, 'tcx, Expr> {
let ty = common::expr_ty(bcx, call_expr);

let _icx = push_ctxt("trans_call");
let val = unpack_result!(
bcx, trans_call_inner(bcx,
call_expr.debug_loc(),
|bcx, _| trans(bcx, f),
args,
Some(expr::Ignore)));

immediate_rvalue_bcx(bcx, val, ty).to_expr_datumblock()
}

pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
call_expr: &ast::Expr,
rcvr: &ast::Expr,
Expand Down Expand Up @@ -705,6 +721,14 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,

let is_rust_fn = abi == synabi::Rust || abi == synabi::RustCall;

let llretty = {
let ret_ty = match ret_ty {
ty::FnConverging(ret_ty) => ret_ty,
ty::FnDiverging => ccx.tcx().mk_nil()
};
type_of::type_of(ccx, ret_ty)
};

// Generate a location to store the result. If the user does
// not care about the result, just make a stack slot.
let opt_llretslot = dest.and_then(|dest| match dest {
Expand All @@ -715,13 +739,12 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
ty::FnDiverging => ccx.tcx().mk_nil()
};
if !is_rust_fn ||
type_of::return_uses_outptr(ccx, ret_ty) ||
bcx.fcx.type_needs_drop(ret_ty) {
type_of::return_uses_outptr(ccx, ret_ty) ||
bcx.fcx.type_needs_drop(ret_ty) {
// Push the out-pointer if we use an out-pointer for this
// return type, otherwise push "undef".
if common::type_is_zero_size(ccx, ret_ty) {
let llty = type_of::type_of(ccx, ret_ty);
Some(common::C_undef(llty.ptr_to()))
Some(common::C_undef(llretty.ptr_to()))
} else {
Some(alloc_ty(bcx, ret_ty, "__llret"))
}
Expand All @@ -731,9 +754,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
}
});

let mut llresult = unsafe {
llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
};
let llresult;

// The code below invokes the function, using either the Rust
// conventions (if it is a rust fn) or the native conventions
Expand Down Expand Up @@ -814,13 +835,16 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
abi);
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();

bcx = foreign::trans_native_call(bcx,
callee.ty,
llfn,
opt_llretslot.unwrap(),
&llargs[..],
arg_tys,
debug_loc);
let (llret, b) = foreign::trans_native_call(bcx,
callee.ty,
llfn,
opt_llretslot.unwrap(),
&llargs[..],
arg_tys,
debug_loc);

bcx = b;
llresult = llret;
}

fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
Expand Down Expand Up @@ -1126,8 +1150,8 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));

if common::type_is_fat_ptr(bcx.tcx(), formal_arg_ty) {
llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
llargs.push(Load(bcx, expr::get_len(bcx, val)));
llargs.push(expr::extract_dataptr(bcx, val));
llargs.push(expr::extract_len(bcx, val));
} else {
llargs.push(val);
}
Expand Down
Loading