@@ -40,13 +40,33 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
4040 } )
4141}
4242
43+ fn codegen_three_way_compare < ' tcx > (
44+ fx : & mut FunctionCx < ' _ , ' _ , ' tcx > ,
45+ signed : bool ,
46+ lhs : Value ,
47+ rhs : Value ,
48+ ) -> CValue < ' tcx > {
49+ // This emits `(lhs > rhs) - (lhs < rhs)`, which is cranelift's preferred form per
50+ // <https://github.com/bytecodealliance/wasmtime/blob/8052bb9e3b792503b225f2a5b2ba3bc023bff462/cranelift/codegen/src/prelude_opt.isle#L41-L47>
51+ let gt_cc = crate :: num:: bin_op_to_intcc ( BinOp :: Gt , signed) . unwrap ( ) ;
52+ let lt_cc = crate :: num:: bin_op_to_intcc ( BinOp :: Lt , signed) . unwrap ( ) ;
53+ let gt = fx. bcx . ins ( ) . icmp ( gt_cc, lhs, rhs) ;
54+ let lt = fx. bcx . ins ( ) . icmp ( lt_cc, lhs, rhs) ;
55+ let val = fx. bcx . ins ( ) . isub ( gt, lt) ;
56+ CValue :: by_val ( val, fx. layout_of ( fx. tcx . ty_ordering_enum ( Some ( fx. mir . span ) ) ) )
57+ }
58+
4359fn codegen_compare_bin_op < ' tcx > (
4460 fx : & mut FunctionCx < ' _ , ' _ , ' tcx > ,
4561 bin_op : BinOp ,
4662 signed : bool ,
4763 lhs : Value ,
4864 rhs : Value ,
4965) -> CValue < ' tcx > {
66+ if bin_op == BinOp :: Cmp {
67+ return codegen_three_way_compare ( fx, signed, lhs, rhs) ;
68+ }
69+
5070 let intcc = crate :: num:: bin_op_to_intcc ( bin_op, signed) . unwrap ( ) ;
5171 let val = fx. bcx . ins ( ) . icmp ( intcc, lhs, rhs) ;
5272 CValue :: by_val ( val, fx. layout_of ( fx. tcx . types . bool ) )
@@ -59,7 +79,7 @@ pub(crate) fn codegen_binop<'tcx>(
5979 in_rhs : CValue < ' tcx > ,
6080) -> CValue < ' tcx > {
6181 match bin_op {
62- BinOp :: Eq | BinOp :: Lt | BinOp :: Le | BinOp :: Ne | BinOp :: Ge | BinOp :: Gt => {
82+ BinOp :: Eq | BinOp :: Lt | BinOp :: Le | BinOp :: Ne | BinOp :: Ge | BinOp :: Gt | BinOp :: Cmp => {
6383 match in_lhs. layout ( ) . ty . kind ( ) {
6484 ty:: Bool | ty:: Uint ( _) | ty:: Int ( _) | ty:: Char => {
6585 let signed = type_sign ( in_lhs. layout ( ) . ty ) ;
@@ -160,7 +180,7 @@ pub(crate) fn codegen_int_binop<'tcx>(
160180 }
161181 BinOp :: Offset => unreachable ! ( "Offset is not an integer operation" ) ,
162182 // Compare binops handles by `codegen_binop`.
163- BinOp :: Eq | BinOp :: Ne | BinOp :: Lt | BinOp :: Le | BinOp :: Gt | BinOp :: Ge => {
183+ BinOp :: Eq | BinOp :: Ne | BinOp :: Lt | BinOp :: Le | BinOp :: Gt | BinOp :: Ge | BinOp :: Cmp => {
164184 unreachable ! ( "{:?}({:?}, {:?})" , bin_op, in_lhs. layout( ) . ty, in_rhs. layout( ) . ty) ;
165185 }
166186 } ;
0 commit comments