use rustc::ty::subst::SubstsRef;
-macro_rules! intrinsic_pat {
+macro intrinsic_pat {
(_) => {
_
- };
+ },
($name:ident) => {
stringify!($name)
+ },
+ ($name:literal) => {
+ stringify!($name)
+ },
+ ($x:ident . $($xs:tt).*) => {
+ concat!(stringify!($x), ".", intrinsic_pat!($($xs).*))
}
}
-macro_rules! intrinsic_arg {
+macro intrinsic_arg {
(o $fx:expr, $arg:ident) => {
$arg
- };
+ },
(c $fx:expr, $arg:ident) => {
trans_operand($fx, $arg)
- };
+ },
(v $fx:expr, $arg:ident) => {
trans_operand($fx, $arg).load_scalar($fx)
- };
+ }
}
-macro_rules! intrinsic_substs {
- ($substs:expr, $index:expr,) => {};
+macro intrinsic_substs {
+ ($substs:expr, $index:expr,) => {},
($substs:expr, $index:expr, $first:ident $(,$rest:ident)*) => {
let $first = $substs.type_at($index);
intrinsic_substs!($substs, $index+1, $($rest),*);
- };
+ }
}
-macro_rules! intrinsic_match {
- ($fx:expr, $intrinsic:expr, $substs:expr, $args:expr, $(
- $($name:tt)|+ $(if $cond:expr)?, $(<$($subst:ident),*>)? ($($a:ident $arg:ident),*) $content:block;
+pub macro intrinsic_match {
+ ($fx:expr, $intrinsic:expr, $substs:expr, $args:expr,
+ _ => $unknown:block;
+ $(
+ $($($name:tt).*)|+ $(if $cond:expr)?, $(<$($subst:ident),*>)? ($($a:ident $arg:ident),*) $content:block;
)*) => {
match $intrinsic {
$(
- $(intrinsic_pat!($name))|* $(if $cond)? => {
+ $(intrinsic_pat!($($name).*))|* $(if $cond)? => {
#[allow(unused_parens, non_snake_case)]
{
$(
}
}
)*
- _ => unimpl!("unsupported intrinsic {}", $intrinsic),
+ _ => $unknown,
}
- };
+ }
}
macro_rules! call_intrinsic_match {
};
}
-fn lane_type_and_count<'tcx>(
+pub fn lane_type_and_count<'tcx>(
fx: &FunctionCx<'_, 'tcx, impl Backend>,
layout: TyLayout<'tcx>,
intrinsic: &str,
intrinsic_match! {
fx, intrinsic, substs, args,
+ _ => {
+ unimpl!("unsupported intrinsic {}", intrinsic)
+ };
assume, (c _a) {};
likely | unlikely, (c a) {
args: &[mir::Operand<'tcx>],
destination: Option<(CPlace<'tcx>, BasicBlock)>,
) {
- fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
- crate::trap::trap_unimplemented(fx, intrinsic);
+ let ret = match destination {
+ Some((place, _)) => place,
+ None => {
+ // Insert non returning intrinsics here
+ match intrinsic {
+ "abort" => {
+ trap_panic(fx, "Called intrinsic::abort.");
+ }
+ "unreachable" => {
+ trap_unreachable(fx, "[corruption] Called intrinsic::unreachable.");
+ }
+ _ => unimplemented!("unsupported instrinsic {}", intrinsic),
+ }
+ return;
+ }
+ };
+
+ crate::intrinsics::intrinsic_match! {
+ fx, intrinsic, substs, args,
+ _ => {
+ fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
+ crate::trap::trap_unimplemented(fx, intrinsic);
+ };
+
+ // Used by _mm_movemask_epi8
+ llvm.x86.sse2.pmovmskb.128, (c a) {
+ let (lane_layout, lane_count) = crate::intrinsics::lane_type_and_count(fx, a.layout(), intrinsic);
+ assert_eq!(lane_layout.ty.sty, fx.tcx.types.i8.sty);
+ assert_eq!(lane_count, 16);
+
+ let mut res = fx.bcx.ins().iconst(types::I32, 0);
+
+ for lane in 0..16 {
+ let a_lane = a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
+ let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, 7); // extract sign bit of 8bit int
+ let a_lane_sign = fx.bcx.ins().uextend(types::I32, a_lane_sign);
+ res = fx.bcx.ins().ishl_imm(res, 1);
+ res = fx.bcx.ins().bor(res, a_lane_sign);
+ }
+
+ let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
+ ret.write_cvalue(fx, res);
+ };
+ }
if let Some((_, dest)) = destination {
let ret_ebb = fx.get_ebb(dest);
}
}
-// llvm.x86.sse2.pmovmskb.128
// llvm.x86.avx2.vperm2i128
// llvm.x86.ssse3.pshuf.b.128
// llvm.x86.avx2.pshuf.b