diff --git a/src/rustc/middle/trans/datum.rs b/src/rustc/middle/trans/datum.rs index 4f3591d99ca..d6338eb8565 100644 --- a/src/rustc/middle/trans/datum.rs +++ b/src/rustc/middle/trans/datum.rs @@ -373,18 +373,39 @@ impl Datum { self.source) } + fn to_value_datum(bcx: block) -> Datum { + /*! + * + * Yields a by-ref form of this datum. This may involve + * creation of a temporary stack slot. The value returned by + * this function is not separately rooted from this datum, so + * it will not live longer than the current datum. */ + + match self.mode { + ByValue => self, + ByRef => { + Datum {val: self.to_value_llval(bcx), mode: ByValue, + ty: self.ty, source: FromRvalue} + } + } + } + fn to_value_llval(bcx: block) -> ValueRef { /*! * * Yields the value itself. */ - match self.mode { - ByValue => self.val, - ByRef => Load(bcx, self.val) + if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { + C_nil() + } else { + match self.mode { + ByValue => self.val, + ByRef => Load(bcx, self.val) + } } } - fn to_ref(bcx: block) -> Datum { + fn to_ref_datum(bcx: block) -> Datum { /*! * * Yields a by-ref form of this datum. This may involve @@ -405,25 +426,52 @@ impl Datum { match self.mode { ByRef => self.val, ByValue => { - let slot = alloc_ty(bcx, self.ty); - Store(bcx, self.val, slot); - slot + if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { + C_null(T_ptr(type_of::type_of(bcx.ccx(), self.ty))) + } else { + let slot = alloc_ty(bcx, self.ty); + Store(bcx, self.val, slot); + slot + } } } } + fn appropriate_mode() -> DatumMode { + /*! + * + * Indicates the "appropriate" mode for this value, + * which is either by ref or by value, depending + * on whether type is iimmediate or what. */ + + if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { + ByValue + } else if ty::type_is_immediate(self.ty) { + ByValue + } else { + ByRef + } + } + fn to_appropriate_llval(bcx: block) -> ValueRef { /*! * - * Yields something that is by value if the type is immediate - * and by ref otherwise. */ + * Yields an llvalue with the `appropriate_mode()`. */ - if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { - self.to_value_llval(bcx) - } else if ty::type_is_immediate(self.ty) { - self.to_value_llval(bcx) - } else { - self.to_ref_llval(bcx) + match self.appropriate_mode() { + ByValue => self.to_value_llval(bcx), + ByRef => self.to_ref_llval(bcx) + } + } + + fn to_appropriate_datum(bcx: block) -> Datum { + /*! + * + * Yields a datum with the `appropriate_mode()`. */ + + match self.appropriate_mode() { + ByValue => self.to_value_datum(bcx), + ByRef => self.to_ref_datum(bcx) } } diff --git a/src/rustc/middle/trans/expr.rs b/src/rustc/middle/trans/expr.rs index 8b2acf1c0b5..1e9c36b1e7e 100644 --- a/src/rustc/middle/trans/expr.rs +++ b/src/rustc/middle/trans/expr.rs @@ -206,6 +206,18 @@ fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { } else { let scratch = scratch_datum(bcx, ty, false); bcx = trans_rvalue_dps(bcx, expr, SaveIn(scratch.val)); + + // Note: this is not obviously a good idea. It causes + // immediate values to be loaded immediately after a + // return from a call or other similar expression, + // which in turn leads to alloca's having shorter + // lifetimes and hence larger stack frames. However, + // in turn it can lead to more register pressure. + // Still, in practice it seems to increase + // performance, since we have fewer problems with + // morestack churn. + let scratch = scratch.to_appropriate_datum(bcx); + scratch.add_clean(bcx); return DatumBlock {bcx: bcx, datum: scratch}; }