Skip to content

Commit f1f453c

Browse files
committed
trans: generalize OperandValue::FatPtr to all pairs of immediates.
1 parent 156b1fb commit f1f453c

File tree

5 files changed

+238
-91
lines changed

5 files changed

+238
-91
lines changed

src/librustc_trans/common.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use monomorphize;
3939
use type_::Type;
4040
use value::Value;
4141
use rustc::ty::{self, Ty, TyCtxt};
42+
use rustc::ty::layout::Layout;
4243
use rustc::traits::{self, SelectionContext, ProjectionMode};
4344
use rustc::ty::fold::TypeFoldable;
4445
use rustc::hir;
@@ -99,6 +100,63 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
99100
}
100101
}
101102

103+
/// Returns Some([a, b]) if the type has a pair of fields with types a and b.
104+
pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
105+
-> Option<[Ty<'tcx>; 2]> {
106+
match ty.sty {
107+
ty::TyEnum(adt, substs) | ty::TyStruct(adt, substs) => {
108+
assert_eq!(adt.variants.len(), 1);
109+
let fields = &adt.variants[0].fields;
110+
if fields.len() != 2 {
111+
return None;
112+
}
113+
Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]),
114+
monomorphize::field_ty(ccx.tcx(), substs, &fields[1])])
115+
}
116+
ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) |
117+
ty::TyTuple(tys) => {
118+
if tys.len() != 2 {
119+
return None;
120+
}
121+
Some([tys[0], tys[1]])
122+
}
123+
_ => None
124+
}
125+
}
126+
127+
/// Returns true if the type is represented as a pair of immediates.
128+
pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
129+
-> bool {
130+
let tcx = ccx.tcx();
131+
let layout = tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
132+
match ty.layout(&infcx) {
133+
Ok(layout) => layout,
134+
Err(err) => {
135+
bug!("type_is_imm_pair: layout for `{:?}` failed: {}",
136+
ty, err);
137+
}
138+
}
139+
});
140+
141+
match *layout {
142+
Layout::FatPointer { .. } => true,
143+
Layout::Univariant { ref variant, .. } => {
144+
// There must be only 2 fields.
145+
if variant.offset_after_field.len() != 2 {
146+
return false;
147+
}
148+
149+
match type_pair_fields(ccx, ty) {
150+
Some([a, b]) => {
151+
type_is_immediate(ccx, a) && type_is_immediate(ccx, b)
152+
}
153+
None => false
154+
}
155+
}
156+
_ => false
157+
}
158+
}
159+
102160
/// Identify types which have size zero at runtime.
103161
pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
104162
use machine::llsize_of_alloc;

src/librustc_trans/mir/block.rs

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use adt;
1717
use base;
1818
use build;
1919
use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
20-
use common::{self, type_is_fat_ptr, Block, BlockAndBuilder, LandingPad};
20+
use common::{self, Block, BlockAndBuilder, LandingPad};
2121
use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
2222
use consts;
2323
use debuginfo::DebugLoc;
@@ -36,7 +36,7 @@ use super::analyze::CleanupKind;
3636
use super::constant::Const;
3737
use super::lvalue::{LvalueRef, load_fat_ptr};
3838
use super::operand::OperandRef;
39-
use super::operand::OperandValue::{self, FatPtr, Immediate, Ref};
39+
use super::operand::OperandValue::*;
4040

4141
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
4242
pub fn trans_block(&mut self, bb: mir::BasicBlock) {
@@ -410,8 +410,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
410410
}
411411
}
412412

