Representing `<=>` in IR

Over in Micro-optimize Ord::cmp for primitives by saethlin · Pull Request #105840 · rust-lang/rust · GitHub we’ve been looking at the best way to represent Ord::cmp, aka C++20’s <=>.

We’re currently doing (a < b) ? -1 : (a == b) ? 0 : 1, https://rust.godbolt.org/z/vjv7EfEqe

Clang C++20 appears to do (a == b) ? 0 : (a < b) ? -1 : 1, https://cpp.godbolt.org/z/6xnfrYjYT

Is there a particular form that’d be best for this, IR-optimization-wise? Is there a good way I could have intuition for which? Should we just copy Clang and assume that’ll get the most attention?

(They also produce substantially-different x86 assembly, but that’s solvable with additional backend matching.)

They are both the same 4 instructions in my ISA–given a reason pattern matcher
as a code generator.

      CMP     Rt,Ra,Rb
      SLA      Rr,Rt,<1:LT>
      SLL      Rt,Rt,<1:GT>
      OR       Rr,Rr,Rt

only 1 of the LT and GT flags are set in CMP
SLA gives a result of {-1,0}
SLL gives a result of {0,1}
OR whacks the results together

An ISA with signed and unsigned integer SET instructions could do this in 3 instructions

     SETALT     Rt,Ra,Rb
     SETUGT   Rd,Ra,Rb
     OR            Rt,Rt,Rd

Don’t think it matters much: but both of these imbodiments prefer it written in the form::

      ( a < b ) | ( a > b )

As it gives ISAs with easy means to {-1,0} and {0,+1} SETs a more direct path to the result.

Which does not work :zipper_mouth_face:–so, any of the following can be used::

 (a < b) ? -1 : (a == b) ? 0 : 1;

 (a == b) ? 0 : (a < b) ? -1 : 1;

 (a < b) ? -1 : (a > b) ? 1 : 0;

 (a > b) ? 1 : (a < b) ? -1 : 0;