Skip to content

Commit f1b7cd9

Browse files
committed
rustc_trans: restrict "immediate pairs" to pairs of scalars.
1 parent ac60872 commit f1b7cd9

File tree

10 files changed

+84
-106
lines changed

10 files changed

+84
-106
lines changed

src/librustc_trans/common.rs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use type_of::LayoutLlvmExt;
2828
use value::Value;
2929
use rustc::traits;
3030
use rustc::ty::{self, Ty, TyCtxt};
31-
use rustc::ty::layout::{self, HasDataLayout, LayoutOf};
31+
use rustc::ty::layout::{HasDataLayout, LayoutOf};
3232
use rustc::ty::subst::{Kind, Subst, Substs};
3333
use rustc::hir;
3434

@@ -54,25 +54,6 @@ pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) ->
5454
}
5555
}
5656

57-
/// Returns true if the type is represented as a pair of immediates.
58-
pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
59-
-> bool {
60-
let layout = ccx.layout_of(ty);
61-
match layout.fields {
62-
layout::FieldPlacement::Arbitrary { .. } => {
63-
// There must be only 2 fields.
64-
if layout.fields.count() != 2 {
65-
return false;
66-
}
67-
68-
// The two fields must be both immediates.
69-
layout.field(ccx, 0).is_llvm_immediate() &&
70-
layout.field(ccx, 1).is_llvm_immediate()
71-
}
72-
_ => false
73-
}
74-
}
75-
7657
pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
7758
ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All))
7859
}

src/librustc_trans/intrinsic.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -675,10 +675,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
675675
let ptr = bcx.pointercast(llresult, ty.llvm_type(ccx).ptr_to());
676676
bcx.store(llval, ptr, Some(ccx.align_of(ret_ty)));
677677
} else {
678-
OperandRef {
679-
val: OperandValue::Immediate(llval),
680-
layout: result.layout
681-
}.unpack_if_pair(bcx).val.store(bcx, result);
678+
OperandRef::from_immediate_or_packed_pair(bcx, llval, result.layout)
679+
.val.store(bcx, result);
682680
}
683681
}
684682
}

src/librustc_trans/mir/analyze.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use rustc::mir::visit::{Visitor, LvalueContext};
1919
use rustc::mir::traversal;
2020
use rustc::ty;
2121
use rustc::ty::layout::LayoutOf;
22-
use common;
2322
use type_of::LayoutLlvmExt;
2423
use super::MirContext;
2524

@@ -32,10 +31,11 @@ pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector {
3231
for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
3332
let ty = mircx.monomorphize(&ty);
3433
debug!("local {} has type {:?}", index, ty);
35-
if mircx.ccx.layout_of(ty).is_llvm_immediate() {
34+
let layout = mircx.ccx.layout_of(ty);
35+
if layout.is_llvm_immediate() {
3636
// These sorts of types are immediates that we can store
3737
// in an ValueRef without an alloca.
38-
} else if common::type_is_imm_pair(mircx.ccx, ty) {
38+
} else if layout.is_llvm_scalar_pair(mircx.ccx) {
3939
// We allow pairs and uses of any of their 2 fields.
4040
} else {
4141
// These sorts of types require an alloca. Note that
@@ -145,7 +145,8 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
145145
let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
146146

147147
let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
148-
if common::type_is_imm_pair(self.cx.ccx, ty) {
148+
let layout = self.cx.ccx.layout_of(ty);
149+
if layout.is_llvm_scalar_pair(self.cx.ccx) {
149150
return;
150151
}
151152
}

src/librustc_trans/mir/block.rs

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
135135
if let Some((ret_dest, target)) = destination {
136136
let ret_bcx = this.get_builder(target);
137137
this.set_debug_loc(&ret_bcx, terminator.source_info);
138-
let op = OperandRef {
139-
val: Immediate(invokeret),
140-
layout: fn_ty.ret.layout,
141-
};
142-
this.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op);
138+
this.store_return(&ret_bcx, ret_dest, &fn_ty.ret, invokeret);
143139
}
144140
} else {
145141
let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle);
@@ -153,11 +149,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
153149
}
154150