413-
let val = self.trans_operand(&bcx, arg).val;
414-
self.trans_argument(&bcx, val, &mut llargs, &fn_ty,
413+
let op = self.trans_operand(&bcx, arg);
414+
self.trans_argument(&bcx, op, &mut llargs, &fn_ty,
415415
&mut idx, &mut callee.data);
416416
}
417417
if let Some(tup) = untuple {
@@ -449,7 +449,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
449449
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
450450
// Make a fake operand for store_return
451451
let op = OperandRef {
452-
val: OperandValue::Ref(dst),
452+
val: Ref(dst),
453453
ty: sig.output.unwrap()
454454
};
455455
self.store_return(&bcx, ret_dest, fn_ty.ret, op);
@@ -487,7 +487,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
487487
ret_bcx.at_start(|ret_bcx| {
488488
debug_loc.apply_to_bcx(ret_bcx);
489489
let op = OperandRef {
490-
val: OperandValue::Immediate(invokeret),
490+
val: Immediate(invokeret),
491491
ty: sig.output.unwrap()
492492
};
493493
self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
@@ -498,7 +498,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
498498
fn_ty.apply_attrs_callsite(llret);
499499
if let Some((_, target)) = *destination {
500500
let op = OperandRef {
501-
val: OperandValue::Immediate(llret),
501+
val: Immediate(llret),
502502
ty: sig.output.unwrap()
503503
};
504504
self.store_return(&bcx, ret_dest, fn_ty.ret, op);
@@ -513,25 +513,36 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
513513

514514
fn trans_argument(&mut self,
515515
bcx: &BlockAndBuilder<'bcx, 'tcx>,
516-
val: OperandValue,
516+
mut op: OperandRef<'tcx>,
517517
llargs: &mut Vec<ValueRef>,
518518
fn_ty: &FnType,
519519
next_idx: &mut usize,
520520
callee: &mut CalleeData) {
521-
// Treat the values in a fat pointer separately.
522-
if let FatPtr(ptr, meta) = val {
523-
if *next_idx == 0 {
524-
if let Virtual(idx) = *callee {
525-
let llfn = bcx.with_block(|bcx| {
526-
meth::get_virtual_method(bcx, meta, idx)
527-
});
528-
let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
529-
*callee = Fn(bcx.pointercast(llfn, llty));
521+
if let Pair(a, b) = op.val {
522+
// Treat the values in a fat pointer separately.
523+
if common::type_is_fat_ptr(bcx.tcx(), op.ty) {
524+
let (ptr, meta) = (a, b);
525+
if *next_idx == 0 {
526+
if let Virtual(idx) = *callee {
527+
let llfn = bcx.with_block(|bcx| {
528+
meth::get_virtual_method(bcx, meta, idx)
529+
});
530+
let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
531+
*callee = Fn(bcx.pointercast(llfn, llty));
532+
}
530533
}
534+
535+
let imm_op = |x| OperandRef {
536+
val: Immediate(x),
537+
// We won't be checking the type again.
538+
ty: bcx.tcx().types.err
539+
};
540+
self.trans_argument(bcx, imm_op(ptr), llargs, fn_ty, next_idx, callee);
541+
self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, callee);
542+
return;
531543
}
532-
self.trans_argument(bcx, Immediate(ptr), llargs, fn_ty, next_idx, callee);
533-
self.trans_argument(bcx, Immediate(meta), llargs, fn_ty, next_idx, callee);
534-
return;
544+
545+
op = op.pack_if_pair(bcx);
535546
}
536547

537548
let arg = &fn_ty.args[*next_idx];
@@ -547,15 +558,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
547558
}
548559

549560
// Force by-ref if we have to load through a cast pointer.
550-
let (mut llval, by_ref) = match val {
561+
let (mut llval, by_ref) = match op.val {
551562
Immediate(llval) if arg.is_indirect() || arg.cast.is_some() => {
552563
let llscratch = build::AllocaFcx(bcx.fcx(), arg.original_ty, "arg");
553564
bcx.store(llval, llscratch);
554565
(llscratch, true)
555566
}
556567
Immediate(llval) => (llval, false),
557568
Ref(llval) => (llval, true),
558-
FatPtr(_, _) => bug!("fat pointers handled above")
569+
Pair(..) => bug!("pairs handled above")
559570
};
560571

561572
if by_ref && !arg.is_indirect() {
@@ -602,12 +613,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
602613
let ptr = adt::trans_field_ptr_builder(bcx, &base_repr, base, Disr(0), n);
603614
let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
604615
let (lldata, llextra) = load_fat_ptr(bcx, ptr);
605-
FatPtr(lldata, llextra)
616+
Pair(lldata, llextra)
606617
} else {
607618
// trans_argument will load this if it needs to
608619
Ref(ptr)
609620
};
610-
self.trans_argument(bcx, val, llargs, fn_ty, next_idx, callee);
621+
let op = OperandRef {
622+
val: val,
623+
ty: ty
624+
};
625+
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
611626
}
612627

613628
}
@@ -619,11 +634,29 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
619634
elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
620635
}
621636
// If the tuple is immediate, the elements are as well
622-
let val = Immediate(elem);
623-
self.trans_argument(bcx, val, llargs, fn_ty, next_idx, callee);
637+
let op = OperandRef {
638+
val: Immediate(elem),
639+
ty: ty
640+
};
641+
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
642+
}
643+
}
644+
Pair(a, b) => {
645+
let elems = [a, b];
646+
for (n, &ty) in arg_types.iter().enumerate() {
647+
let mut elem = elems[n];
648+
// Truncate bools to i1, if needed
649+
if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx()) {
650+
elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
651+
}
652+
// Pair is always made up of immediates
653+
let op = OperandRef {
654+
val: Immediate(elem),
655+
ty: ty
656+
};
657+
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
624658
}
625659
}
626-
FatPtr(_, _) => bug!("tuple is a fat pointer?!")
627660
}
628661

