auto merge of #15464 : dotdash/rust/bool_stores, r=pcwalton
LLVM doesn't handle i1 value in allocas/memory very well and skips a number of optimizations if it hits it. So we have to do the same thing that Clang does, using i1 for SSA values, but storing i8 in memory. Fixes #15203.
This commit is contained in:
commit
d9db7f6137
@ -618,7 +618,7 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
|
||||
RawNullablePointer { .. } |
|
||||
StructWrappedNullablePointer { .. } => {
|
||||
assert!(discr == 0 || discr == 1);
|
||||
_match::single_result(Result::new(bcx, C_i1(bcx.ccx(), discr != 0)))
|
||||
_match::single_result(Result::new(bcx, C_bool(bcx.ccx(), discr != 0)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -641,7 +641,7 @@ pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
|
||||
}
|
||||
Univariant(ref st, true) => {
|
||||
assert_eq!(discr, 0);
|
||||
Store(bcx, C_bool(bcx.ccx(), true),
|
||||
Store(bcx, C_u8(bcx.ccx(), 1),
|
||||
GEPi(bcx, val, [0, st.fields.len() - 1]))
|
||||
}
|
||||
Univariant(..) => {
|
||||
|
@ -538,8 +538,8 @@ pub fn compare_scalar_values<'a>(
|
||||
// We don't need to do actual comparisons for nil.
|
||||
// () == () holds but () < () does not.
|
||||
match op {
|
||||
ast::BiEq | ast::BiLe | ast::BiGe => return C_i1(cx.ccx(), true),
|
||||
ast::BiNe | ast::BiLt | ast::BiGt => return C_i1(cx.ccx(), false),
|
||||
ast::BiEq | ast::BiLe | ast::BiGe => return C_bool(cx.ccx(), true),
|
||||
ast::BiNe | ast::BiLt | ast::BiGt => return C_bool(cx.ccx(), false),
|
||||
// refinements would be nice
|
||||
_ => die(cx)
|
||||
}
|
||||
@ -958,10 +958,42 @@ pub fn need_invoke(bcx: &Block) -> bool {
|
||||
|
||||
pub fn load_if_immediate(cx: &Block, v: ValueRef, t: ty::t) -> ValueRef {
|
||||
let _icx = push_ctxt("load_if_immediate");
|
||||
if type_is_immediate(cx.ccx(), t) { return Load(cx, v); }
|
||||
if type_is_immediate(cx.ccx(), t) { return load_ty(cx, v, t); }
|
||||
return v;
|
||||
}
|
||||
|
||||
pub fn load_ty(cx: &Block, ptr: ValueRef, t: ty::t) -> ValueRef {
|
||||
/*!
|
||||
* Helper for loading values from memory. Does the necessary conversion if
|
||||
* the in-memory type differs from the type used for SSA values. Also
|
||||
* handles various special cases where the type gives us better information
|
||||
* about what we are loading.
|
||||
*/
|
||||
if type_is_zero_size(cx.ccx(), t) {
|
||||
C_undef(type_of::type_of(cx.ccx(), t))
|
||||
} else if ty::type_is_bool(t) {
|
||||
Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, lib::llvm::False), Type::i1(cx.ccx()))
|
||||
} else if ty::type_is_char(t) {
|
||||
// a char is a unicode codepoint, and so takes values from 0
|
||||
// to 0x10FFFF inclusive only.
|
||||
LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, lib::llvm::False)
|
||||
} else {
|
||||
Load(cx, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_ty(cx: &Block, v: ValueRef, dst: ValueRef, t: ty::t) {
|
||||
/*!
|
||||
* Helper for storing values in memory. Does the necessary conversion if
|
||||
* the in-memory type differs from the type used for SSA values.
|
||||
*/
|
||||
if ty::type_is_bool(t) {
|
||||
Store(cx, ZExt(cx, v, Type::i8(cx.ccx())), dst);
|
||||
} else {
|
||||
Store(cx, v, dst);
|
||||
};
|
||||
}
|
||||
|
||||
pub fn ignore_lhs(_bcx: &Block, local: &ast::Local) -> bool {
|
||||
match local.pat.node {
|
||||
ast::PatWild => true, _ => false
|
||||
@ -1013,7 +1045,7 @@ pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef,
|
||||
let dst_ptr = PointerCast(cx, dst, Type::i8p(ccx));
|
||||
let size = IntCast(cx, n_bytes, ccx.int_type);
|
||||
let align = C_i32(ccx, align as i32);
|
||||
let volatile = C_i1(ccx, false);
|
||||
let volatile = C_bool(ccx, false);
|
||||
Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile], []);
|
||||
}
|
||||
|
||||
@ -1058,7 +1090,7 @@ fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
|
||||
let llzeroval = C_u8(ccx, 0);
|
||||
let size = machine::llsize_of(ccx, ty);
|
||||
let align = C_i32(ccx, llalign_of_min(ccx, ty) as i32);
|
||||
let volatile = C_i1(ccx, false);
|
||||
let volatile = C_bool(ccx, false);
|
||||
b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], []);
|
||||
}
|
||||
|
||||
@ -1282,9 +1314,14 @@ fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
|
||||
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
|
||||
// and builds the return block.
|
||||
pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
|
||||
last_bcx: &'a Block<'a>) {
|
||||
last_bcx: &'a Block<'a>,
|
||||
retty: ty::t) {
|
||||
let _icx = push_ctxt("finish_fn");
|
||||
|
||||
// This shouldn't need to recompute the return type,
|
||||
// as new_fn_ctxt did it already.
|
||||
let substd_retty = retty.substp(fcx.ccx.tcx(), fcx.param_substs);
|
||||
|
||||
let ret_cx = match fcx.llreturn.get() {
|
||||
Some(llreturn) => {
|
||||
if !last_bcx.terminated.get() {
|
||||
@ -1294,13 +1331,13 @@ pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
|
||||
}
|
||||
None => last_bcx
|
||||
};
|
||||
build_return_block(fcx, ret_cx);
|
||||
build_return_block(fcx, ret_cx, substd_retty);
|
||||
debuginfo::clear_source_location(fcx);
|
||||
fcx.cleanup();
|
||||
}
|
||||
|
||||
// Builds the return block for a function.
|
||||
pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block) {
|
||||
pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
|
||||
// Return the value if this function immediate; otherwise, return void.
|
||||
if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
|
||||
return RetVoid(ret_cx);
|
||||
@ -1318,13 +1355,16 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block) {
|
||||
retptr.erase_from_parent();
|
||||
}
|
||||
|
||||
retval
|
||||
if ty::type_is_bool(retty) {
|
||||
Trunc(ret_cx, retval, Type::i1(fcx.ccx))
|
||||
} else {
|
||||
retval
|
||||
}
|
||||
}
|
||||
// Otherwise, load the return value from the ret slot
|
||||
None => Load(ret_cx, fcx.llretptr.get().unwrap())
|
||||
None => load_ty(ret_cx, fcx.llretptr.get().unwrap(), retty)
|
||||
};
|
||||
|
||||
|
||||
Ret(ret_cx, retval);
|
||||
}
|
||||
|
||||
@ -1422,7 +1462,7 @@ pub fn trans_closure(ccx: &CrateContext,
|
||||
}
|
||||
|
||||
// Insert the mandatory first few basic blocks before lltop.
|
||||
finish_fn(&fcx, bcx);
|
||||
finish_fn(&fcx, bcx, output_type);
|
||||
}
|
||||
|
||||
// trans_fn: creates an LLVM function corresponding to a source language
|
||||
@ -1512,7 +1552,7 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
|
||||
}
|
||||
}
|
||||
|
||||
finish_fn(&fcx, bcx);
|
||||
finish_fn(&fcx, bcx, result_ty);
|
||||
}
|
||||
|
||||
fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef,
|
||||
|
@ -85,7 +85,7 @@ fn ty_size(ty: Type) -> uint {
|
||||
|
||||
fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
|
||||
if is_reg_ty(ty) {
|
||||
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
|
||||
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
|
||||
return ArgType::direct(ty, None, None, attr);
|
||||
}
|
||||
let size = ty_size(ty);
|
||||
@ -104,7 +104,7 @@ fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
|
||||
|
||||
fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
|
||||
if is_reg_ty(ty) {
|
||||
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
|
||||
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
|
||||
return ArgType::direct(ty, None, None, attr);
|
||||
}
|
||||
let align = ty_align(ty);
|
||||
|
@ -85,7 +85,7 @@ fn ty_size(ty: Type) -> uint {
|
||||
|
||||
fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
|
||||
if is_reg_ty(ty) {
|
||||
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
|
||||
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
|
||||
ArgType::direct(ty, None, None, attr)
|
||||
} else {
|
||||
ArgType::indirect(ty, Some(StructRetAttribute))
|
||||
@ -102,7 +102,7 @@ fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut uint) -> ArgType {
|
||||
*offset += align_up_to(size, align * 8) / 8;
|
||||
|
||||
if is_reg_ty(ty) {
|
||||
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
|
||||
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
|
||||
ArgType::direct(ty, None, None, attr)
|
||||
} else {
|
||||
ArgType::direct(
|
||||
|
@ -59,7 +59,7 @@ pub fn compute_abi_info(ccx: &CrateContext,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let attr = if rty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
|
||||
let attr = if rty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
|
||||
ret_ty = ArgType::direct(rty, None, None, attr);
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ pub fn compute_abi_info(ccx: &CrateContext,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let attr = if t == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
|
||||
let attr = if t == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
|
||||
ArgType::direct(t, None, None, attr)
|
||||
}
|
||||
};
|
||||
|
@ -350,7 +350,7 @@ pub fn compute_abi_info(ccx: &CrateContext,
|
||||
None)
|
||||
}
|
||||
} else {
|
||||
let attr = if ty == Type::bool(ccx) { Some(ZExtAttribute) } else { None };
|
||||
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
|
||||
ArgType::direct(ty, None, None, attr)
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +345,7 @@ pub fn trans_unboxing_shim(bcx: &Block,
|
||||
}).bcx;
|
||||
|
||||
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
|
||||
finish_fn(&fcx, bcx);
|
||||
finish_fn(&fcx, bcx, return_type);
|
||||
|
||||
llfn
|
||||
}
|
||||
@ -757,7 +757,7 @@ pub fn trans_call_inner<'a>(
|
||||
if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
|
||||
!type_is_zero_size(bcx.ccx(), ret_ty)
|
||||
{
|
||||
Store(bcx, llret, llretslot);
|
||||
store_ty(bcx, llret, llretslot, ret_ty)
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
|
@ -522,10 +522,6 @@ pub fn C_nil(ccx: &CrateContext) -> ValueRef {
|
||||
}
|
||||
|
||||
pub fn C_bool(ccx: &CrateContext, val: bool) -> ValueRef {
|
||||
C_integral(Type::bool(ccx), val as u64, false)
|
||||
}
|
||||
|
||||
pub fn C_i1(ccx: &CrateContext, val: bool) -> ValueRef {
|
||||
C_integral(Type::i1(ccx), val as u64, false)
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,8 @@
|
||||
* Datums are and how they are intended to be used.
|
||||
*/
|
||||
|
||||
use lib;
|
||||
use lib::llvm::ValueRef;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::cleanup;
|
||||
use middle::trans::cleanup::CleanupMethods;
|
||||
@ -344,7 +342,7 @@ impl Datum<Rvalue> {
|
||||
match self.kind.mode {
|
||||
ByValue => DatumBlock::new(bcx, self),
|
||||
ByRef => {
|
||||
let llval = load(bcx, self.val, self.ty);
|
||||
let llval = load_ty(bcx, self.val, self.ty);
|
||||
DatumBlock::new(bcx, Datum::new(llval, self.ty, Rvalue::new(ByValue)))
|
||||
}
|
||||
}
|
||||
@ -471,7 +469,7 @@ impl Datum<Expr> {
|
||||
DatumBlock::new(bcx, scratch)
|
||||
}
|
||||
ByValue => {
|
||||
let v = load(bcx, l.val, l.ty);
|
||||
let v = load_ty(bcx, l.val, l.ty);
|
||||
bcx = l.kind.post_store(bcx, l.val, l.ty);
|
||||
DatumBlock::new(bcx, Datum::new(v, l.ty, Rvalue::new(ByValue)))
|
||||
}
|
||||
@ -516,24 +514,6 @@ impl Datum<Lvalue> {
|
||||
}
|
||||
}
|
||||
|
||||
fn load<'a>(bcx: &'a Block<'a>, llptr: ValueRef, ty: ty::t) -> ValueRef {
|
||||
/*!
|
||||
* Private helper for loading from a by-ref datum. Handles various
|
||||
* special cases where the type gives us better information about
|
||||
* what we are loading.
|
||||
*/
|
||||
|
||||
if type_is_zero_size(bcx.ccx(), ty) {
|
||||
C_undef(type_of::type_of(bcx.ccx(), ty))
|
||||
} else if ty::type_is_char(ty) {
|
||||
// a char is a unicode codepoint, and so takes values from 0
|
||||
// to 0x10FFFF inclusive only.
|
||||
LoadRangeAssert(bcx, llptr, 0, 0x10FFFF + 1, lib::llvm::False)
|
||||
} else {
|
||||
Load(bcx, llptr)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic methods applicable to any sort of datum.
|
||||
*/
|
||||
@ -591,7 +571,7 @@ impl<K:KindOps> Datum<K> {
|
||||
if self.kind.is_by_ref() {
|
||||
memcpy_ty(bcx, dst, self.val, self.ty);
|
||||
} else {
|
||||
Store(bcx, self.val, dst);
|
||||
store_ty(bcx, self.val, dst, self.ty);
|
||||
}
|
||||
|
||||
return bcx;
|
||||
@ -642,7 +622,7 @@ impl<K:KindOps> Datum<K> {
|
||||
assert!(!ty::type_needs_drop(bcx.tcx(), self.ty));
|
||||
assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
|
||||
if self.kind.is_by_ref() {
|
||||
load(bcx, self.val, self.ty)
|
||||
load_ty(bcx, self.val, self.ty)
|
||||
} else {
|
||||
self.val
|
||||
}
|
||||
|
@ -505,7 +505,7 @@ fn trans_index<'a>(bcx: &'a Block<'a>,
|
||||
|
||||
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len);
|
||||
let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
|
||||
let expected = Call(bcx, expect, [bounds_check, C_i1(ccx, false)], []);
|
||||
let expected = Call(bcx, expect, [bounds_check, C_bool(ccx, false)], []);
|
||||
let bcx = with_cond(bcx, expected, |bcx| {
|
||||
controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
|
||||
});
|
||||
@ -1149,13 +1149,7 @@ fn trans_unary<'a>(bcx: &'a Block<'a>,
|
||||
match op {
|
||||
ast::UnNot => {
|
||||
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
|
||||
let llresult = if ty::type_is_bool(un_ty) {
|
||||
let val = datum.to_llscalarish(bcx);
|
||||
Xor(bcx, val, C_bool(ccx, true))
|
||||
} else {
|
||||
// Note: `Not` is bitwise, not suitable for logical not.
|
||||
Not(bcx, datum.to_llscalarish(bcx))
|
||||
};
|
||||
let llresult = Not(bcx, datum.to_llscalarish(bcx));
|
||||
immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
|
||||
}
|
||||
ast::UnNeg => {
|
||||
@ -1380,7 +1374,7 @@ fn trans_lazy_binop<'a>(
|
||||
}
|
||||
|
||||
Br(past_rhs, join.llbb);
|
||||
let phi = Phi(join, Type::bool(bcx.ccx()), [lhs, rhs],
|
||||
let phi = Phi(join, Type::i1(bcx.ccx()), [lhs, rhs],
|
||||
[past_lhs.llbb, past_rhs.llbb]);
|
||||
|
||||
return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
|
||||
@ -1597,8 +1591,8 @@ fn trans_imm_cast<'a>(bcx: &'a Block<'a>,
|
||||
let k_in = cast_type_kind(t_in);
|
||||
let k_out = cast_type_kind(t_out);
|
||||
let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
|
||||
let ll_t_in = type_of::type_of(ccx, t_in);
|
||||
let ll_t_out = type_of::type_of(ccx, t_out);
|
||||
let ll_t_in = type_of::arg_type_of(ccx, t_in);
|
||||
let ll_t_out = type_of::arg_type_of(ccx, t_out);
|
||||
|
||||
// Convert the value to be cast into a ValueRef, either by-ref or
|
||||
// by-value as appropriate given its type:
|
||||
@ -1689,7 +1683,7 @@ fn trans_assign_op<'a>(
|
||||
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
|
||||
assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
|
||||
let dst_ty = dst_datum.ty;
|
||||
let dst = Load(bcx, dst_datum.val);
|
||||
let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
|
||||
|
||||
// Evaluate RHS
|
||||
let rhs_datum = unpack_datum!(bcx, trans(bcx, &*src));
|
||||
|
@ -325,7 +325,7 @@ pub fn trans_native_call<'a>(
|
||||
base::alloca(bcx,
|
||||
type_of::type_of(ccx, *passed_arg_tys.get(i)),
|
||||
"__arg");
|
||||
Store(bcx, llarg_rust, scratch);
|
||||
base::store_ty(bcx, llarg_rust, scratch, *passed_arg_tys.get(i));
|
||||
llarg_rust = scratch;
|
||||
}
|
||||
|
||||
@ -346,7 +346,12 @@ pub fn trans_native_call<'a>(
|
||||
let llarg_foreign = if foreign_indirect {
|
||||
llarg_rust
|
||||
} else {
|
||||
Load(bcx, llarg_rust)
|
||||
if ty::type_is_bool(*passed_arg_tys.get(i)) {
|
||||
let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, lib::llvm::False);
|
||||
Trunc(bcx, val, Type::i1(bcx.ccx()))
|
||||
} else {
|
||||
Load(bcx, llarg_rust)
|
||||
}
|
||||
};
|
||||
|
||||
debug!("argument {}, llarg_foreign={}",
|
||||
@ -431,7 +436,7 @@ pub fn trans_native_call<'a>(
|
||||
debug!("llforeign_ret_ty={}", ccx.tn.type_to_str(llforeign_ret_ty));
|
||||
|
||||
if llrust_ret_ty == llforeign_ret_ty {
|
||||
Store(bcx, llforeign_retval, llretptr);
|
||||
base::store_ty(bcx, llforeign_retval, llretptr, fn_sig.output)
|
||||
} else {
|
||||
// The actual return type is a struct, but the ABI
|
||||
// adaptation code has cast it into some scalar type. The
|
||||
@ -715,9 +720,15 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
// pointer). It makes adapting types easier, since we can
|
||||
// always just bitcast pointers.
|
||||
if !foreign_indirect {
|
||||
let lltemp = builder.alloca(val_ty(llforeign_arg), "");
|
||||
builder.store(llforeign_arg, lltemp);
|
||||
llforeign_arg = lltemp;
|
||||
llforeign_arg = if ty::type_is_bool(rust_ty) {
|
||||
let lltemp = builder.alloca(Type::bool(ccx), "");
|
||||
builder.store(builder.zext(llforeign_arg, Type::bool(ccx)), lltemp);
|
||||
lltemp
|
||||
} else {
|
||||
let lltemp = builder.alloca(val_ty(llforeign_arg), "");
|
||||
builder.store(llforeign_arg, lltemp);
|
||||
lltemp
|
||||
}
|
||||
}
|
||||
|
||||
// If the types in the ABI and the Rust types don't match,
|
||||
@ -731,7 +742,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
let llrust_arg = if rust_indirect {
|
||||
llforeign_arg
|
||||
} else {
|
||||
builder.load(llforeign_arg)
|
||||
if ty::type_is_bool(rust_ty) {
|
||||
let tmp = builder.load_range_assert(llforeign_arg, 0, 2, lib::llvm::False);
|
||||
builder.trunc(tmp, Type::i1(ccx))
|
||||
} else {
|
||||
builder.load(llforeign_arg)
|
||||
}
|
||||
};
|
||||
|
||||
debug!("llrust_arg {}{}: {}", "#",
|
||||
@ -828,8 +844,8 @@ fn foreign_signature(ccx: &CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t])
|
||||
* values by pointer like we do.
|
||||
*/
|
||||
|
||||
let llarg_tys = arg_tys.iter().map(|&arg| type_of(ccx, arg)).collect();
|
||||
let llret_ty = type_of::type_of(ccx, fn_sig.output);
|
||||
let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect();
|
||||
let llret_ty = type_of::arg_type_of(ccx, fn_sig.output);
|
||||
LlvmSignature {
|
||||
llarg_tys: llarg_tys,
|
||||
llret_ty: llret_ty
|
||||
|
@ -234,7 +234,7 @@ fn trans_struct_drop_flag<'a>(bcx: &'a Block<'a>,
|
||||
-> &'a Block<'a> {
|
||||
let repr = adt::represent_type(bcx.ccx(), t);
|
||||
let drop_flag = adt::trans_drop_flag_ptr(bcx, &*repr, v0);
|
||||
with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag)), |cx| {
|
||||
with_cond(bcx, load_ty(bcx, drop_flag, ty::mk_bool()), |cx| {
|
||||
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
||||
})
|
||||
}
|
||||
@ -504,7 +504,7 @@ fn make_generic_glue(ccx: &CrateContext,
|
||||
|
||||
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, fcx.arg_pos(0) as c_uint) };
|
||||
let bcx = helper(bcx, llrawptr0, t);
|
||||
finish_fn(&fcx, bcx);
|
||||
finish_fn(&fcx, bcx, ty::mk_nil());
|
||||
|
||||
llfn
|
||||
}
|
||||
|
@ -96,13 +96,19 @@ pub fn trans_intrinsic(ccx: &CrateContext,
|
||||
let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
|
||||
let llfn = bcx.ccx().get_intrinsic(&name);
|
||||
|
||||
// convert `i1` to a `bool`, and write to the out parameter
|
||||
let val = Call(bcx, llfn, [a, b], []);
|
||||
let result = ExtractValue(bcx, val, 0);
|
||||
let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool(bcx.ccx()));
|
||||
let ret = C_undef(type_of::type_of(bcx.ccx(), t));
|
||||
let ret = InsertValue(bcx, ret, result, 0);
|
||||
let ret = InsertValue(bcx, ret, overflow, 1);
|
||||
|
||||
if type_is_immediate(bcx.ccx(), t) {
|
||||
Ret(bcx, val);
|
||||
Ret(bcx, ret);
|
||||
} else {
|
||||
let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
|
||||
Store(bcx, val, retptr);
|
||||
Store(bcx, ret, retptr);
|
||||
RetVoid(bcx);
|
||||
}
|
||||
}
|
||||
@ -150,7 +156,8 @@ pub fn trans_intrinsic(ccx: &CrateContext,
|
||||
let src_ptr = PointerCast(bcx, get_param(decl, first_real_arg + 1), Type::i8p(ccx));
|
||||
let count = get_param(decl, first_real_arg + 2);
|
||||
let llfn = ccx.get_intrinsic(&name);
|
||||
Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, C_i1(ccx, volatile)], []);
|
||||
Call(bcx, llfn,
|
||||
[dst_ptr, src_ptr, Mul(bcx, size, count), align, C_bool(ccx, volatile)], []);
|
||||
RetVoid(bcx);
|
||||
}
|
||||
|
||||
@ -171,13 +178,13 @@ pub fn trans_intrinsic(ccx: &CrateContext,
|
||||
let val = get_param(decl, first_real_arg + 1);
|
||||
let count = get_param(decl, first_real_arg + 2);
|
||||
let llfn = ccx.get_intrinsic(&name);
|
||||
Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, C_i1(ccx, volatile)], []);
|
||||
Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, C_bool(ccx, volatile)], []);
|
||||
RetVoid(bcx);
|
||||
}
|
||||
|
||||
fn count_zeros_intrinsic(bcx: &Block, name: &'static str) {
|
||||
let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
|
||||
let y = C_i1(bcx.ccx(), false);
|
||||
let y = C_bool(bcx.ccx(), false);
|
||||
let llfn = bcx.ccx().get_intrinsic(&name);
|
||||
let llcall = Call(bcx, llfn, [x, y], []);
|
||||
Ret(bcx, llcall);
|
||||
@ -365,7 +372,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
|
||||
let retty = *substs.substs.types.get(FnSpace, 0);
|
||||
if type_is_immediate(ccx, retty) && !return_type_is_void(ccx, retty) {
|
||||
unsafe {
|
||||
Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
|
||||
Ret(bcx, lib::llvm::llvm::LLVMGetUndef(arg_type_of(ccx, retty).to_ref()));
|
||||
}
|
||||
} else {
|
||||
RetVoid(bcx)
|
||||
|
@ -330,7 +330,7 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
Some(llreturn) => Br(bcx, llreturn),
|
||||
None => {}
|
||||
};
|
||||
finish_fn(&fcx, bcx);
|
||||
finish_fn(&fcx, bcx, ty::mk_u64());
|
||||
llfdecl
|
||||
};
|
||||
|
||||
|
@ -89,7 +89,7 @@ impl Type {
|
||||
}
|
||||
|
||||
pub fn bool(ccx: &CrateContext) -> Type {
|
||||
Type::i1(ccx)
|
||||
Type::i8(ccx)
|
||||
}
|
||||
|
||||
pub fn char(ccx: &CrateContext) -> Type {
|
||||
|
@ -31,7 +31,7 @@ pub fn return_uses_outptr(ccx: &CrateContext, ty: ty::t) -> bool {
|
||||
}
|
||||
|
||||
pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
|
||||
let llty = type_of(ccx, arg_ty);
|
||||
let llty = arg_type_of(ccx, arg_ty);
|
||||
if arg_is_indirect(ccx, arg_ty) {
|
||||
llty.ptr_to()
|
||||
} else {
|
||||
@ -46,7 +46,7 @@ pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
|
||||
// Arg 0: Output pointer.
|
||||
// (if the output type is non-immediate)
|
||||
let use_out_pointer = return_uses_outptr(cx, output);
|
||||
let lloutputtype = type_of(cx, output);
|
||||
let lloutputtype = arg_type_of(cx, output);
|
||||
if use_out_pointer {
|
||||
atys.push(lloutputtype.ptr_to());
|
||||
}
|
||||
@ -167,6 +167,14 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
llsizingty
|
||||
}
|
||||
|
||||
pub fn arg_type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
if ty::type_is_bool(t) {
|
||||
Type::i1(cx)
|
||||
} else {
|
||||
type_of(cx, t)
|
||||
}
|
||||
}
|
||||
|
||||
// NB: If you update this, be sure to update `sizing_type_of()` as well.
|
||||
pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
// Check the cache.
|
||||
|
Loading…
x
Reference in New Issue
Block a user