@@ -35,63 +35,49 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
35
35
// Prefix should have already been checked.
36
36
let unprefixed_name = link_name. as_str ( ) . strip_prefix ( "llvm.x86." ) . unwrap ( ) ;
37
37
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.
42
41
// 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" {
45
45
return Ok ( EmulateItemResult :: NotSupported ) ;
46
46
}
47
47
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 ;
50
- let a = this. read_immediate ( a) ?;
51
- let b = this. read_immediate ( b) ?;
52
-
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 ( ) ?;
63
-
64
- this. write_scalar ( Scalar :: from_u8 ( c_out. into ( ) ) , & this. project_field ( dest, 0 ) ?) ?;
48
+ let [ cb_in, a, b] = this. check_shim ( abi, Abi :: Unadjusted , link_name, args) ?;
49
+
50
+ let op = if unprefixed_name. starts_with ( "add" ) {
51
+ mir:: BinOp :: AddWithOverflow
52
+ } else {
53
+ mir:: BinOp :: SubWithOverflow
54
+ } ;
55
+
56
+ let ( sum, cb_out) = carrying_add ( this, cb_in, a, b, op) ?;
57
+ this. write_scalar ( cb_out, & this. project_field ( dest, 0 ) ?) ?;
65
58
this. write_immediate ( * sum, & this. project_field ( dest, 1 ) ?) ?;
66
59
}
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" {
60
+
61
+ // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions,
62
+ // except for a slightly different type signature and the requirement for the "adx" target feature.
63
+ // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarryx-u32-addcarryx-u64.html
64
+ "addcarryx.u32" | "addcarryx.u64" => {
65
+ this. expect_target_feature_for_intrinsic ( link_name, "adx" ) ?;
66
+
67
+ let is_u64 = unprefixed_name. ends_with ( "64" ) ;
68
+ if is_u64 && this. tcx . sess . target . arch != "x86_64" {
74
69
return Ok ( EmulateItemResult :: NotSupported ) ;
75
70
}
76
71
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 a = this. read_immediate ( a) ?;
80
- let b = this. read_immediate ( b) ?;
81
-
82
- let ( sub, overflow1) =
83
- this. binary_op ( mir:: BinOp :: SubWithOverflow , & a, & b) ?. to_pair ( this) ;
84
- let ( sub, overflow2) = this
85
- . binary_op (
86
- mir:: BinOp :: SubWithOverflow ,
87
- & sub,
88
- & ImmTy :: from_uint ( b_in, a. layout ) ,
89
- ) ?
90
- . to_pair ( this) ;
91
- let b_out = overflow1. to_scalar ( ) . to_bool ( ) ? | overflow2. to_scalar ( ) . to_bool ( ) ?;
92
-
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 ) ?) ?;
72
+ let [ c_in, a, b, out] = this. check_shim ( abi, Abi :: Unadjusted , link_name, args) ?;
73
+ let out = this. deref_pointer_as (
74
+ out,
75
+ if is_u64 { this. machine . layouts . u64 } else { this. machine . layouts . u32 } ,
76
+ ) ?;
77
+
78
+ let ( sum, c_out) = carrying_add ( this, c_in, a, b, mir:: BinOp :: AddWithOverflow ) ?;
79
+ this. write_scalar ( c_out, dest) ?;
80
+ this. write_immediate ( * sum, & out) ?;
95
81
}
96
82
97
83
// Used to implement the `_mm_pause` function.
@@ -1359,3 +1345,27 @@ fn psign<'tcx>(
1359
1345
1360
1346
Ok ( ( ) )
1361
1347
}
1348
+
1349
+ /// Calcultates either `a + b + cb_in` or `a - b - cb_in` depending on the value
1350
+ /// of `op` and returns both the sum and the overflow bit. `op` is expected to be
1351
+ /// either one of `mir::BinOp::AddWithOverflow` and `mir::BinOp::SubWithOverflow`.
1352
+ fn carrying_add < ' tcx > (
1353
+ this : & mut crate :: MiriInterpCx < ' tcx > ,
1354
+ cb_in : & OpTy < ' tcx > ,
1355
+ a : & OpTy < ' tcx > ,
1356
+ b : & OpTy < ' tcx > ,
1357
+ op : mir:: BinOp ,
1358
+ ) -> InterpResult < ' tcx , ( ImmTy < ' tcx > , Scalar ) > {
1359
+ assert ! ( op == mir:: BinOp :: AddWithOverflow || op == mir:: BinOp :: SubWithOverflow ) ;
1360
+
1361
+ let cb_in = this. read_scalar ( cb_in) ?. to_u8 ( ) ? != 0 ;
1362
+ let a = this. read_immediate ( a) ?;
1363
+ let b = this. read_immediate ( b) ?;
1364
+
1365
+ let ( sum, overflow1) = this. binary_op ( op, & a, & b) ?. to_pair ( this) ;
1366
+ let ( sum, overflow2) =
1367
+ this. binary_op ( op, & sum, & ImmTy :: from_uint ( cb_in, a. layout ) ) ?. to_pair ( this) ;
1368
+ let cb_out = overflow1. to_scalar ( ) . to_bool ( ) ? | overflow2. to_scalar ( ) . to_bool ( ) ?;
1369
+
1370
+ Ok ( ( sum, Scalar :: from_u8 ( cb_out. into ( ) ) ) )
1371
+ }
0 commit comments