Skip to content

Commit ee2de27

Browse files
committed
Add support for aggregates in platform intrinsics.
This adds support for flattened intrinsics, which are called in Rust with tuples but in LLVM without them (e.g. `foo((a, b))` becomes `foo(a, b)`). Unflattened ones could be supported, but are not yet.
1 parent b03ca7f commit ee2de27

File tree

3 files changed

+101
-10
lines changed

3 files changed

+101
-10
lines changed

src/librustc_platform_intrinsics/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub enum Type {
3434
Float(u8),
3535
Pointer(Box<Type>),
3636
Vector(Box<Type>, u8),
37+
Aggregate(bool, Vec<Type>),
3738
}
3839

3940
pub enum IntrinsicDef {
@@ -44,6 +45,9 @@ fn i(width: u8) -> Type { Type::Integer(true, width) }
4445
fn u(width: u8) -> Type { Type::Integer(false, width) }
4546
fn f(width: u8) -> Type { Type::Float(width) }
4647
fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) }
48+
fn agg(flatten: bool, types: Vec<Type>) -> Type {
49+
Type::Aggregate(flatten, types)
50+
}
4751

4852
macro_rules! ty {
4953
(f32x8) => (v(f(32), 8));

src/librustc_trans/trans/intrinsic.rs

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
171171

172172
let _icx = push_ctxt("trans_intrinsic_call");
173173

174-
let ret_ty = match callee_ty.sty {
174+
let (arg_tys, ret_ty) = match callee_ty.sty {
175175
ty::TyBareFn(_, ref f) => {
176-
bcx.tcx().erase_late_bound_regions(&f.sig.output())
176+
(bcx.tcx().erase_late_bound_regions(&f.sig.inputs()),
177+
bcx.tcx().erase_late_bound_regions(&f.sig.output()))
177178
}
178179
_ => panic!("expected bare_fn in trans_intrinsic_call")
179180
};
@@ -924,25 +925,94 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
924925
Some(intr) => intr,
925926
None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"),
926927
};
927-
fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type) -> Type {
928+
fn one<T>(x: Vec<T>) -> T {
929+
assert_eq!(x.len(), 1);
930+
x.into_iter().next().unwrap()
931+
}
932+
fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type,
933+
any_flattened_aggregate: &mut bool) -> Vec<Type> {
928934
use intrinsics::Type::*;
929935
match *t {
930-
Integer(_signed, x) => Type::ix(ccx, x as u64),
936+
Integer(_signed, x) => vec![Type::ix(ccx, x as u64)],
931937
Float(x) => {
932938
match x {
933-
32 => Type::f32(ccx),
934-
64 => Type::f64(ccx),
939+
32 => vec![Type::f32(ccx)],
940+
64 => vec![Type::f64(ccx)],
935941
_ => unreachable!()
936942
}
937943
}
938944
Pointer(_) => unimplemented!(),
939-
Vector(ref t, length) => Type::vector(&ty_to_type(ccx, t),
940-
length as u64)
945+
Vector(ref t, length) => {
946+
let elem = one(ty_to_type(ccx, t,
947+
any_flattened_aggregate));
948+
vec![Type::vector(&elem,
949+
length as u64)]
950+
}
951+
Aggregate(false, _) => unimplemented!(),
952+
Aggregate(true, ref contents) => {
953+
*any_flattened_aggregate = true;
954+
contents.iter()
955+
.flat_map(|t| ty_to_type(ccx, t, any_flattened_aggregate))
956+
.collect()
957+
}
958+
}
959+
}
960+
961+
// This allows an argument list like `foo, (bar, baz),
962+
// qux` to be converted into `foo, bar, baz, qux`.
963+
fn flatten_aggregate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
964+
t: &intrinsics::Type,
965+
arg_type: Ty<'tcx>,
966+
llarg: ValueRef)
967+
-> Vec<ValueRef>
968+
{
969+
match *t {
970+
intrinsics::Type::Aggregate(true, ref contents) => {
971+
// We found a tuple that needs squishing! So
972+
// run over the tuple and load each field.
973+
//
974+
// This assumes the type is "simple", i.e. no
975+
// destructors, and the contents are SIMD
976+
// etc.
977+
assert!(!bcx.fcx.type_needs_drop(arg_type));
978+
979+
let repr = adt::represent_type(bcx.ccx(), arg_type);
980+
let repr_ptr = &*repr;
981+
(0..contents.len())
982+
.map(|i| {
983+
Load(bcx, adt::trans_field_ptr(bcx, repr_ptr, llarg, 0, i))
984+
})
985+
.collect()
986+
}
987+
_ => vec![llarg],
941988
}
942989
}
943990

944-
let inputs = intr.inputs.iter().map(|t| ty_to_type(ccx, t)).collect::<Vec<_>>();
945-
let outputs = ty_to_type(ccx, &intr.output);
991+
992+
let mut any_flattened_aggregate = false;
993+
let inputs = intr.inputs.iter()
994+
.flat_map(|t| ty_to_type(ccx, t, &mut any_flattened_aggregate))
995+
.collect::<Vec<_>>();
996+
997+
let mut out_flattening = false;
998+
let outputs = one(ty_to_type(ccx, &intr.output, &mut out_flattening));
999+
// outputting a flattened aggregate is nonsense
1000+
assert!(!out_flattening);
1001+
1002+
let llargs = if !any_flattened_aggregate {
1003+
// no aggregates to flatten, so no change needed
1004+
llargs
1005+
} else {
1006+
// there are some aggregates that need to be flattened
1007+
// in the LLVM call, so we need to run over the types
1008+
// again to find them and extract the arguments
1009+
intr.inputs.iter()
1010+
.zip(&llargs)
1011+
.zip(&arg_tys)
1012+
.flat_map(|((t, llarg), ty)| flatten_aggregate(bcx, t, ty, *llarg))
1013+
.collect()
1014+
};
1015+
9461016
match intr.definition {
9471017
intrinsics::IntrinsicDef::Named(name) => {
9481018
let f = declare::declare_cfn(ccx,

src/librustc_typeck/check/intrinsic.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,5 +507,22 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
507507
inner_expected,
508508
t_ty)
509509
}
510+
Aggregate(_flatten, ref expected_contents) => {
511+
match t.sty {
512+
ty::TyTuple(ref contents) => {
513+
if contents.len() != expected_contents.len() {
514+
simple_error(&format!("tuple with length {}", contents.len()),
515+
&format!("tuple with length {}", expected_contents.len()));
516+
return
517+
}
518+
for (e, c) in expected_contents.iter().zip(contents) {
519+
match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal,
520+
e, c)
521+
}
522+
}
523+
_ => simple_error(&format!("`{}`", t),
524+
&format!("tuple")),
525+
}
526+
}
510527
}
511528
}

0 commit comments

Comments
 (0)