Skip to content

Avoid loads/stores of first class aggregates #20755

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

Merged
merged 3 commits into from
Jan 11, 2015
Merged
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
12 changes: 11 additions & 1 deletion src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,11 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
C_undef(type_of::type_of(cx.ccx(), t))
} else if ty::type_is_bool(t) {
Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx()))
} else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
// and we have to convert it
Load(cx, BitCast(cx, ptr, type_of::arg_type_of(cx.ccx(), t).ptr_to()))
} else if ty::type_is_char(t) {
// a char is a Unicode codepoint, and so takes values from 0
// to 0x10FFFF inclusive only.
Expand All @@ -1065,9 +1070,14 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,

/// Helper for storing values in memory. Does the necessary conversion if the in-memory type
/// differs from the type used for SSA values.
pub fn store_ty(cx: Block, v: ValueRef, dst: ValueRef, t: Ty) {
pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
if ty::type_is_bool(t) {
Store(cx, ZExt(cx, v, Type::i8(cx.ccx())), dst);
} else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
// and we have to convert it
Store(cx, v, BitCast(cx, dst, type_of::arg_type_of(cx.ccx(), t).ptr_to()));
} else {
Store(cx, v, dst);
};
Expand Down
7 changes: 2 additions & 5 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,7 @@ fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
match ty.sty {
ty::ty_struct(def_id, substs) => {
let fields = ty::struct_fields(ccx.tcx(), def_id, substs);
fields.len() == 1 &&
fields[0].name ==
token::special_idents::unnamed_field.name &&
type_is_immediate(ccx, fields[0].mt.ty)
fields.len() == 1 && type_is_immediate(ccx, fields[0].mt.ty)
}
_ => false
}
Expand All @@ -247,7 +244,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
return false;
}
match ty.sty {
ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) |
ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) | ty::ty_vec(_, Some(_)) |
ty::ty_unboxed_closure(..) => {
let llty = sizing_type_of(ccx, ty);
llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type())
Expand Down
11 changes: 9 additions & 2 deletions src/librustc_trans/trans/foreign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,13 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
if ty::type_is_bool(rust_ty) {
let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False);
builder.trunc(tmp, Type::i1(ccx))
} else if type_of::type_of(ccx, rust_ty).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate
// LLVM type for this leads to bad optimizations, so its arg type is an
// appropriately sized integer and we have to convert it
let tmp = builder.bitcast(llforeign_arg,
type_of::arg_type_of(ccx, rust_ty).ptr_to());
builder.load(tmp)
} else {
builder.load(llforeign_arg)
}
Expand Down Expand Up @@ -834,10 +841,10 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_sig: &ty::FnSig<'tcx>,
arg_tys: &[Ty<'tcx>])
-> LlvmSignature {
let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect();
let llarg_tys = arg_tys.iter().map(|&arg| foreign_arg_type_of(ccx, arg)).collect();
let (llret_ty, ret_def) = match fn_sig.output {
ty::FnConverging(ret_ty) =>
(type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
(type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
ty::FnDiverging =>
(Type::nil(ccx), false)
};
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("drop_ty_immediate");
let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
Store(bcx, v, vp);
store_ty(bcx, v, vp, t);
drop_ty(bcx, vp, t, source_location)
}

Expand Down
13 changes: 9 additions & 4 deletions src/librustc_trans/trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
&ccx.link_meta().crate_hash);
// NB: This needs to be kept in lockstep with the TypeId struct in
// the intrinsic module
C_named_struct(llret_ty, &[C_u64(ccx, hash)])
C_u64(ccx, hash)
}
(_, "init") => {
let tp_ty = *substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
let lltp_ty = type_of::arg_type_of(ccx, tp_ty);
if return_type_is_void(ccx, tp_ty) {
C_nil(ccx)
} else {
Expand Down Expand Up @@ -686,6 +686,11 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, name: &'static st
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);

ret
if type_is_immediate(bcx.ccx(), t) {
let tmp = alloc_ty(bcx, t, "tmp");
Store(bcx, ret, tmp);
load_ty(bcx, tmp, t)
} else {
ret
}
}
12 changes: 12 additions & 0 deletions src/librustc_trans/trans/type_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ impl Type {
ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
}

// Creates an integer type with the given number of bits, e.g. i24
pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
}

pub fn f32(ccx: &CrateContext) -> Type {
ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
}
Expand Down Expand Up @@ -260,6 +265,13 @@ impl Type {
ty!(llvm::LLVMPointerType(self.to_ref(), 0))
}

pub fn is_aggregate(&self) -> bool {
match self.kind() {
TypeKind::Struct | TypeKind::Array => true,
_ => false
}
}

pub fn is_packed(&self) -> bool {
unsafe {
llvm::LLVMIsPackedStruct(self.to_ref()) == True
Expand Down
15 changes: 15 additions & 0 deletions src/librustc_trans/trans/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,24 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
llsizingty
}

pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
if ty::type_is_bool(t) {
Type::i1(cx)
} else {
type_of(cx, t)
}
}

pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
if ty::type_is_bool(t) {
Type::i1(cx)
} else if type_is_immediate(cx, t) && type_of(cx, t).is_aggregate() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment describing what is happening here?

// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
match machine::llsize_of_alloc(cx, sizing_type_of(cx, t)) {
0 => type_of(cx, t),
n => Type::ix(cx, n * 8),
}
} else {
type_of(cx, t)
}
Expand Down