From 2558bf2f6bd5e74861d7db760f689b3b01bcc618 Mon Sep 17 00:00:00 2001
From: bjorn3 <bjorn3@users.noreply.github.com>
Date: Fri, 16 Aug 2019 16:04:50 +0200
Subject: [PATCH] Workaround for missing `#[rustc_args_required_const(..)]`
 support

cc #666
---
 example/std_example.rs | 16 ++++++++++++++++
 src/constant.rs        | 15 ++++++---------
 src/intrinsics.rs      | 12 +++++++++++-
 3 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/example/std_example.rs b/example/std_example.rs
index 7819881b69b..61182a49b9c 100644
--- a/example/std_example.rs
+++ b/example/std_example.rs
@@ -75,6 +75,9 @@ unsafe fn test_simd() {
     test_mm_cvtepi8_epi16();
     test_mm_cvtsi128_si64();
 
+    // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support
+    //test_mm_extract_epi8();
+
     let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
     assert_eq!(mask1, 1);
 }
@@ -194,6 +197,19 @@ unsafe fn test_mm_cvtepi8_epi16() {
     assert_eq_m128i(r, e);
 }
 
+#[target_feature(enable = "sse4.1")]
+unsafe fn test_mm_extract_epi8() {
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        -1, 1, 2, 3, 4, 5, 6, 7,
+        8, 9, 10, 11, 12, 13, 14, 15
+    );
+    let r1 = _mm_extract_epi8(a, 0);
+    let r2 = _mm_extract_epi8(a, 19);
+    assert_eq!(r1, 0xFF);
+    assert_eq!(r2, 3);
+}
+
 #[derive(PartialEq)]
 enum LoopState {
     Continue(()),
diff --git a/src/constant.rs b/src/constant.rs
index a71a8d0bf2c..23f550050e4 100644
--- a/src/constant.rs
+++ b/src/constant.rs
@@ -439,22 +439,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for TransPlaceInterpreter {
 pub fn mir_operand_get_const_val<'tcx>(
     fx: &FunctionCx<'_, 'tcx, impl Backend>,
     operand: &Operand<'tcx>,
-) -> Result<&'tcx Const<'tcx>, String> {
+) -> Option<&'tcx Const<'tcx>> {
     let place = match operand {
-        Operand::Copy(place) => place,
-        Operand::Constant(const_) => return Ok(force_eval_const(fx, const_.literal)),
-        _ => return Err(format!("{:?}", operand)),
+        Operand::Copy(place) | Operand::Move(place) => place,
+        Operand::Constant(const_) => return Some(force_eval_const(fx, const_.literal)),
     };
 
     assert!(place.projection.is_none());
     let static_ = match &place.base {
-        PlaceBase::Static(static_) => {
-            static_
-        }
-        PlaceBase::Local(_) => return Err("local".to_string()),
+        PlaceBase::Static(static_) => static_,
+        PlaceBase::Local(_) => return None,
     };
 
-    Ok(match &static_.kind {
+    Some(match &static_.kind {
         StaticKind::Static(_) => unimplemented!(),
         StaticKind::Promoted(promoted) => {
             fx.tcx.const_eval(ParamEnv::reveal_all().and(GlobalId {
diff --git a/src/intrinsics.rs b/src/intrinsics.rs
index 8b4d5962856..bd78271057c 100644
--- a/src/intrinsics.rs
+++ b/src/intrinsics.rs
@@ -951,7 +951,17 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
         };
 
         simd_extract, (c v, o idx) {
-            let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_extract* idx not const");
+            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
+                idx_const
+            } else {
+                fx.tcx.sess.span_warn(
+                    fx.mir.span,
+                    "`#[rustc_arg_required_const(..)]` is not yet supported. Calling this function will panic.",
+                );
+                crate::trap::trap_panic(fx, "`#[rustc_arg_required_const(..)]` is not yet supported.");
+                return;
+            };
+
             let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const));
             let (_lane_type, lane_count) = lane_type_and_count(fx, v.layout(), intrinsic);
             if idx >= lane_count.into() {