Сравнение без знака, которое возвращает -1,0,1 (cmpu), - это один из случаев, который проверяется GNU SuperOptimizer .
cmpu: compare (unsigned)
int cmpu(unsigned_word v0, unsigned_word v1)
{
return ( (v0 > v1) ? 1 : ( (v0 < v1) ? -1 : 0) );
}
SuperOptimizer исчерпывающе ищет в пространстве команд наилучшую возможную комбинацию команд, которая будет реализовывать данную функцию. Предполагается, что компиляторы автоматически заменяют функции, указанные выше, их супероптимизированными версиями (хотя не все компиляторы делают этот). Например, в Руководстве по написанию компилятора PowerPC ( powerpc-cwg.pdf ) функция cmpu показана в Приложении D на стр. 204:
cmpu: compare (unsigned)
PowerPC SuperOptimized Version
subf R5,R4,R3
subfc R6,R3,R4
subfe R7,R4,R3
subfe R8,R7,R5
Это довольно хорошо, не правда ли ... только четыре вычитания (и с переносом и / или расширенными версиями). Не говоря уже о том, что действительно не содержит ветвей на уровне кода операции машины . Вероятно, существует аналогичная последовательность ПК / Intel X86, которая также коротка, поскольку GNU Superoptimizer работает как для X86, так и для PowerPC.
Обратите внимание, что Сравнение без знака (cmpu) можно превратить в Сравнение со знаком (cmps) в 32-разрядном сравнении, добавив 0x80000000 к обоим входам со знаком перед передачей его в cmpu.
cmps: compare (signed)
int cmps(signed_word v0, signed_word v1)
{
signed_word offset=0x80000000;
return ( (unsigned_word) (v0 + signed_word),
(unsigned_word) (v1 + signed_word) );
}
Это всего лишь один из вариантов ... SuperOptimizer может найти cmps, который короче и не должен добавлять смещения, и вызвать cmpu.
Чтобы получить запрашиваемую вами версию, которая возвращает ваши значения {1,0,2}, а не {-1,0,1}, используйте следующий код, который использует функцию SuperOptimized cmps.
int Compare(int x, int y)
{
static const int retvals[]={1,0,2};
return (retvals[cmps(x,y)+1]);
}