155151
if let Some((ret_dest, target)) = destination {
156-
let op = OperandRef {
157-
val: Immediate(llret),
158-
layout: fn_ty.ret.layout,
159-
};
160-
this.store_return(&bcx, ret_dest, &fn_ty.ret, op);
152+
this.store_return(&bcx, ret_dest, &fn_ty.ret, llret);
161153
funclet_br(this, bcx, target);
162154
} else {
163155
bcx.unreachable();
@@ -252,7 +244,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
252244
if let Ref(llval, align) = op.val {
253245
bcx.load(llval, align.non_abi())
254246
} else {
255-
op.pack_if_pair(&bcx).immediate()
247+
op.immediate_or_packed_pair(&bcx)
256248
}
257249
};
258250
bcx.ret(llval);
@@ -545,12 +537,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
545537
terminator.source_info.span);
546538

547539
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
548-
// Make a fake operand for store_return
549-
let op = OperandRef {
550-
val: Ref(dst.llval, Alignment::AbiAligned),
551-
layout: fn_ty.ret.layout,
552-
};
553-
self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
540+
self.store_return(&bcx, ret_dest, &fn_ty.ret, dst.llval);
554541
}
555542

556543
if let Some((_, target)) = *destination {
@@ -649,7 +636,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
649636
op.val.store(bcx, scratch);
650637
(scratch.llval, Alignment::AbiAligned, true)
651638
} else {
652-
(op.pack_if_pair(bcx).immediate(), Alignment::AbiAligned, false)
639+
(op.immediate_or_packed_pair(bcx), Alignment::AbiAligned, false)
653640
}
654641
}
655642
Ref(llval, align @ Alignment::Packed(_)) if arg.is_indirect() => {
@@ -915,12 +902,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
915902
bcx: &Builder<'a, 'tcx>,
916903
dest: ReturnDest<'tcx>,
917904
ret_ty: &ArgType<'tcx>,
918-
op: OperandRef<'tcx>) {
905+
llval: ValueRef) {
919906
use self::ReturnDest::*;
920907

921908
match dest {
922909
Nothing => (),
923-
Store(dst) => ret_ty.store(bcx, op.immediate(), dst),
910+
Store(dst) => ret_ty.store(bcx, llval, dst),
924911
IndirectOperand(tmp, index) => {
925912
let op = tmp.load(bcx);
926913
tmp.storage_dead(bcx);
@@ -929,14 +916,14 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
929916
DirectOperand(index) => {
930917
// If there is a cast, we have to store and reload.
931918
let op = if ret_ty.cast.is_some() {
932-
let tmp = LvalueRef::alloca(bcx, op.layout, "tmp_ret");
919+
let tmp = LvalueRef::alloca(bcx, ret_ty.layout, "tmp_ret");
933920
tmp.storage_live(bcx);
934-
ret_ty.store(bcx, op.immediate(), tmp);
921+
ret_ty.store(bcx, llval, tmp);
935922
let op = tmp.load(bcx);
936923
tmp.storage_dead(bcx);
937924
op
938925
} else {
939-
op.unpack_if_pair(bcx)
926+
OperandRef::from_immediate_or_packed_pair(bcx, llval, ret_ty.layout)
940927
};
941928
self.locals[index] = LocalRef::Operand(Some(op));
942929
}

src/librustc_trans/mir/constant.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,14 @@ impl<'a, 'tcx> Const<'tcx> {
139139
}
140140

141141
pub fn to_operand(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
142-
let llty = ccx.layout_of(self.ty).immediate_llvm_type(ccx);
142+
let layout = ccx.layout_of(self.ty);
143+
let llty = layout.immediate_llvm_type(ccx);
143144
let llvalty = val_ty(self.llval);
144145

145-
let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
146+
let val = if llty == llvalty && layout.is_llvm_scalar_pair(ccx) {
146147
let (a, b) = self.get_pair(ccx);
147148
OperandValue::Pair(a, b)
148-
} else if llty == llvalty && ccx.layout_of(self.ty).is_llvm_immediate() {
149+
} else if llty == llvalty && layout.is_llvm_immediate() {
149150
// If the types match, we can use the value directly.
150151
OperandValue::Immediate(self.llval)
151152
} else {

src/librustc_trans/mir/lvalue.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc::mir::tcx::LvalueTy;
1616
use rustc_data_structures::indexed_vec::Idx;
1717
use base;
1818
use builder::Builder;
19-
use common::{self, CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big};
19+
use common::{CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big};
2020
use consts;
2121
use type_of::LayoutLlvmExt;
2222
use type_::Type;
@@ -175,10 +175,10 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
175175
load
176176
};
177177
OperandValue::Immediate(base::to_immediate(bcx, llval, self.layout))
178-
} else if common::type_is_imm_pair(bcx.ccx, self.layout.ty) {
178+
} else if self.layout.is_llvm_scalar_pair(bcx.ccx) {
179179
OperandValue::Pair(
180-
self.project_field(bcx, 0).load(bcx).pack_if_pair(bcx).immediate(),
181-
self.project_field(bcx, 1).load(bcx).pack_if_pair(bcx).immediate())
180+
self.project_field(bcx, 0).load(bcx).immediate(),
181+
self.project_field(bcx, 1).load(bcx).immediate())
182182
} else {
183183
OperandValue::Ref(self.llval, self.alignment)
184184
};

src/librustc_trans/mir/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,9 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
475475
let llarg = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
476476
bcx.set_value_name(llarg, &name);
477477
llarg_idx += 1;
478-
let operand = OperandRef {
479-
val: OperandValue::Immediate(llarg),
480-
layout: arg.layout
481-
};
482-
return LocalRef::Operand(Some(operand.unpack_if_pair(bcx)));
478+
return LocalRef::Operand(Some(
479+
OperandRef::from_immediate_or_packed_pair(bcx, llarg, arg.layout)
480+
));
483481
} else {
484482
let tmp = LvalueRef::alloca(bcx, arg.layout, &name);
485483
arg.store_fn_arg(bcx, &mut llarg_idx, tmp);

src/librustc_trans/mir/operand.rs

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::mir;
1515
use rustc_data_structures::indexed_vec::Idx;
1616

1717
use base;
18-
use common::{self, CrateContext, C_undef};
18+
use common::{CrateContext, C_undef};
1919
use builder::Builder;
2020
use value::Value;
2121
use type_of::LayoutLlvmExt;
@@ -24,7 +24,6 @@ use std::fmt;
2424
use std::ptr;
2525

2626
use super::{MirContext, LocalRef};
27-
use super::constant::Const;
2827
use super::lvalue::{Alignment, LvalueRef};
2928

3029
/// The representation of a Rust value. The enum variant is in fact
@@ -84,10 +83,10 @@ impl<'a, 'tcx> OperandRef<'tcx> {
8483
pub fn new_zst(ccx: &CrateContext<'a, 'tcx>,
8584
layout: TyLayout<'tcx>) -> OperandRef<'tcx> {
8685
assert!(layout.is_zst());
87-
let llty = layout.llvm_type(ccx);
88-
// FIXME(eddyb) ZSTs should always be immediate, not pairs.
89-
// This hack only exists to unpack a constant undef pair.
90-
Const::new(C_undef(llty), layout.ty).to_operand(ccx)
86+
OperandRef {
87+
val: OperandValue::Immediate(C_undef(layout.llvm_type(ccx))),
88+
layout
89+
}
9190
}
9291

9392
/// Asserts that this operand refers to a scalar and returns
@@ -115,42 +114,47 @@ impl<'a, 'tcx> OperandRef<'tcx> {
115114
}
116115
}
117116

