|
1 | 1 | use rustc_middle::mir;
|
| 2 | +use rustc_span::Symbol; |
2 | 3 | use rustc_target::abi::Size;
|
| 4 | +use rustc_target::spec::abi::Abi; |
3 | 5 |
|
4 | 6 | use crate::*;
|
5 | 7 | use helpers::bool_to_simd_element;
|
| 8 | +use shims::foreign_items::EmulateByNameResult; |
6 | 9 |
|
7 |
| -pub(super) mod sse; |
8 |
| -pub(super) mod sse2; |
| 10 | +mod sse; |
| 11 | +mod sse2; |
| 12 | + |
| 13 | +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} |
| 14 | +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: |
| 15 | + crate::MiriInterpCxExt<'mir, 'tcx> |
| 16 | +{ |
| 17 | + fn emulate_x86_intrinsic( |
| 18 | + &mut self, |
| 19 | + link_name: Symbol, |
| 20 | + abi: Abi, |
| 21 | + args: &[OpTy<'tcx, Provenance>], |
| 22 | + dest: &PlaceTy<'tcx, Provenance>, |
| 23 | + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { |
| 24 | + let this = self.eval_context_mut(); |
| 25 | + // Prefix should have already been checked. |
| 26 | + let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); |
| 27 | + match unprefixed_name { |
| 28 | + // Used to implement the `_addcarry_u32` and `_addcarry_u64` functions. |
| 29 | + // Computes a + b with input and output carry. The input carry is an 8-bit |
| 30 | + // value, which is interpreted as 1 if it is non-zero. The output carry is |
| 31 | + // an 8-bit value that will be 0 or 1. |
| 32 | + // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html |
| 33 | + "addcarry.32" | "addcarry.64" => { |
| 34 | + if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" { |
| 35 | + return Ok(EmulateByNameResult::NotSupported); |
| 36 | + } |
| 37 | + |
| 38 | + let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; |
| 39 | + let c_in = this.read_scalar(c_in)?.to_u8()? != 0; |
| 40 | + let a = this.read_immediate(a)?; |
| 41 | + let b = this.read_immediate(b)?; |
| 42 | + |
| 43 | + let (sum, overflow1) = this.overflowing_binary_op(mir::BinOp::Add, &a, &b)?; |
| 44 | + let (sum, overflow2) = this.overflowing_binary_op( |
| 45 | + mir::BinOp::Add, |
| 46 | + &sum, |
| 47 | + &ImmTy::from_uint(c_in, a.layout), |
| 48 | + )?; |
| 49 | + let c_out = overflow1 | overflow2; |
| 50 | + |
| 51 | + this.write_scalar(Scalar::from_u8(c_out.into()), &this.project_field(dest, 0)?)?; |
| 52 | + this.write_immediate(*sum, &this.project_field(dest, 1)?)?; |
| 53 | + } |
| 54 | + // Used to implement the `_subborrow_u32` and `_subborrow_u64` functions. |
| 55 | + // Computes a - b with input and output borrow. The input borrow is an 8-bit |
| 56 | + // value, which is interpreted as 1 if it is non-zero. The output borrow is |
| 57 | + // an 8-bit value that will be 0 or 1. |
| 58 | + // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html |
| 59 | + "subborrow.32" | "subborrow.64" => { |
| 60 | + if unprefixed_name == "subborrow.64" && this.tcx.sess.target.arch != "x86_64" { |
| 61 | + return Ok(EmulateByNameResult::NotSupported); |
| 62 | + } |
| 63 | + |
| 64 | + let [b_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; |
| 65 | + let b_in = this.read_scalar(b_in)?.to_u8()? != 0; |
| 66 | + let a = this.read_immediate(a)?; |
| 67 | + let b = this.read_immediate(b)?; |
| 68 | + |
| 69 | + let (sub, overflow1) = this.overflowing_binary_op(mir::BinOp::Sub, &a, &b)?; |
| 70 | + let (sub, overflow2) = this.overflowing_binary_op( |
| 71 | + mir::BinOp::Sub, |
| 72 | + &sub, |
| 73 | + &ImmTy::from_uint(b_in, a.layout), |
| 74 | + )?; |
| 75 | + let b_out = overflow1 | overflow2; |
| 76 | + |
| 77 | + this.write_scalar(Scalar::from_u8(b_out.into()), &this.project_field(dest, 0)?)?; |
| 78 | + this.write_immediate(*sub, &this.project_field(dest, 1)?)?; |
| 79 | + } |
| 80 | + |
| 81 | + name if name.starts_with("sse.") => { |
| 82 | + return sse::EvalContextExt::emulate_x86_sse_intrinsic( |
| 83 | + this, link_name, abi, args, dest, |
| 84 | + ); |
| 85 | + } |
| 86 | + name if name.starts_with("sse2.") => { |
| 87 | + return sse2::EvalContextExt::emulate_x86_sse2_intrinsic( |
| 88 | + this, link_name, abi, args, dest, |
| 89 | + ); |
| 90 | + } |
| 91 | + _ => return Ok(EmulateByNameResult::NotSupported), |
| 92 | + } |
| 93 | + Ok(EmulateByNameResult::NeedsJumping) |
| 94 | + } |
| 95 | +} |
9 | 96 |
|
10 | 97 | /// Floating point comparison operation
|
11 | 98 | ///
|
|
0 commit comments