|  | //! Emulate LLVM intrinsics | 
|  |  | 
|  | use crate::intrinsics::*; | 
|  | use crate::prelude::*; | 
|  |  | 
|  | pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( | 
|  | fx: &mut FunctionCx<'_, '_, 'tcx>, | 
|  | intrinsic: &str, | 
|  | args: &[Spanned<mir::Operand<'tcx>>], | 
|  | ret: CPlace<'tcx>, | 
|  | target: Option<BasicBlock>, | 
|  | span: Span, | 
|  | ) { | 
|  | if intrinsic.starts_with("llvm.aarch64") { | 
|  | return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(fx, intrinsic, args, ret, target); | 
|  | } | 
|  | if intrinsic.starts_with("llvm.x86") { | 
|  | return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, args, ret, target, span); | 
|  | } | 
|  |  | 
|  | match intrinsic { | 
|  | "llvm.prefetch" => { | 
|  | // Nothing to do. This is merely a perf hint. | 
|  | } | 
|  |  | 
|  | _ if intrinsic.starts_with("llvm.ctlz.v") => { | 
|  | intrinsic_args!(fx, args => (a); intrinsic); | 
|  |  | 
|  | simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { | 
|  | fx.bcx.ins().clz(lane) | 
|  | }); | 
|  | } | 
|  |  | 
|  | _ if intrinsic.starts_with("llvm.ctpop.v") => { | 
|  | intrinsic_args!(fx, args => (a); intrinsic); | 
|  |  | 
|  | simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { | 
|  | fx.bcx.ins().popcnt(lane) | 
|  | }); | 
|  | } | 
|  |  | 
|  | _ if intrinsic.starts_with("llvm.fma.v") => { | 
|  | intrinsic_args!(fx, args => (x,y,z); intrinsic); | 
|  |  | 
|  | simd_trio_for_each_lane( | 
|  | fx, | 
|  | x, | 
|  | y, | 
|  | z, | 
|  | ret, | 
|  | &|fx, _lane_ty, _res_lane_ty, lane_x, lane_y, lane_z| { | 
|  | fx.bcx.ins().fma(lane_x, lane_y, lane_z) | 
|  | }, | 
|  | ); | 
|  | } | 
|  |  | 
|  | "llvm.fptosi.sat.v4i32.v4f32" => { | 
|  | intrinsic_args!(fx, args => (a); intrinsic); | 
|  |  | 
|  | simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { | 
|  | fx.bcx.ins().fcvt_to_sint_sat(types::I32, lane) | 
|  | }); | 
|  | } | 
|  |  | 
|  | _ if intrinsic.starts_with("llvm.roundeven.v") => { | 
|  | intrinsic_args!(fx, args => (v); intrinsic); | 
|  |  | 
|  | simd_for_each_lane(fx, v, ret, &|fx, _lane_ty, _res_lane_ty, lane| { | 
|  | fx.bcx.ins().nearest(lane) | 
|  | }); | 
|  | } | 
|  |  | 
|  | _ => { | 
|  | fx.tcx | 
|  | .dcx() | 
|  | .warn(format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic)); | 
|  | let msg = format!( | 
|  | "{intrinsic} is not yet supported.\n\ | 
|  | See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ | 
|  | Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" | 
|  | ); | 
|  | crate::base::codegen_panic_nounwind(fx, &msg, span); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | let dest = target.expect("all llvm intrinsics used by stdlib should return"); | 
|  | let ret_block = fx.get_block(dest); | 
|  | fx.bcx.ins().jump(ret_block, &[]); | 
|  | } |