118-
/// If this operand is a Pair, we return an
119-
/// Immediate aggregate with the two values.
120-
pub fn pack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
117+
/// If this operand is a `Pair`, we return an aggregate with the two values.
118+
/// For other cases, see `immediate`.
119+
pub fn immediate_or_packed_pair(self, bcx: &Builder<'a, 'tcx>) -> ValueRef {
121120
if let OperandValue::Pair(a, b) = self.val {
122121
let llty = self.layout.llvm_type(bcx.ccx);
123-
debug!("Operand::pack_if_pair: packing {:?} into {:?}", self, llty);
122+
debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}",
123+
self, llty);
124124
// Reconstruct the immediate aggregate.
125125
let mut llpair = C_undef(llty);
126126
let elems = [a, b];
127127
for i in 0..2 {
128128
let elem = base::from_immediate(bcx, elems[i]);
129129
llpair = bcx.insert_value(llpair, elem, self.layout.llvm_field_index(i));
130130
}
131-
self.val = OperandValue::Immediate(llpair);
131+
llpair
132+
} else {
133+
self.immediate()
132134
}
133-
self
134135
}
135136

136-
/// If this operand is a pair in an Immediate,
137-
/// we return a Pair with the two halves.
138-
pub fn unpack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
139-
if let OperandValue::Immediate(llval) = self.val {
140-
// Deconstruct the immediate aggregate.
141-
if common::type_is_imm_pair(bcx.ccx, self.layout.ty) {
142-
debug!("Operand::unpack_if_pair: unpacking {:?}", self);
137+
/// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`.
138+
pub fn from_immediate_or_packed_pair(bcx: &Builder<'a, 'tcx>,
139+
llval: ValueRef,
140+
layout: TyLayout<'tcx>)
141+
-> OperandRef<'tcx> {
142+
let val = if layout.is_llvm_scalar_pair(bcx.ccx) {
143+
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
144+
llval, layout);
143145

144-
let a = bcx.extract_value(llval, self.layout.llvm_field_index(0));
145-
let a = base::to_immediate(bcx, a, self.layout.field(bcx.ccx, 0));
146+
// Deconstruct the immediate aggregate.
147+
let a = bcx.extract_value(llval, layout.llvm_field_index(0));
148+
let a = base::to_immediate(bcx, a, layout.field(bcx.ccx, 0));
146149

147-
let b = bcx.extract_value(llval, self.layout.llvm_field_index(1));
148-
let b = base::to_immediate(bcx, b, self.layout.field(bcx.ccx, 1));
150+
let b = bcx.extract_value(llval, layout.llvm_field_index(1));
151+
let b = base::to_immediate(bcx, b, layout.field(bcx.ccx, 1));
149152

150-
self.val = OperandValue::Pair(a, b);
151-
}
152-
}
153-
self
153+
OperandValue::Pair(a, b)
154+
} else {
155+
OperandValue::Immediate(llval)
156+
};
157+
OperandRef { val, layout }
154158
}
155159
}
156160

