Skip to content
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

Newtype structs as immediates #6638

Closed
wants to merge 5 commits into from
Closed
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
10 changes: 5 additions & 5 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
@@ -1034,13 +1034,13 @@ pub fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef {

pub fn spill_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef {
let _icx = cx.insn_ctxt("spill_if_immediate");
if ty::type_is_immediate(t) { return do_spill(cx, v, t); }
if ty::type_is_immediate(cx.tcx(), t) { return do_spill(cx, v, t); }
return v;
}

pub fn load_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef {
let _icx = cx.insn_ctxt("load_if_immediate");
if ty::type_is_immediate(t) { return Load(cx, v); }
if ty::type_is_immediate(cx.tcx(), t) { return Load(cx, v); }
return v;
}

@@ -1571,7 +1571,7 @@ pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks {
// slot where the return value of the function must go.
pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
unsafe {
if !ty::type_is_immediate(output_type) {
if !ty::type_is_immediate(fcx.ccx.tcx, output_type) {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(*fcx.ccx, output_type);
@@ -1612,7 +1612,7 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
}
};
let is_immediate = ty::type_is_immediate(substd_output_type);
let is_immediate = ty::type_is_immediate(ccx.tcx, substd_output_type);

let fcx = @mut fn_ctxt_ {
llfn: llfndecl,
@@ -1732,7 +1732,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
// This alloca should be optimized away by LLVM's mem-to-reg pass in
// the event it's not truly needed.
// only by value if immediate:
let llarg = if datum::appropriate_mode(arg_ty).is_by_value() {
let llarg = if datum::appropriate_mode(bcx.tcx(), arg_ty).is_by_value() {
let alloc = alloc_ty(bcx, arg_ty);
Store(bcx, raw_llarg, alloc);
alloc
24 changes: 19 additions & 5 deletions src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
@@ -486,8 +486,22 @@ pub fn trans_call_inner(in_cx: block,
}
Method(d) => {
// Weird but true: we pass self in the *environment* slot!
let llselfptr =
if ty::type_is_immediate(bcx.tcx(), d.self_ty) &&
d.self_mode != ty::ByRef &&
llvm::LLVMGetTypeKind(val_ty(d.llself)) != lib::llvm::Pointer {

let llselfptr = alloca(bcx, val_ty(d.llself));

Store(bcx, d.llself, llselfptr);
bcx = glue::drop_ty(bcx, llselfptr, d.self_ty);

llselfptr
} else {
d.llself
};
let llself = PointerCast(bcx,
d.llself,
llselfptr,
T_opaque_box_ptr(ccx));
(d.llfn, llself)
}
@@ -508,7 +522,7 @@ pub fn trans_call_inner(in_cx: block,

let mut llargs = ~[];

if ty::type_is_immediate(ret_ty) {
if ty::type_is_immediate(bcx.tcx(), ret_ty) {
unsafe {
llargs.push(llvm::LLVMGetUndef(T_ptr(T_i8())));
}
@@ -557,7 +571,7 @@ pub fn trans_call_inner(in_cx: block,
// case to ignore instead of invoking the Store
// below into a scratch pointer of a mismatched
// type.
} else if ty::type_is_immediate(ret_ty) {
} else if ty::type_is_immediate(bcx.tcx(), ret_ty) {
let llscratchptr = alloc_ty(bcx, ret_ty);
Store(bcx, llresult, llscratchptr);
bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
@@ -571,7 +585,7 @@ pub fn trans_call_inner(in_cx: block,
// If this is an immediate, store into the result location.
// (If this was not an immediate, the result will already be
// directly written into the output slot.)
if ty::type_is_immediate(ret_ty) {
if ty::type_is_immediate(bcx.tcx(), ret_ty) {
Store(bcx, llresult, lldest);
}
}
@@ -775,7 +789,7 @@ pub fn trans_arg_expr(bcx: block,
scratch.add_clean(bcx);
temp_cleanups.push(scratch.val);

match arg_datum.appropriate_mode() {
match arg_datum.appropriate_mode(bcx.tcx()) {
ByValue => val = Load(bcx, scratch.val),
ByRef => val = scratch.val,
}
29 changes: 8 additions & 21 deletions src/librustc/middle/trans/datum.rs
Original file line number Diff line number Diff line change
@@ -195,7 +195,7 @@ pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum {
Datum { val: scratch, ty: ty, mode: ByRef, source: RevokeClean }
}

pub fn appropriate_mode(ty: ty::t) -> DatumMode {
pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode {
/*!
*
* Indicates the "appropriate" mode for this value,
@@ -204,7 +204,7 @@ pub fn appropriate_mode(ty: ty::t) -> DatumMode {

if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
ByValue
} else if ty::type_is_immediate(ty) {
} else if ty::type_is_immediate(tcx, ty) {
ByValue
} else {
ByRef
@@ -474,18 +474,18 @@ pub impl Datum {
}
}

fn appropriate_mode(&self) -> DatumMode {
fn appropriate_mode(&self, tcx: ty::ctxt) -> DatumMode {
/*! See the `appropriate_mode()` function */

appropriate_mode(self.ty)
appropriate_mode(tcx, self.ty)
}

fn to_appropriate_llval(&self, bcx: block) -> ValueRef {
/*!
*
* Yields an llvalue with the `appropriate_mode()`. */

match self.appropriate_mode() {
match self.appropriate_mode(bcx.tcx()) {
ByValue => self.to_value_llval(bcx),
ByRef => self.to_ref_llval(bcx)
}
@@ -496,7 +496,7 @@ pub impl Datum {
*
* Yields a datum with the `appropriate_mode()`. */

match self.appropriate_mode() {
match self.appropriate_mode(bcx.tcx()) {
ByValue => self.to_value_datum(bcx),
ByRef => self.to_ref_datum(bcx)
}
@@ -620,13 +620,7 @@ pub impl Datum {
ByValue => {
// Actually, this case cannot happen right
// now, because enums are never immediate.
// But in principle newtype'd immediate
// values should be immediate, and in that
// case the * would be a no-op except for
// changing the type, so I am putting this
// code in place here to do the right
// thing if this change ever goes through.
assert!(ty::type_is_immediate(ty));
assert!(ty::type_is_immediate(bcx.tcx(), ty));
(Some(Datum {ty: ty, ..*self}), bcx)
}
};
@@ -659,14 +653,7 @@ pub impl Datum {
)
}
ByValue => {
// Actually, this case cannot happen right now,
// because structs are never immediate. But in
// principle, newtype'd immediate values should be
// immediate, and in that case the * would be a no-op
// except for changing the type, so I am putting this
// code in place here to do the right thing if this
// change ever goes through.
assert!(ty::type_is_immediate(ty));
assert!(ty::type_is_immediate(bcx.tcx(), ty));
(Some(Datum {ty: ty, ..*self}), bcx)
}
}
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
@@ -287,7 +287,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx));
let scratch = scratch_datum(bcx, closure_ty, false);
let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
assert_eq!(datum.appropriate_mode(), ByValue);
assert_eq!(datum.appropriate_mode(tcx), ByValue);
Store(bcx, datum.to_appropriate_llval(bcx), llfn);
let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
Store(bcx, base::null_env_ptr(bcx), llenv);
14 changes: 7 additions & 7 deletions src/librustc/middle/trans/foreign.rs
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@ fn foreign_signature(ccx: @CrateContext, fn_sig: &ty::FnSig)
LlvmSignature {
llarg_tys: llarg_tys,
llret_ty: llret_ty,
sret: !ty::type_is_immediate(fn_sig.output),
sret: !ty::type_is_immediate(ccx.tcx, fn_sig.output),
}
}

@@ -191,7 +191,7 @@ fn build_wrap_fn_(ccx: @CrateContext,

// 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(tys.fn_sig.output) {
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.llstaticallocas),
lloutputtype));
@@ -695,7 +695,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
// is not necessary since, for intrinsics, there is no
// cleanup to concern ourselves with.
let tp_ty = substs.tys[0];
let mode = appropriate_mode(tp_ty);
let mode = appropriate_mode(ccx.tcx, tp_ty);
let src = Datum {val: get_param(decl, first_real_arg + 1u),
ty: tp_ty, mode: mode, source: RevokeClean};
bcx = src.move_to(bcx, DROP_EXISTING,
@@ -704,7 +704,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
~"move_val_init" => {
// See comments for `"move_val"`.
let tp_ty = substs.tys[0];
let mode = appropriate_mode(tp_ty);
let mode = appropriate_mode(ccx.tcx, tp_ty);
let src = Datum {val: get_param(decl, first_real_arg + 1u),
ty: tp_ty, mode: mode, source: RevokeClean};
bcx = src.move_to(bcx, INIT, get_param(decl, first_real_arg));
@@ -775,7 +775,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
let lldestptr = PointerCast(bcx, lldestptr, T_ptr(T_i8()));

let llsrcval = get_param(decl, first_real_arg);
let llsrcptr = if ty::type_is_immediate(in_type) {
let llsrcptr = if ty::type_is_immediate(ccx.tcx, in_type) {
let llsrcptr = alloca(bcx, llintype);
Store(bcx, llsrcval, llsrcptr);
llsrcptr
@@ -1206,7 +1206,7 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
let mut i = 0u;
let n = tys.fn_sig.inputs.len();

if !ty::type_is_immediate(tys.fn_sig.output) {
if !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
let llretptr = load_inbounds(bcx, llargbundle, ~[0u, n]);
llargvals.push(llretptr);
} else {
@@ -1234,7 +1234,7 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
shim_types: &ShimTypes,
llargbundle: ValueRef,
llretval: ValueRef) {
if ty::type_is_immediate(shim_types.fn_sig.output) {
if ty::type_is_immediate(bcx.tcx(), shim_types.fn_sig.output) {
// Write the value into the argument bundle.
let arg_count = shim_types.fn_sig.inputs.len();
let llretptr = load_inbounds(bcx,
29 changes: 28 additions & 1 deletion src/librustc/middle/trans/glue.rs
Original file line number Diff line number Diff line change
@@ -100,6 +100,15 @@ pub fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
ty::ty_estr(ty::vstore_box) => {
decr_refcnt_maybe_free(bcx, v, t)
}
ty::ty_struct(def_id, ref substs) => {
let fields = ty::struct_fields(bcx.tcx(), def_id, substs);

if fields.len() == 1 {
drop_ty_immediate(bcx, v, fields[0].mt.ty)
} else {
bcx.tcx().sess.bug(~"drop_ty_immediate: non-box ty")
}
}
_ => bcx.tcx().sess.bug(~"drop_ty_immediate: non-box ty")
}
}
@@ -120,6 +129,15 @@ pub fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> Result {
ty::ty_estr(ty::vstore_uniq) => {
tvec::duplicate_uniq(bcx, v, t)
}
ty::ty_struct(def_id, ref substs) => {
let fields = ty::struct_fields(bcx.tcx(), def_id, substs);

if fields.len() == 1 {
take_ty_immediate(bcx, v, fields[0].mt.ty)
} else {
rslt(bcx, v)
}
}
_ => rslt(bcx, v)
}
}
@@ -147,6 +165,15 @@ pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
Store(bcx, v, vp);
free_ty(bcx, vp, t)
}
ty::ty_struct(def_id, ref substs) => {
let fields = ty::struct_fields(bcx.tcx(), def_id, substs);

if fields.len() == 1 {
free_ty_immediate(bcx, v, fields[0].mt.ty)
} else {
bcx.tcx().sess.bug(~"free_ty_immediate: non-box ty")
}
}
_ => bcx.tcx().sess.bug(~"free_ty_immediate: non-box ty")
}
}
@@ -641,7 +668,7 @@ pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
pub fn declare_tydesc_addrspace(ccx: @CrateContext, t: ty::t) -> addrspace {
if !ty::type_needs_drop(ccx.tcx, t) {
return default_addrspace;
} else if ty::type_is_immediate(t) {
} else if ty::type_is_immediate(ccx.tcx, t) {
// For immediate types, we don't actually need an addrspace, because
// e.g. boxed types include pointers to their contents which are
// already correctly tagged with addrspaces.
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/monomorphize.rs
Original file line number Diff line number Diff line change
@@ -378,7 +378,7 @@ pub fn make_mono_id(ccx: @CrateContext,
let llty = type_of::type_of(ccx, subst);
let size = machine::llbitsize_of_real(ccx, llty);
let align = machine::llalign_of_pref(ccx, llty);
let mode = datum::appropriate_mode(subst);
let mode = datum::appropriate_mode(ccx.tcx, subst);
let data_class = mono_data_classify(subst);

// Special value for nil to prevent problems
6 changes: 3 additions & 3 deletions src/librustc/middle/trans/type_of.rs
Original file line number Diff line number Diff line change
@@ -19,8 +19,8 @@ use util::ppaux;

use syntax::ast;

pub fn arg_is_indirect(_: @CrateContext, arg_ty: &ty::t) -> bool {
!ty::type_is_immediate(*arg_ty)
pub fn arg_is_indirect(ccx: @CrateContext, arg_ty: &ty::t) -> bool {
!ty::type_is_immediate(ccx.tcx, *arg_ty)
}

pub fn type_of_explicit_arg(ccx: @CrateContext, arg_ty: &ty::t) -> TypeRef {
@@ -40,7 +40,7 @@ pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::t], output: ty::t)

// Arg 0: Output pointer.
// (if the output type is non-immediate)
let output_is_immediate = ty::type_is_immediate(output);
let output_is_immediate = ty::type_is_immediate(cx.tcx, output);
let lloutputtype = type_of(cx, output);
if !output_is_immediate {
atys.push(T_ptr(lloutputtype));
20 changes: 16 additions & 4 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
@@ -1689,9 +1689,21 @@ pub fn type_is_scalar(ty: t) -> bool {
}
}

pub fn type_is_immediate(ty: t) -> bool {
return type_is_scalar(ty) || type_is_boxed(ty) ||
type_is_unique(ty) || type_is_region_ptr(ty);
pub fn type_is_newtype_scalar(cx: ctxt, ty: t) -> bool {
match get(ty).sty {
ty_struct(def_id, ref substs) => {
let fields = struct_fields(cx, def_id, substs);

// Is this a newtype/single field scalar struct?
fields.len() == 1 && type_is_scalar(fields[0].mt.ty)
}
_ => false
}
}

pub fn type_is_immediate(cx: ctxt, ty: t) -> bool {
return type_is_newtype_scalar(cx, ty) || type_is_scalar(ty) ||
type_is_boxed(ty) || type_is_unique(ty) || type_is_region_ptr(ty);
}

pub fn type_needs_drop(cx: ctxt, ty: t) -> bool {
@@ -3215,7 +3227,7 @@ pub fn expr_kind(tcx: ctxt,
ast::expr_cast(*) => {
match tcx.node_types.find(&(expr.id as uint)) {
Some(&t) => {
if ty::type_is_immediate(t) {
if ty::type_is_immediate(tcx, t) {
RvalueDatumExpr
} else {
RvalueDpsExpr
Binary file removed src/test/run-pass/issue-3559
Binary file not shown.
Binary file removed src/test/run-pass/issue-3702
Binary file not shown.
Binary file removed src/test/run-pass/issue-4016
Binary file not shown.
Binary file removed src/test/run-pass/issue-4092
Binary file not shown.
Loading