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
–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;