@@ -35,63 +35,65 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
3535 // Prefix should have already been checked.
3636 let unprefixed_name = link_name. as_str ( ) . strip_prefix ( "llvm.x86." ) . unwrap ( ) ;
3737 match unprefixed_name {
38- // Used to implement the `_addcarry_u32` and `_addcarry_u64` functions.
39- // Computes a + b with input and output carry. The input carry is an 8-bit
40- // value, which is interpreted as 1 if it is non-zero. The output carry is
41- // an 8-bit value that will be 0 or 1.
38+ // Used to implement the `_addcarry_u{32, 64}` and the `_subborrow_u{32, 64}` functions.
39+ // Computes a + b or a - b with input and output carry/borrow. The input carry/borrow is an 8-bit
40+ // value, which is interpreted as 1 if it is non-zero. The output carry/borrow is an 8-bit value that will be 0 or 1.
4241 // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html
43- "addcarry.32" | "addcarry.64" => {
44- if unprefixed_name == "addcarry.64" && this. tcx . sess . target . arch != "x86_64" {
42+ // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html
43+ "addcarry.32" | "addcarry.64" | "subborrow.32" | "subborrow.64" => {
44+ if unprefixed_name. ends_with ( "64" ) && this. tcx . sess . target . arch != "x86_64" {
4545 return Ok ( EmulateItemResult :: NotSupported ) ;
4646 }
4747
48- let [ c_in, a, b] = this. check_shim ( abi, Abi :: Unadjusted , link_name, args) ?;
49- let c_in = this. read_scalar ( c_in) ?. to_u8 ( ) ? != 0 ;
48+ let op = if unprefixed_name. starts_with ( "add" ) {
49+ mir:: BinOp :: AddWithOverflow
50+ } else {
51+ mir:: BinOp :: SubWithOverflow
52+ } ;
53+
54+ let [ cb_in, a, b] = this. check_shim ( abi, Abi :: Unadjusted , link_name, args) ?;
55+ let cb_in = this. read_scalar ( cb_in) ?. to_u8 ( ) ? != 0 ;
5056 let a = this. read_immediate ( a) ?;
5157 let b = this. read_immediate ( b) ?;
5258
53- let ( sum, overflow1) =
54- this. binary_op ( mir:: BinOp :: AddWithOverflow , & a, & b) ?. to_pair ( this) ;
55- let ( sum, overflow2) = this
56- . binary_op (
57- mir:: BinOp :: AddWithOverflow ,
58- & sum,
59- & ImmTy :: from_uint ( c_in, a. layout ) ,
60- ) ?
61- . to_pair ( this) ;
62- let c_out = overflow1. to_scalar ( ) . to_bool ( ) ? | overflow2. to_scalar ( ) . to_bool ( ) ?;
59+ let ( sum, overflow1) = this. binary_op ( op, & a, & b) ?. to_pair ( this) ;
60+ let ( sum, overflow2) =
61+ this. binary_op ( op, & sum, & ImmTy :: from_uint ( cb_in, a. layout ) ) ?. to_pair ( this) ;
62+ let cb_out = overflow1. to_scalar ( ) . to_bool ( ) ? | overflow2. to_scalar ( ) . to_bool ( ) ?;
6363
64- this. write_scalar ( Scalar :: from_u8 ( c_out. into ( ) ) , & this. project_field ( dest, 0 ) ?) ?;
65- this. write_immediate ( * sum, & this. project_field ( dest, 1 ) ?) ?;
64+ let d1 = this. project_field ( dest, 0 ) ?;
65+ let d2 = this. project_field ( dest, 1 ) ?;
66+ write_twice ( this, & d1, Scalar :: from_u8 ( cb_out. into ( ) ) , & d2, sum) ?;
6667 }
67- // Used to implement the `_subborrow_u32` and `_subborrow_u64` functions.
68- // Computes a - b with input and output borrow. The input borrow is an 8-bit
69- // value, which is interpreted as 1 if it is non-zero. The output borrow is
70- // an 8-bit value that will be 0 or 1.
71- // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html
72- "subborrow.32" | "subborrow.64" => {
73- if unprefixed_name == "subborrow.64" && this. tcx . sess . target . arch != "x86_64" {
68+
69+ // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions,
70+ // except for a slightly different type signature and the requirement for the "adx" target feature.
71+ // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarryx-u32-addcarryx-u64.html
72+ "addcarryx.u32" | "addcarryx.u64" => {
73+ this. expect_target_feature_for_intrinsic ( link_name, "adx" ) ?;
74+
75+ if unprefixed_name. ends_with ( "64" ) && this. tcx . sess . target . arch != "x86_64" {
7476 return Ok ( EmulateItemResult :: NotSupported ) ;
7577 }
7678
77- let [ b_in , a, b] = this. check_shim ( abi, Abi :: Unadjusted , link_name, args) ?;
78- let b_in = this. read_scalar ( b_in ) ?. to_u8 ( ) ? != 0 ;
79+ let [ c_in , a, b, out ] = this. check_shim ( abi, Abi :: Unadjusted , link_name, args) ?;
80+ let c_in = this. read_scalar ( c_in ) ?. to_u8 ( ) ? != 0 ;
7981 let a = this. read_immediate ( a) ?;
8082 let b = this. read_immediate ( b) ?;
8183
82- let ( sub , overflow1) =
83- this. binary_op ( mir:: BinOp :: SubWithOverflow , & a, & b) ?. to_pair ( this) ;
84- let ( sub , overflow2) = this
84+ let ( sum , overflow1) =
85+ this. binary_op ( mir:: BinOp :: AddWithOverflow , & a, & b) ?. to_pair ( this) ;
86+ let ( sum , overflow2) = this
8587 . binary_op (
86- mir:: BinOp :: SubWithOverflow ,
87- & sub ,
88- & ImmTy :: from_uint ( b_in , a. layout ) ,
88+ mir:: BinOp :: AddWithOverflow ,
89+ & sum ,
90+ & ImmTy :: from_uint ( c_in , a. layout ) ,
8991 ) ?
9092 . to_pair ( this) ;
91- let b_out = overflow1. to_scalar ( ) . to_bool ( ) ? | overflow2. to_scalar ( ) . to_bool ( ) ?;
93+ let c_out = overflow1. to_scalar ( ) . to_bool ( ) ? | overflow2. to_scalar ( ) . to_bool ( ) ?;
9294
93- this . write_scalar ( Scalar :: from_u8 ( b_out . into ( ) ) , & this. project_field ( dest , 0 ) ? ) ?;
94- this. write_immediate ( * sub , & this . project_field ( dest , 1 ) ? ) ?;
95+ let out = this. deref_pointer_as ( out , sum . layout ) ?;
96+ write_twice ( this, dest , Scalar :: from_u8 ( c_out . into ( ) ) , & out , sum ) ?;
9597 }
9698
9799 // Used to implement the `_mm_pause` function.
@@ -1366,3 +1368,16 @@ fn psign<'tcx>(
13661368
13671369 Ok ( ( ) )
13681370}
1371+
1372+ /// Write two values `v1` and `v2` to the places `d1` and `d2`.
1373+ fn write_twice < ' tcx > (
1374+ this : & mut crate :: MiriInterpCx < ' tcx > ,
1375+ d1 : & MPlaceTy < ' tcx > ,
1376+ v1 : Scalar ,
1377+ d2 : & MPlaceTy < ' tcx > ,
1378+ v2 : ImmTy < ' tcx > ,
1379+ ) -> InterpResult < ' tcx , ( ) > {
1380+ this. write_scalar ( v1, d1) ?;
1381+ this. write_immediate ( * v2, d2) ?;
1382+ Ok ( ( ) )
1383+ }
0 commit comments