| //! 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.p0" => { | |
| // 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, &[]); | |
| } |