@@ -119,53 +119,32 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
119
119
}
120
120
}
121
121
122
- /// Floating point comparison operation
123
- ///
124
- /// <https://www.felixcloutier.com/x86/cmpss>
125
- /// <https://www.felixcloutier.com/x86/cmpps>
126
- /// <https://www.felixcloutier.com/x86/cmpsd>
127
- /// <https://www.felixcloutier.com/x86/cmppd>
128
- #[ derive( Copy , Clone ) ]
129
- enum FloatCmpOp {
130
- Eq ,
131
- Lt ,
132
- Le ,
133
- Unord ,
134
- Neq ,
135
- /// Not less-than
136
- Nlt ,
137
- /// Not less-or-equal
138
- Nle ,
139
- /// Ordered, i.e. neither of them is NaN
140
- Ord ,
141
- }
142
-
143
- impl FloatCmpOp {
144
- /// Convert from the `imm` argument used to specify the comparison
145
- /// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
146
- fn from_intrinsic_imm ( imm : i8 , intrinsic : & str ) -> InterpResult < ' _ , Self > {
147
- match imm {
148
- 0 => Ok ( Self :: Eq ) ,
149
- 1 => Ok ( Self :: Lt ) ,
150
- 2 => Ok ( Self :: Le ) ,
151
- 3 => Ok ( Self :: Unord ) ,
152
- 4 => Ok ( Self :: Neq ) ,
153
- 5 => Ok ( Self :: Nlt ) ,
154
- 6 => Ok ( Self :: Nle ) ,
155
- 7 => Ok ( Self :: Ord ) ,
156
- imm => {
157
- throw_unsup_format ! ( "invalid `imm` parameter of {intrinsic}: {imm}" ) ;
158
- }
159
- }
160
- }
161
- }
162
-
163
122
#[ derive( Copy , Clone ) ]
164
123
enum FloatBinOp {
165
124
/// Arithmetic operation
166
125
Arith ( mir:: BinOp ) ,
167
126
/// Comparison
168
- Cmp ( FloatCmpOp ) ,
127
+ ///
128
+ /// The semantics of this operator is a case distinction: we compare the two operands,
129
+ /// and then we return one of the four booleans `gt`, `lt`, `eq`, `unord` depending on
130
+ /// which class they fall into.
131
+ ///
132
+ /// AVX supports all 16 combinations, SSE only a subset
133
+ ///
134
+ /// <https://www.felixcloutier.com/x86/cmpss>
135
+ /// <https://www.felixcloutier.com/x86/cmpps>
136
+ /// <https://www.felixcloutier.com/x86/cmpsd>
137
+ /// <https://www.felixcloutier.com/x86/cmppd>
138
+ Cmp {
139
+ /// Result when lhs < rhs
140
+ gt : bool ,
141
+ /// Result when lhs > rhs
142
+ lt : bool ,
143
+ /// Result when lhs == rhs
144
+ eq : bool ,
145
+ /// Result when lhs is NaN or rhs is NaN
146
+ unord : bool ,
147
+ } ,
169
148
/// Minimum value (with SSE semantics)
170
149
///
171
150
/// <https://www.felixcloutier.com/x86/minss>
@@ -182,6 +161,44 @@ enum FloatBinOp {
182
161
Max ,
183
162
}
184
163
164
+ impl FloatBinOp {
165
+ /// Convert from the `imm` argument used to specify the comparison
166
+ /// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
167
+ fn cmp_from_imm ( imm : i8 , intrinsic : & str ) -> InterpResult < ' _ , Self > {
168
+ // Only bits 0..=4 are used, remaining should be zero.
169
+ if imm & !0b1_1111 != 0 {
170
+ throw_unsup_format ! ( "invalid `imm` parameter of {intrinsic}: 0x{imm:x}" ) ;
171
+ }
172
+ // Bit 4 specifies whether the operation is quiet or signaling, which
173
+ // we do not care in Miri.
174
+ // Bits 0..=2 specifies the operation.
175
+ // `gt` indicates the result to be returned when the LHS is strictly
176
+ // greater than the RHS, and so on.
177
+ let ( gt, lt, eq, unord) = match imm & 0b111 {
178
+ // Equal
179
+ 0x0 => ( false , false , true , false ) ,
180
+ // Less-than
181
+ 0x1 => ( false , true , false , false ) ,
182
+ // Less-or-equal
183
+ 0x2 => ( false , true , true , false ) ,
184
+ // Unordered (either is NaN)
185
+ 0x3 => ( false , false , false , true ) ,
186
+ // Not equal
187
+ 0x4 => ( true , true , false , true ) ,
188
+ // Not less-than
189
+ 0x5 => ( true , false , true , true ) ,
190
+ // Not less-or-equal
191
+ 0x6 => ( true , false , false , true ) ,
192
+ // Ordered (neither is NaN)
193
+ 0x7 => ( true , true , true , false ) ,
194
+ _ => unreachable ! ( ) ,
195
+ } ;
196
+ // When bit 3 is 1 (only possible in AVX), unord is toggled.
197
+ let unord = unord ^ ( imm & 0b1000 != 0 ) ;
198
+ Ok ( Self :: Cmp { gt, lt, eq, unord } )
199
+ }
200
+ }
201
+
185
202
/// Performs `which` scalar operation on `left` and `right` and returns
186
203
/// the result.
187
204
fn bin_op_float < ' tcx , F : rustc_apfloat:: Float > (
@@ -195,20 +212,15 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
195
212
let res = this. wrapping_binary_op ( which, left, right) ?;
196
213
Ok ( res. to_scalar ( ) )
197
214
}
198
- FloatBinOp :: Cmp ( which ) => {
215
+ FloatBinOp :: Cmp { gt , lt , eq , unord } => {
199
216
let left = left. to_scalar ( ) . to_float :: < F > ( ) ?;
200
217
let right = right. to_scalar ( ) . to_float :: < F > ( ) ?;
201
- // FIXME: Make sure that these operations match the semantics
202
- // of cmpps/cmpss/cmppd/cmpsd
203
- let res = match which {
204
- FloatCmpOp :: Eq => left == right,
205
- FloatCmpOp :: Lt => left < right,
206
- FloatCmpOp :: Le => left <= right,
207
- FloatCmpOp :: Unord => left. is_nan ( ) || right. is_nan ( ) ,
208
- FloatCmpOp :: Neq => left != right,
209
- FloatCmpOp :: Nlt => !( left < right) ,
210
- FloatCmpOp :: Nle => !( left <= right) ,
211
- FloatCmpOp :: Ord => !left. is_nan ( ) && !right. is_nan ( ) ,
218
+
219
+ let res = match left. partial_cmp ( & right) {
220
+ None => unord,
221
+ Some ( std:: cmp:: Ordering :: Less ) => lt,
222
+ Some ( std:: cmp:: Ordering :: Equal ) => eq,
223
+ Some ( std:: cmp:: Ordering :: Greater ) => gt,
212
224
} ;
213
225
Ok ( bool_to_simd_element ( res, Size :: from_bits ( F :: BITS ) ) )
214
226
}
0 commit comments