629662
}
@@ -779,7 +812,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
779812
let f = Callee::def(bcx.ccx(), def_id, substs);
780813
let datum = f.reify(bcx.ccx());
781814
val = OperandRef {
782-
val: OperandValue::Immediate(datum.val),
815+
val: Immediate(datum.val),
783816
ty: datum.ty
784817
};
785818
}
@@ -806,17 +839,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
806839
self.temps[idx as usize] = TempRef::Operand(Some(op));
807840
}
808841
DirectOperand(idx) => {
809-
let op = if type_is_fat_ptr(bcx.tcx(), op.ty) {
810-
let llval = op.immediate();
811-
let ptr = bcx.extract_value(llval, 0);
812-
let meta = bcx.extract_value(llval, 1);
813-
814-
OperandRef {
815-
val: OperandValue::FatPtr(ptr, meta),
816-
ty: op.ty
817-
}
842+
// If there is a cast, we have to store and reload.
843+
let op = if ret_ty.cast.is_some() {
844+
let tmp = bcx.with_block(|bcx| {
845+
base::alloc_ty(bcx, op.ty, "tmp_ret")
846+
});
847+
ret_ty.store(bcx, op.immediate(), tmp);
848+
self.trans_load(bcx, tmp, op.ty)
818849
} else {
819-
op
850+
op.unpack_if_pair(bcx)
820851
};
821852
self.temps[idx as usize] = TempRef::Operand(Some(op));
822853
}

src/librustc_trans/mir/constant.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,15 @@ impl<'tcx> Const<'tcx> {
9898
Const::new(val, ty)
9999
}
100100

101+
fn get_pair(&self) -> (ValueRef, ValueRef) {
102+
(const_get_elt(self.llval, &[0]),
103+
const_get_elt(self.llval, &[1]))
104+
}
105+
101106
fn get_fat_ptr(&self) -> (ValueRef, ValueRef) {
102-
(const_get_elt(self.llval, &[abi::FAT_PTR_ADDR as u32]),
103-
const_get_elt(self.llval, &[abi::FAT_PTR_EXTRA as u32]))
107+
assert_eq!(abi::FAT_PTR_ADDR, 0);
108+
assert_eq!(abi::FAT_PTR_EXTRA, 1);
109+
self.get_pair()
104110
}
105111

106112
fn as_lvalue(&self) -> ConstLvalue<'tcx> {
@@ -115,9 +121,9 @@ impl<'tcx> Const<'tcx> {
115121
let llty = type_of::immediate_type_of(ccx, self.ty);
116122
let llvalty = val_ty(self.llval);
117123

118-
let val = if common::type_is_fat_ptr(ccx.tcx(), self.ty) {
119-
let (data, extra) = self.get_fat_ptr();
120-
OperandValue::FatPtr(data, extra)
124+
let val = if common::type_is_imm_pair(ccx, self.ty) {
125+
let (a, b) = self.get_pair();
126+
OperandValue::Pair(a, b)
121127
} else if common::type_is_immediate(ccx, self.ty) && llty == llvalty {
122128
// If the types match, we can use the value directly.
123129
OperandValue::Immediate(self.llval)
@@ -656,7 +662,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
656662
consts::ptrcast(data_ptr, ll_cast_ty)
657663
}
658664
} else {
659-
bug!("Unexpected non-FatPtr operand")
665+
bug!("Unexpected non-fat-pointer operand")
660666
}
661667
}
662668
};

0 commit comments

Comments
 (0)