Как вы можете кодировать оператор C "&&" в x86? - PullRequest
4 голосов
/ 17 июля 2011

Как я могу кодировать оператор C '&&' в x86?Например:

int a = ...
int b = ...
int c = a && b;

Что будет эквивалентно последней строке в x86?

РЕДАКТИРОВАТЬ: я хочу сделать выше, без каких-либо переходов.g ++ генерирует это, но я не понимаю этого:

testl   %edi, %edi
setne   %dl
xorl    %eax, %eax
testl   %esi, %esi
setne   %al
andl    %edx, %eax

Ответы [ 4 ]

10 голосов
/ 17 июля 2011

Вот как GCC реализует это на -O3.

    movl    8(%esp), %edx  ;; load argument into edx
    xorl    %eax, %eax     ;; eax = 0
    movl    4(%esp), %ecx  ;; load other argument into ecx
    testl   %edx, %edx     ;; Is EDX nonzero?
    setne   %al            ;; al = 1 if Z = 0
    xorl    %edx, %edx     ;; EDX = 0
    testl   %ecx, %ecx     ;; Is ECX nonzero?
    setne   %dl            ;; dc = 1 if Z = 0
    andl    %edx, %eax     ;; edx &= eax

Обратите внимание, что этот код не закорачивается; это потому, что в этом случае GCC может доказать, что у второго аргумента нет побочных эффектов. Если у второго аргумента есть побочные эффекты, вы должны реализовать его с помощью переходов. Например:

int test(int *a, int *b) {
  return (*a)++ && (*b)++;
}

становится:

test:
        pushl   %ebx            ;; save ebx
        movl    8(%esp), %eax   ;; load a into eax
        movl    12(%esp), %ecx  ;; load b in to ecx
        movl    (%eax), %edx    ;; *a -> edx
        leal    1(%edx), %ebx   ;; ebx = edx + 1
        movl    %ebx, (%eax)    ;; *a <- ebx
        xorl    %eax, %eax      ;; eax = 0
        testl   %edx, %edx      ;; if the old value of *a was 0...
        je      .L2             ;; jump to the end
        movl    (%ecx), %eax    ;; *a -> eax
        testl   %eax, %eax      ;; does *a = 0?
        leal    1(%eax), %edx   ;; edx = *a + 1 (does not set flags!)
        setne   %al             ;; al = 1 if Z (ie, if a = 0 at the testl above)
        movl    %edx, (%ecx)    ;; save edx to *a (increment *a)
        movzbl  %al, %eax       ;; zero-extend al to eax
.L2:
        popl    %ebx            ;; restore ebx
        ret                     ;; return
3 голосов
/ 17 июля 2011

Вы не можете сделать это без скачков, потому что && является оператором короткого замыкания.

    XOR ecx, ecx
    MOV eax, <value of A>
    MOV ebx, <value of B>
    TEST eax, eax
    JZ testDone
    TEST ebx, ebx
    JZ testDone
    INC ecx
testDone:
    ...
0 голосов
/ 17 июля 2011

Вы правы, очевидная реализация использует ветки. Моя первоначальная идея состояла в том, чтобы преобразовать каждый операнд в 0 или -1 с помощью сдвига знака, расширяющего знак, а затем с помощью побитовой инструкции и инструкции, но gcc (1) напомнил мне о наборе xy x86 инструкция, так что кажется проще.

Следующая функция реализует: int f(int a, int b) { return a && b; }

.text
.globl f
f:
  cmpl   $0, 4(%esp)
  setne  %dl
  cmpl   $0, 8(%esp)
  setne  %al
  movzbl %al, %eax
  andl   %edx, %eax
  ret

Как оказалось, правильное значение для выражения можно вычислить без переходов или переходов, но, определяя мою реализацию как функцию, я обманываю, потому что она заставляет оба операнда вычисляться в чтобы выполнить вызов функции, после чего функция не наносит вреда, считывая оба операнда без короткого замыкания, поскольку известно, что параметры являются копиями.

Но для открытого кода то, можно ли это сделать без перехода, полностью зависит от того, можно ли вычислить правый операнд без побочных эффектов. Итак, это зависит от типа. Представьте себе случай, когда правым операндом является вызов функции, возможно, операция ввода-вывода или системный вызов ядра. Сгенерированный код не может оценить его вообще , если левый операнд имеет значение false, и я не вижу, как это можно сделать без перехода или перехода.

Интересно, что gcc -O (который генерирует подобный код), кажется, нарушает C99 6.5.13 (4), который категорически заявляет «Если первый операнд сравнивается равным 0, второй операнд не оценивается». В случае сборки f () он, очевидно, решает, что, поскольку у параметра значения не может быть побочных эффектов, компиляция кода не будет вредной, вопреки буквальной спецификации C99.

0 голосов
/ 17 июля 2011

Это будет работать (и является самым быстрым фрагментом кода) , только если a и b нормализованы, т. Е. Содержит логическое значение от 1 доОтметьте true или 0, чтобы отметить false.

MOV eax, <value>  ; a = ...
MOV ebx, <value>  ; b = ...
MOV ecx, eax
AND ecx, ebx      ; c = a & b
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...