@@ -119,53 +119,32 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
119119 }
120120}
121121
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-
163122#[ derive( Copy , Clone ) ]
164123enum FloatBinOp {
165124 /// Arithmetic operation
166125 Arith ( mir:: BinOp ) ,
167126 /// 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+ } ,
169148 /// Minimum value (with SSE semantics)
170149 ///
171150 /// <https://www.felixcloutier.com/x86/minss>
@@ -182,6 +161,44 @@ enum FloatBinOp {
182161 Max ,
183162}
184163
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+
185202/// Performs `which` scalar operation on `left` and `right` and returns
186203/// the result.
187204fn bin_op_float < ' tcx , F : rustc_apfloat:: Float > (
@@ -195,20 +212,15 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
195212 let res = this. wrapping_binary_op ( which, left, right) ?;
196213 Ok ( res. to_scalar ( ) )
197214 }
198- FloatBinOp :: Cmp ( which ) => {
215+ FloatBinOp :: Cmp { gt , lt , eq , unord } => {
199216 let left = left. to_scalar ( ) . to_float :: < F > ( ) ?;
200217 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,
212224 } ;
213225 Ok ( bool_to_simd_element ( res, Size :: from_bits ( F :: BITS ) ) )
214226 }
0 commit comments