diff options
| author | Huon Wilson <dbau.pp+github@gmail.com> | 2015-08-28 16:34:07 -0700 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2015-08-29 15:36:16 -0700 |
| commit | ee2de279965a27e8189a9129a4b3454dd82568b9 (patch) | |
| tree | d3f43aeb293ce1a7f683566dafce3bfea64f7563 | |
| parent | b03ca7f805ab4e2bc6a5da6182fec6c0934042c7 (diff) | |
| download | rust-ee2de279965a27e8189a9129a4b3454dd82568b9.tar.gz rust-ee2de279965a27e8189a9129a4b3454dd82568b9.zip | |
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.
| -rwxr-xr-x | src/librustc_platform_intrinsics/lib.rs | 4 | ||||
| -rw-r--r-- | src/librustc_trans/trans/intrinsic.rs | 90 | ||||
| -rw-r--r-- | src/librustc_typeck/check/intrinsic.rs | 17 |
3 files changed, 101 insertions, 10 deletions
diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 476b9ee31fe..88ad2dce55c 100755 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -34,6 +34,7 @@ pub enum Type { Float(u8), Pointer(Box<Type>), Vector(Box<Type>, u8), + Aggregate(bool, Vec<Type>), } pub enum IntrinsicDef { @@ -44,6 +45,9 @@ fn i(width: u8) -> Type { Type::Integer(true, width) } fn u(width: u8) -> Type { Type::Integer(false, width) } fn f(width: u8) -> Type { Type::Float(width) } fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) } +fn agg(flatten: bool, types: Vec<Type>) -> Type { + Type::Aggregate(flatten, types) +} macro_rules! ty { (f32x8) => (v(f(32), 8)); diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index d6275f2b9e8..267a8a15f69 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -171,9 +171,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_intrinsic_call"); - let ret_ty = match callee_ty.sty { + let (arg_tys, ret_ty) = match callee_ty.sty { ty::TyBareFn(_, ref f) => { - bcx.tcx().erase_late_bound_regions(&f.sig.output()) + (bcx.tcx().erase_late_bound_regions(&f.sig.inputs()), + bcx.tcx().erase_late_bound_regions(&f.sig.output())) } _ => panic!("expected bare_fn in trans_intrinsic_call") }; @@ -924,25 +925,94 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, Some(intr) => intr, None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"), }; - fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type) -> Type { + fn one<T>(x: Vec<T>) -> T { + assert_eq!(x.len(), 1); + x.into_iter().next().unwrap() + } + fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type, + any_flattened_aggregate: &mut bool) -> Vec<Type> { use intrinsics::Type::*; match *t { - Integer(_signed, x) => Type::ix(ccx, x as u64), + Integer(_signed, x) => vec![Type::ix(ccx, x as u64)], Float(x) => { match x { - 32 => Type::f32(ccx), - 64 => Type::f64(ccx), + 32 => vec![Type::f32(ccx)], + 64 => vec![Type::f64(ccx)], _ => unreachable!() } } Pointer(_) => unimplemented!(), - Vector(ref t, length) => Type::vector(&ty_to_type(ccx, t), - length as u64) + Vector(ref t, length) => { + let elem = one(ty_to_type(ccx, t, + any_flattened_aggregate)); + vec![Type::vector(&elem, + length as u64)] + } + Aggregate(false, _) => unimplemented!(), + Aggregate(true, ref contents) => { + *any_flattened_aggregate = true; + contents.iter() + .flat_map(|t| ty_to_type(ccx, t, any_flattened_aggregate)) + .collect() + } + } + } + + // This allows an argument list like `foo, (bar, baz), + // qux` to be converted into `foo, bar, baz, qux`. + fn flatten_aggregate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + t: &intrinsics::Type, + arg_type: Ty<'tcx>, + llarg: ValueRef) + -> Vec<ValueRef> + { + match *t { + intrinsics::Type::Aggregate(true, ref contents) => { + // We found a tuple that needs squishing! So + // run over the tuple and load each field. + // + // This assumes the type is "simple", i.e. no + // destructors, and the contents are SIMD + // etc. + assert!(!bcx.fcx.type_needs_drop(arg_type)); + + let repr = adt::represent_type(bcx.ccx(), arg_type); + let repr_ptr = &*repr; + (0..contents.len()) + .map(|i| { + Load(bcx, adt::trans_field_ptr(bcx, repr_ptr, llarg, 0, i)) + }) + .collect() + } + _ => vec![llarg], } } - let inputs = intr.inputs.iter().map(|t| ty_to_type(ccx, t)).collect::<Vec<_>>(); - let outputs = ty_to_type(ccx, &intr.output); + + let mut any_flattened_aggregate = false; + let inputs = intr.inputs.iter() + .flat_map(|t| ty_to_type(ccx, t, &mut any_flattened_aggregate)) + .collect::<Vec<_>>(); + + let mut out_flattening = false; + let outputs = one(ty_to_type(ccx, &intr.output, &mut out_flattening)); + // outputting a flattened aggregate is nonsense + assert!(!out_flattening); + + let llargs = if !any_flattened_aggregate { + // no aggregates to flatten, so no change needed + llargs + } else { + // there are some aggregates that need to be flattened + // in the LLVM call, so we need to run over the types + // again to find them and extract the arguments + intr.inputs.iter() + .zip(&llargs) + .zip(&arg_tys) + .flat_map(|((t, llarg), ty)| flatten_aggregate(bcx, t, ty, *llarg)) + .collect() + }; + match intr.definition { intrinsics::IntrinsicDef::Named(name) => { let f = declare::declare_cfn(ccx, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 24b63f5d4f4..74a1926916b 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -507,5 +507,22 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( inner_expected, t_ty) } + Aggregate(_flatten, ref expected_contents) => { + match t.sty { + ty::TyTuple(ref contents) => { + if contents.len() != expected_contents.len() { + simple_error(&format!("tuple with length {}", contents.len()), + &format!("tuple with length {}", expected_contents.len())); + return + } + for (e, c) in expected_contents.iter().zip(contents) { + match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal, + e, c) + } + } + _ => simple_error(&format!("`{}`", t), + &format!("tuple")), + } + } } } |
