@@ -20,6 +20,7 @@ use num::bigint::BigInt;
20
20
use rustc_middle:: ty:: { TyCtxt , VtblEntry } ;
21
21
use rustc_smir:: rustc_internal;
22
22
use rustc_target:: abi:: { FieldsShape , TagEncoding , Variants } ;
23
+ use stable_mir:: abi:: { Primitive , Scalar , ValueAbi } ;
23
24
use stable_mir:: mir:: mono:: Instance ;
24
25
use stable_mir:: mir:: {
25
26
AggregateKind , BinOp , CastKind , NullOp , Operand , Place , PointerCoercion , Rvalue , UnOp ,
@@ -32,9 +33,11 @@ impl<'tcx> GotocCtx<'tcx> {
32
33
fn codegen_comparison ( & mut self , op : & BinOp , e1 : & Operand , e2 : & Operand ) -> Expr {
33
34
let left_op = self . codegen_operand_stable ( e1) ;
34
35
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)
38
41
}
39
42
40
43
/// This function codegen comparison for fat pointers.
@@ -72,16 +75,18 @@ impl<'tcx> GotocCtx<'tcx> {
72
75
Expr :: statement_expression ( body, ret_type) . with_location ( loc)
73
76
} else {
74
77
// Compare data pointer.
78
+ let res_ty = op. ty ( left_typ, right_typ) ;
75
79
let left_ptr = self . codegen_operand_stable ( left_op) ;
76
80
let left_data = left_ptr. clone ( ) . member ( "data" , & self . symbol_table ) ;
77
81
let right_ptr = self . codegen_operand_stable ( right_op) ;
78
82
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 ) ;
80
85
81
86
// Compare the slice metadata (this logic could be adapted to compare vtable if needed).
82
87
let left_len = left_ptr. member ( "len" , & self . symbol_table ) ;
83
88
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 ) ;
85
90
86
91
// Join the results.
87
92
// https://github.com/rust-lang/rust/pull/29781
@@ -93,10 +98,20 @@ impl<'tcx> GotocCtx<'tcx> {
93
98
// If data is different, only compare data.
94
99
// If data is equal, apply operator to metadata.
95
100
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
+ ) ;
100
115
data_strict_comp. or ( data_eq. and ( metadata_cmp) )
101
116
}
102
117
_ => unreachable ! ( "Unexpected operator {:?}" , op) ,
@@ -376,7 +391,7 @@ impl<'tcx> GotocCtx<'tcx> {
376
391
BinOp :: BitXor | BinOp :: BitAnd | BinOp :: BitOr => {
377
392
self . codegen_unchecked_scalar_binop ( op, e1, e2)
378
393
}
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 => {
380
395
let op_ty = self . operand_ty_stable ( e1) ;
381
396
if self . is_fat_pointer_stable ( op_ty) {
382
397
self . codegen_comparison_fat_ptr ( op, e1, e2, loc)
@@ -681,7 +696,7 @@ impl<'tcx> GotocCtx<'tcx> {
681
696
| CastKind :: FnPtrToPtr
682
697
| CastKind :: PtrToPtr
683
698
| CastKind :: PointerExposeAddress
684
- | CastKind :: PointerFromExposedAddress ,
699
+ | CastKind :: PointerWithExposedProvenance ,
685
700
e,
686
701
t,
687
702
) => self . codegen_misc_cast ( e, * t) ,
@@ -1260,7 +1275,7 @@ impl<'tcx> GotocCtx<'tcx> {
1260
1275
fn check_vtable_size ( & mut self , operand_type : Ty , vt_size : Expr ) -> Stmt {
1261
1276
// Check against the size we get from the layout from the what we
1262
1277
// 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) ;
1264
1279
let codegen_size = ty. sizeof ( & self . symbol_table ) ;
1265
1280
assert_eq ! ( vt_size. int_constant_value( ) . unwrap( ) , BigInt :: from( codegen_size) ) ;
1266
1281
@@ -1423,6 +1438,65 @@ impl<'tcx> GotocCtx<'tcx> {
1423
1438
}
1424
1439
}
1425
1440
}
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
+ }
1426
1500
}
1427
1501
1428
1502
/// Perform a wrapping subtraction of an Expr with a constant "expr - constant"
@@ -1445,30 +1519,6 @@ fn wrapping_sub(expr: &Expr, constant: u64) -> Expr {
1445
1519
}
1446
1520
}
1447
1521
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
-
1472
1522
/// Remove the equality from an operator. Translates `<=` to `<` and `>=` to `>`
1473
1523
fn get_strict_operator ( op : & BinOp ) -> BinOp {
1474
1524
match op {
0 commit comments