@@ -20,6 +20,7 @@ use num::bigint::BigInt;
2020use rustc_middle:: ty:: { TyCtxt , VtblEntry } ;
2121use rustc_smir:: rustc_internal;
2222use rustc_target:: abi:: { FieldsShape , TagEncoding , Variants } ;
23+ use stable_mir:: abi:: { Primitive , Scalar , ValueAbi } ;
2324use stable_mir:: mir:: mono:: Instance ;
2425use stable_mir:: mir:: {
2526 AggregateKind , BinOp , CastKind , NullOp , Operand , Place , PointerCoercion , Rvalue , UnOp ,
@@ -32,9 +33,11 @@ impl<'tcx> GotocCtx<'tcx> {
3233 fn codegen_comparison ( & mut self , op : & BinOp , e1 : & Operand , e2 : & Operand ) -> Expr {
3334 let left_op = self . codegen_operand_stable ( e1) ;
3435 let right_op = self . codegen_operand_stable ( e2) ;
35- let is_float =
36- matches ! ( self . operand_ty_stable( e1) . kind( ) , TyKind :: RigidTy ( RigidTy :: Float ( ..) ) ) ;
37- comparison_expr ( op, left_op, right_op, is_float)
36+ let left_ty = self . operand_ty_stable ( e1) ;
37+ let right_ty = self . operand_ty_stable ( e2) ;
38+ let res_ty = op. ty ( left_ty, right_ty) ;
39+ let is_float = matches ! ( left_ty. kind( ) , TyKind :: RigidTy ( RigidTy :: Float ( ..) ) ) ;
40+ self . comparison_expr ( op, left_op, right_op, res_ty, is_float)
3841 }
3942
4043 /// This function codegen comparison for fat pointers.
@@ -72,16 +75,18 @@ impl<'tcx> GotocCtx<'tcx> {
7275 Expr :: statement_expression ( body, ret_type) . with_location ( loc)
7376 } else {
7477 // Compare data pointer.
78+ let res_ty = op. ty ( left_typ, right_typ) ;
7579 let left_ptr = self . codegen_operand_stable ( left_op) ;
7680 let left_data = left_ptr. clone ( ) . member ( "data" , & self . symbol_table ) ;
7781 let right_ptr = self . codegen_operand_stable ( right_op) ;
7882 let right_data = right_ptr. clone ( ) . member ( "data" , & self . symbol_table ) ;
79- let data_cmp = comparison_expr ( op, left_data. clone ( ) , right_data. clone ( ) , false ) ;
83+ let data_cmp =
84+ self . comparison_expr ( op, left_data. clone ( ) , right_data. clone ( ) , res_ty, false ) ;
8085
8186 // Compare the slice metadata (this logic could be adapted to compare vtable if needed).
8287 let left_len = left_ptr. member ( "len" , & self . symbol_table ) ;
8388 let right_len = right_ptr. member ( "len" , & self . symbol_table ) ;
84- let metadata_cmp = comparison_expr ( op, left_len, right_len, false ) ;
89+ let metadata_cmp = self . comparison_expr ( op, left_len, right_len, res_ty , false ) ;
8590
8691 // Join the results.
8792 // https://github.com/rust-lang/rust/pull/29781
@@ -93,10 +98,20 @@ impl<'tcx> GotocCtx<'tcx> {
9398 // If data is different, only compare data.
9499 // If data is equal, apply operator to metadata.
95100 BinOp :: Lt | BinOp :: Le | BinOp :: Ge | BinOp :: Gt => {
96- let data_eq =
97- comparison_expr ( & BinOp :: Eq , left_data. clone ( ) , right_data. clone ( ) , false ) ;
98- let data_strict_comp =
99- comparison_expr ( & get_strict_operator ( op) , left_data, right_data, false ) ;
101+ let data_eq = self . comparison_expr (
102+ & BinOp :: Eq ,
103+ left_data. clone ( ) ,
104+ right_data. clone ( ) ,
105+ res_ty,
106+ false ,
107+ ) ;
108+ let data_strict_comp = self . comparison_expr (
109+ & get_strict_operator ( op) ,
110+ left_data,
111+ right_data,
112+ res_ty,
113+ false ,
114+ ) ;
100115 data_strict_comp. or ( data_eq. and ( metadata_cmp) )
101116 }
102117 _ => unreachable ! ( "Unexpected operator {:?}" , op) ,
@@ -376,7 +391,7 @@ impl<'tcx> GotocCtx<'tcx> {
376391 BinOp :: BitXor | BinOp :: BitAnd | BinOp :: BitOr => {
377392 self . codegen_unchecked_scalar_binop ( op, e1, e2)
378393 }
379- BinOp :: Eq | BinOp :: Lt | BinOp :: Le | BinOp :: Ne | BinOp :: Ge | BinOp :: Gt => {
394+ BinOp :: Eq | BinOp :: Lt | BinOp :: Le | BinOp :: Ne | BinOp :: Ge | BinOp :: Gt | BinOp :: Cmp => {
380395 let op_ty = self . operand_ty_stable ( e1) ;
381396 if self . is_fat_pointer_stable ( op_ty) {
382397 self . codegen_comparison_fat_ptr ( op, e1, e2, loc)
@@ -681,7 +696,7 @@ impl<'tcx> GotocCtx<'tcx> {
681696 | CastKind :: FnPtrToPtr
682697 | CastKind :: PtrToPtr
683698 | CastKind :: PointerExposeAddress
684- | CastKind :: PointerFromExposedAddress ,
699+ | CastKind :: PointerWithExposedProvenance ,
685700 e,
686701 t,
687702 ) => self . codegen_misc_cast ( e, * t) ,
@@ -1260,7 +1275,7 @@ impl<'tcx> GotocCtx<'tcx> {
12601275 fn check_vtable_size ( & mut self , operand_type : Ty , vt_size : Expr ) -> Stmt {
12611276 // Check against the size we get from the layout from the what we
12621277 // get constructing a value of that type
1263- let ty: Type = self . codegen_ty_stable ( operand_type) ;
1278+ let ty = self . codegen_ty_stable ( operand_type) ;
12641279 let codegen_size = ty. sizeof ( & self . symbol_table ) ;
12651280 assert_eq ! ( vt_size. int_constant_value( ) . unwrap( ) , BigInt :: from( codegen_size) ) ;
12661281
@@ -1423,6 +1438,65 @@ impl<'tcx> GotocCtx<'tcx> {
14231438 }
14241439 }
14251440 }
1441+
1442+ fn comparison_expr (
1443+ & mut self ,
1444+ op : & BinOp ,
1445+ left : Expr ,
1446+ right : Expr ,
1447+ res_ty : Ty ,
1448+ is_float : bool ,
1449+ ) -> Expr {
1450+ match op {
1451+ BinOp :: Eq => {
1452+ if is_float {
1453+ left. feq ( right)
1454+ } else {
1455+ left. eq ( right)
1456+ }
1457+ }
1458+ BinOp :: Lt => left. lt ( right) ,
1459+ BinOp :: Le => left. le ( right) ,
1460+ BinOp :: Ne => {
1461+ if is_float {
1462+ left. fneq ( right)
1463+ } else {
1464+ left. neq ( right)
1465+ }
1466+ }
1467+ BinOp :: Ge => left. ge ( right) ,
1468+ BinOp :: Gt => left. gt ( right) ,
1469+ BinOp :: Cmp => {
1470+ // Implement https://doc.rust-lang.org/core/cmp/trait.Ord.html as done in cranelift,
1471+ // i.e., (left > right) - (left < right)
1472+ // Return value is the Ordering enumeration:
1473+ // ```
1474+ // #[repr(i8)]
1475+ // pub enum Ordering {
1476+ // Less = -1,
1477+ // Equal = 0,
1478+ // Greater = 1,
1479+ // }
1480+ // ```
1481+ let res_typ = self . codegen_ty_stable ( res_ty) ;
1482+ let ValueAbi :: Scalar ( Scalar :: Initialized { value, valid_range } ) =
1483+ res_ty. layout ( ) . unwrap ( ) . shape ( ) . abi
1484+ else {
1485+ unreachable ! ( "Unexpected layout" )
1486+ } ;
1487+ assert_eq ! ( valid_range. start, -1i8 as u8 as u128 ) ;
1488+ assert_eq ! ( valid_range. end, 1 ) ;
1489+ let Primitive :: Int { length, signed : true } = value else { unreachable ! ( ) } ;
1490+ let scalar_typ = Type :: signed_int ( length. bits ( ) ) ;
1491+ left. clone ( )
1492+ . gt ( right. clone ( ) )
1493+ . cast_to ( scalar_typ. clone ( ) )
1494+ . sub ( left. lt ( right) . cast_to ( scalar_typ) )
1495+ . transmute_to ( res_typ, & self . symbol_table )
1496+ }
1497+ _ => unreachable ! ( ) ,
1498+ }
1499+ }
14261500}
14271501
14281502/// Perform a wrapping subtraction of an Expr with a constant "expr - constant"
@@ -1445,30 +1519,6 @@ fn wrapping_sub(expr: &Expr, constant: u64) -> Expr {
14451519 }
14461520}
14471521
1448- fn comparison_expr ( op : & BinOp , left : Expr , right : Expr , is_float : bool ) -> Expr {
1449- match op {
1450- BinOp :: Eq => {
1451- if is_float {
1452- left. feq ( right)
1453- } else {
1454- left. eq ( right)
1455- }
1456- }
1457- BinOp :: Lt => left. lt ( right) ,
1458- BinOp :: Le => left. le ( right) ,
1459- BinOp :: Ne => {
1460- if is_float {
1461- left. fneq ( right)
1462- } else {
1463- left. neq ( right)
1464- }
1465- }
1466- BinOp :: Ge => left. ge ( right) ,
1467- BinOp :: Gt => left. gt ( right) ,
1468- _ => unreachable ! ( ) ,
1469- }
1470- }
1471-
14721522/// Remove the equality from an operator. Translates `<=` to `<` and `>=` to `>`
14731523fn get_strict_operator ( op : & BinOp ) -> BinOp {
14741524 match op {
0 commit comments