From 5c42e694cb7eb2bc26336351a1fb4e1e4f94768e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 26 Apr 2016 23:54:38 +0300 Subject: [PATCH] trans: support simd_shuffle using MIR constants for indices. --- src/librustc_trans/intrinsic.rs | 15 +++----- src/librustc_trans/mir/block.rs | 34 +++++++++++++----- src/librustc_trans/mir/constant.rs | 35 +++++++------------ src/librustc_trans/mir/operand.rs | 9 ++++- .../simd-intrinsic-generic-elements.rs | 3 +- 5 files changed, 51 insertions(+), 45 deletions(-) diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 1220fbafa29c..1824055fcf94 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -1482,28 +1482,23 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> let total_len = in_len as u64 * 2; - let (vector, indirect) = match args { + let vector = match args { Some(args) => { match consts::const_expr(bcx.ccx(), &args[2], substs, None, // this should probably help simd error reporting consts::TrueConst::Yes) { - Ok((vector, _)) => (vector, false), + Ok((vector, _)) => vector, Err(err) => bcx.sess().span_fatal(span, &err.description()), } } - None => (llargs[2], !type_is_immediate(bcx.ccx(), arg_tys[2])) + None => llargs[2] }; let indices: Option> = (0..n) .map(|i| { let arg_idx = i; - let val = if indirect { - Load(bcx, StructGEP(bcx, vector, i)) - } else { - const_get_elt(vector, &[i as libc::c_uint]) - }; - let c = const_to_opt_uint(val); - match c { + let val = const_get_elt(vector, &[i as libc::c_uint]); + match const_to_opt_uint(val) { None => { emit_error!("shuffle index #{} is not a constant", arg_idx); None diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index d2e47a5f92bb..e605ef81c587 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -26,6 +26,7 @@ use glue; use type_::Type; use super::{MirContext, TempRef, drop}; +use super::constant::Const; use super::lvalue::{LvalueRef, load_fat_ptr}; use super::operand::OperandRef; use super::operand::OperandValue::{self, FatPtr, Immediate, Ref}; @@ -114,16 +115,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let discr = bcx.with_block(|bcx| base::to_immediate(bcx, discr, switch_ty)); let switch = bcx.switch(discr, self.llblock(*otherwise), values.len()); for (value, target) in values.iter().zip(targets) { - let constant = mir::Constant { - literal: mir::Literal::Value { - value: value.clone() - }, - ty: switch_ty, - span: terminator.span - }; - let val = self.trans_constant(&bcx, &constant).immediate(); + let val = Const::from_constval(bcx.ccx(), value.clone(), switch_ty); let llbb = self.llblock(*target); - build::AddCase(switch, val, llbb) + build::AddCase(switch, val.llval, llbb) } } @@ -247,8 +241,30 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (&args[..], None) }; + let is_shuffle = intrinsic.map_or(false, |name| { + name.starts_with("simd_shuffle") + }); let mut idx = 0; for arg in first_args { + // The indices passed to simd_shuffle* in the + // third argument must be constant. This is + // checked by const-qualification, which also + // promotes any complex rvalues to constants. + if is_shuffle && idx == 2 { + match *arg { + mir::Operand::Consume(_) => { + span_bug!(terminator.span, + "shuffle indices must be constant"); + } + mir::Operand::Constant(ref constant) => { + let val = self.trans_constant(&bcx, constant); + llargs.push(val.llval); + idx += 1; + continue; + } + } + } + let val = self.trans_operand(&bcx, arg).val; self.trans_argument(&bcx, val, &mut llargs, &fn_ty, &mut idx, &mut callee.data); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 9c1dfb0fc8d2..0097bca2306a 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -41,13 +41,13 @@ use super::MirContext; /// The LLVM type might not be the same for a single Rust type, /// e.g. each enum variant would have its own LLVM struct type. #[derive(Copy, Clone)] -struct Const<'tcx> { - llval: ValueRef, - ty: Ty<'tcx> +pub struct Const<'tcx> { + pub llval: ValueRef, + pub ty: Ty<'tcx> } impl<'tcx> Const<'tcx> { - fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> { Const { llval: llval, ty: ty @@ -55,10 +55,10 @@ impl<'tcx> Const<'tcx> { } /// Translate ConstVal into a LLVM constant value. - fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>, - cv: ConstVal, - ty: Ty<'tcx>) - -> Const<'tcx> { + pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>, + cv: ConstVal, + ty: Ty<'tcx>) + -> Const<'tcx> { let llty = type_of::type_of(ccx, ty); let val = match cv { ConstVal::Float(v) => C_floating_f64(v, llty), @@ -110,7 +110,7 @@ impl<'tcx> Const<'tcx> { } } - fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> { + pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> { let llty = type_of::immediate_type_of(ccx, self.ty); let llvalty = val_ty(self.llval); @@ -799,7 +799,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_constant(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, constant: &mir::Constant<'tcx>) - -> OperandRef<'tcx> + -> Const<'tcx> { let ty = bcx.monomorphize(&constant.ty); let result = match constant.literal.clone() { @@ -808,10 +808,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // types, which would not work with MirConstContext. if common::type_is_zero_size(bcx.ccx(), ty) { let llty = type_of::type_of(bcx.ccx(), ty); - return OperandRef { - val: OperandValue::Immediate(C_null(llty)), - ty: ty - }; + return Const::new(C_null(llty), ty); } let substs = bcx.tcx().mk_substs(bcx.monomorphize(substs)); @@ -827,7 +824,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } }; - let val = match result { + match result { Ok(v) => v, Err(ConstEvalFailure::Compiletime(_)) => { // We've errored, so we don't have to produce working code. @@ -839,14 +836,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { "MIR constant {:?} results in runtime panic: {}", constant, err.description()) } - }; - - let operand = val.to_operand(bcx.ccx()); - if let OperandValue::Ref(ptr) = operand.val { - // If this is a OperandValue::Ref to an immediate constant, load it. - self.trans_load(bcx, ptr, operand.ty) - } else { - operand } } } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index c15d6cd5b244..fc726a3474f7 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -140,7 +140,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Operand::Constant(ref constant) => { - self.trans_constant(bcx, constant) + let val = self.trans_constant(bcx, constant); + let operand = val.to_operand(bcx.ccx()); + if let OperandValue::Ref(ptr) = operand.val { + // If this is a OperandValue::Ref to an immediate constant, load it. + self.trans_load(bcx, ptr, operand.ty) + } else { + operand + } } } } diff --git a/src/test/run-pass/simd-intrinsic-generic-elements.rs b/src/test/run-pass/simd-intrinsic-generic-elements.rs index ffb9e6072dfe..5cb57b63ada2 100644 --- a/src/test/run-pass/simd-intrinsic-generic-elements.rs +++ b/src/test/run-pass/simd-intrinsic-generic-elements.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_simd, rustc_attrs, platform_intrinsics)] +#![feature(repr_simd, platform_intrinsics)] // ignore-pretty : (#23623) problems when ending with // comments @@ -52,7 +52,6 @@ macro_rules! all_eq { }} } -#[rustc_no_mir] // FIXME #27840 MIR doesn't handle shuffle constants. fn main() { let x2 = i32x2(20, 21); let x3 = i32x3(30, 31, 32);