@@ -170,16 +174,9 @@ impl<'a, 'tcx> OperandValue {
170174
bcx.store(base::from_immediate(bcx, s), dest.llval, dest.alignment.non_abi());
171175
}
172176
OperandValue::Pair(a, b) => {
173-
// See comment above about zero-sized values.
174-
let dest_a = dest.project_field(bcx, 0);
175-
if !dest_a.layout.is_zst() {
176-
let a = base::from_immediate(bcx, a);
177-
bcx.store(a, dest_a.llval, dest_a.alignment.non_abi());
178-
}
179-
let dest_b = dest.project_field(bcx, 1);
180-
if !dest_b.layout.is_zst() {
181-
let b = base::from_immediate(bcx, b);
182-
bcx.store(b, dest_b.llval, dest_b.alignment.non_abi());
177+
for (i, &x) in [a, b].iter().enumerate() {
178+
OperandValue::Immediate(x)
179+
.store(bcx, dest.project_field(bcx, i));
183180
}
184181
}
185182
}
@@ -218,13 +215,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
218215
(OperandValue::Pair(a, b),
219216
&mir::ProjectionElem::Field(ref f, ty)) => {
220217
let llval = [a, b][f.index()];
221-
let op = OperandRef {
218+
return OperandRef {
222219
val: OperandValue::Immediate(llval),
223220
layout: bcx.ccx.layout_of(self.monomorphize(&ty))
224221
};
225-
226-
// Handle nested pairs.
227-
return op.unpack_if_pair(bcx);
228222
}
229223
_ => {}
230224
}

src/librustc_trans/mir/rvalue.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
7070
// `CoerceUnsized` can be passed by a where-clause,
7171
// so the (generic) MIR may not be able to expand it.
7272
let operand = self.trans_operand(&bcx, source);
73-
let operand = operand.pack_if_pair(&bcx);
7473
match operand.val {
75-
OperandValue::Pair(..) => bug!(),
74+
OperandValue::Pair(..) |
7675
OperandValue::Immediate(_) => {
7776
// unsize from an immediate structure. We don't
7877
// really need a temporary alloca here, but

0 commit comments

Comments
 (0)