Compilação para Assembly de Mecanismos de Repetição e Decisão

Suponha que as variáveis (int) a, b, c e d estão alocadas respectivamente nos registradores eax, ebx, ecx e edx. Como programar estruturas como:

if (a==b) c=d;
d=a+c;
ou
while (a<=b) {
  ...
  a++;
}
d=a+c;
?

A forma natural de execução do programa é a sequencial, ou seja, a CPU automaticamente busca instruções na memória em endereços sequenciais. Instruções de desvio de assembly servem para "quebrar" a execução sequencial, fazendo com que, sob certas condições, deixe de valer a regra que diz que sempre a próxima instrução a ser executada é a próxima fisicamente na memória.

Existem instruções de desvio condicional e incondicional. No Pentium os desvios são chamados jump, em algumas outras máquinas são chamadas de branch.

Um exemplo de jump condicional é a instrução:

      jle label

Observe que a condição do jump se refere ao resultado da instrução anterior. Em outras máquinas, a própria instrução de desvio contém os operandos a serem comparados. No Pentium, diversas instruções registram características de seus resultados nos flags, e os desvios condicionais operam sobre os valores dos flags. Por exemplo, podemos escrever

      cmp %eax, %ebx
      jle depois
Nesse caso, se o valor de ebx for menor ou igual que o de eax (observe a "inversão" dos operandos), o controle é desviado para o endereço indicado pelo label depois. Para programar o if acima, poderíamos escrever:
        cmpl %eax, %ebx
        jne depois_if
        movl %edx, %ecx
depois_if: 
        movl %eax, %edx
        addl %ecx, %edx

atenção: Observe que a condição de desvio é a negativa da condição do if!!

Existem muitas outras instruções de desvio condicional (ver manual), como je, jg, jge, jecxz, etc. Um exemplo de desvio incondicional é a instrução:

        jmp depois

que faz com que o controle seja desviado para o endereço indicado pelo label depois, independentemente de qualquer condição.

Para implementar uma estrutura if ... else ... é necessário utilizar um desvio condicional e um incondicional! Tente fazê-lo!

Para programar o while acima, poderíamos escrever:

loop:   cmpl %ebx, %eax
        jgt depois
        ...
        incl %eax
        jmp loop                  ; desvia para teste
depois: movl %eax, %edx
        addl %ecx, %edx

e se for um do..while?

Nos exemplos acima, as condições eram sempre condições simples, que podiam ser testadas com uma instrução de comparação. Muitas vezes, temos expressões mais complexas, envolvendo and e or.

A maior parte das linguagens de programação atuais utilizam o que se chama de curto circuito: a avaliação de uma expressão lógica é interrompida assim que o resultado é conhecido. Por exemplo, em uma expressão com and, se o resultado da primeira parte é falso, não se avalia a segunda. Por outro lado, em um or, se o resultado da primeira parte é verdadeiro, também não se avalia a segunda.

Como exemplo, supondo mais uma vez que as variáveis a, b, c e d estão alocadas nos registradores eax, ebx, ecx e edx, o código C:

if ((a==b)||(c<d)) {
  a = c;
}
c = d;
pode ser implementado por:
      cmpl %ebx, %eax
      je l1
      cmpl %edx, %ecx
      lge l2
l1:   movl %eax, %ecx
l2:   movl %ecx, %edx 
Referência