]> git.lizzy.rs Git - rust.git/commitdiff
trans: support simd_shuffle using MIR constants for indices.
authorEduard Burtescu <edy.burt@gmail.com>
Tue, 26 Apr 2016 20:54:38 +0000 (23:54 +0300)
committerEduard Burtescu <edy.burt@gmail.com>
Sat, 7 May 2016 16:14:33 +0000 (19:14 +0300)
src/librustc_trans/intrinsic.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/operand.rs
src/test/run-pass/simd-intrinsic-generic-elements.rs

index 1220fbafa29c9ddb6831538f0481affca251f4bb..1824055fcf94dd2369fff4711aad22f0ccd3d794 100644 (file)
@@ -1482,28 +1482,23 @@ macro_rules! require_simd {
 
         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
index d2e47a5f92bb462bd566048ef8d81da03cc16e5d..e605ef81c587f1cb60e6e1285de83719649bd10e 100644 (file)
@@ -26,6 +26,7 @@
 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 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 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 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     (&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);
index 9c1dfb0fc8d216efc156e725fd125c8ef18c4efb..0097bca2306ac1866e99c6d9774bd2a4b3831c2c 100644 (file)
 /// 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 @@ fn new(llval: ValueRef, ty: Ty<'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 @@ fn as_lvalue(&self) -> ConstLvalue<'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 @@ pub fn trans_constant(&mut self,
                 // 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 @@ pub fn trans_constant(&mut self,
             }
         };
 
-        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 @@ pub fn trans_constant(&mut self,
                           "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
         }
     }
 }
index c15d6cd5b2440929536cf4a4030a9ac8b74e705d..fc726a3474f7e6d996b506b08e1cf6306338ee3f 100644 (file)
@@ -140,7 +140,14 @@ pub fn trans_operand(&mut self,
             }
 
             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
+                }
             }
         }
     }
index ffb9e6072dfe3cd488a5dd85e557c2448c00aa89..5cb57b63ada2c24e50c8d60e971d783c1909ee91 100644 (file)
@@ -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);