about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-04-26 23:54:38 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-05-07 19:14:33 +0300
commit5c42e694cb7eb2bc26336351a1fb4e1e4f94768e (patch)
treecbf0d26ca40728ddc7200e38f6b7ba87a91e34f8
parented66fe48e94df2cd0dee5af4afa44d7fb50cb0cf (diff)
downloadrust-5c42e694cb7eb2bc26336351a1fb4e1e4f94768e.tar.gz
rust-5c42e694cb7eb2bc26336351a1fb4e1e4f94768e.zip
trans: support simd_shuffle using MIR constants for indices.
-rw-r--r--src/librustc_trans/intrinsic.rs15
-rw-r--r--src/librustc_trans/mir/block.rs34
-rw-r--r--src/librustc_trans/mir/constant.rs35
-rw-r--r--src/librustc_trans/mir/operand.rs9
-rw-r--r--src/test/run-pass/simd-intrinsic-generic-elements.rs3
5 files changed, 51 insertions, 45 deletions
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 1220fbafa29..1824055fcf9 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<Vec<_>> = (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 d2e47a5f92b..e605ef81c58 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 9c1dfb0fc8d..0097bca2306 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 c15d6cd5b24..fc726a3474f 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 ffb9e6072df..5cb57b63ada 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);