Instruções condicionais em Thumb: IT blocks e execução condicional
No artigo anterior a gente viu o Thumb comprimindo instruções para 16 bits. Mas tem um detalhe que perdemos: no ARM, quase toda instrução é condicional (basta mudar os 4 bits do topo). No Thumb-1, poucas instruções aceitam condição — e o processador precisa de BLT, BGE etc. para decidir. O Thumb-2 resolve isso com os IT blocks (If-Then): permitem executar até 4 instruções condicionalmente, sem branch. É o que este texto explica — com bytes reais.
Por que execução condicional importa
Quando o processador encontra um BLT, ele precisa adivinhar se o desvio vai acontecer (branch prediction). Se errar, o pipeline é descarregado e 2–3 ciclos se perdem. Com execução condicional, o processador simplesmente não executa a instrução se a condição for falsa — sem branch, sem penalty, sem flush. É mais rápido e mais previsível.
Thumb-1: poucas condições
No Thumb-1, apenas algumas instruções têm formas condicionais: CMP, B (todos os desvios), MOV, ADD, SUB com registradores, e LSL/LSR/ASR. Para o resto, você precisa de um branch:
Oito instruções, 16 bytes. Dois branches (BLT e B) — cada um pode causar penalty se o predictor errar.
Thumb-2: os IT blocks
O IT (If-Then) é uma instrução de 16 bits que diz ao processador: "as próximas 1 a 4 instruções são condicionais". A máscara (bits 3..0) tem 4 bits e define quantas instruções seguem e quais são THEN/ELSE. Os padrões comuns são:
IT— 1 THEN.ITE— 1 THEN + 1 ELSE.ITT— 2 THEN.ITEE— 1 THEN + 2 ELSE.ITTE— 2 THEN + 1 ELSE.ITTT— 3 THEN.ITEEE— 1 THEN + 3 ELSE.ITEET— 1 THEN + 1 ELSE + 1 ELSE + 1 THEN.ITETT— 1 THEN + 1 ELSE + 2 THEN.ITTTE— 3 THEN + 1 ELSE.ITTTT— 4 THEN.
Nota:ITT, ITTT e ITTTT normalmente usam condição AL (sempre executar) — servem para converter código ARM para Thumb sem mudar a lógica, preservando a execução incondicional.
O mesmo exemplo com IT block (bytes reais, ARMv7-A):
Sete instruções, 18 bytes. Parece maior — mas não tem nenhum branch. O ITE instrui o processador a executar movlt se a condição for verdadeira, ou movge se for falsa, sem desvio. Em loops pequenos ou blocos condicionais críticos, isso elimina penalties de pipeline.
Decodificando o IT
ITE LT = 0xbfb4. Vamos bit a bit:
- O
firstcond(bits 7..4) é o código da condição do primeiro bloco (THEN). ParaLT, é1011.Tabela de Condições Código Condição 0000 EQ (Equal) 0001 NE (Not Equal) 0010 CS / HS (Carry Set / Unsigned Higher or Same) 0011 CC / LO (Carry Clear / Unsigned Lower) 0100 MI (Minus / Negative) 0101 PL (Plus / Positive or Zero) 0110 VS (Overflow) 0111 VC (No Overflow) 1000 HI (Unsigned Higher) 1001 LS (Unsigned Lower or Same) 1010 GE (Signed Greater than or Equal) 1011 LT (Signed Less Than) 1100 GT (Signed Greater Than) 1101 LE (Signed Less than or Equal) 1110 AL (Always / Unconditional) 1111 Reserved / Unpredictable - A máscara (bits 3..0) tem 4 bits e define quantas instruções seguem e quais são THEN/ELSE. O 1 menos significativo indica o fim da cadeia e e os bits anteriores indicam se a instrução é THEN (T) ou ELSE (E) baseado no bit menos significativo da
firstcond. Se o bit for igual a firstcond[0], então é THEN (T), caso contrário é ELSE (E). Por exemplo, paraITE LT:firstcond= LT =1011→ O bit menos significativo (firstcond[0]) é 1.- máscara =
0100→ bits 3..0 =0100. - O bit
1mais à direita está na posição do bit 2 (os bits são 3, 2, 1, 0). Ele atua exclusivamente como terminador, avisando a CPU que o bloco possui 2 instruções no total (a base + 1 extra). - O bit restante acima do terminador (o bit 3) dita a condição da segunda instrução. O valor dele é
0. - Como o bit 3 (
0) é diferente defirstcond[0](1), a segunda instrução recebe a condição oposta, ou seja, um ELSE (E).
ITE.Tabela de máscaras possíveis e como elas se traduzem em instruções THEN/ELSE dependendo do valor de firstcond[0] mask Terminador Qtd. de Instruções Se firstcond[0] == 0 Se firstcond[0] == 1 1000 Bit 3 1 IT IT 0100 Bit 2 2 ITT ITE 1100 Bit 2 2 ITE ITT 0010 Bit 1 3 ITTT ITEE 0110 Bit 1 3 ITTE ITET 1010 Bit 1 3 ITET ITTE 1110 Bit 1 3 ITEE ITTT 0001 Bit 0 4 ITTTT ITEEE 0011 Bit 0 4 ITTTE ITEET 0101 Bit 0 4 ITTET ITETE 0111 Bit 0 4 ITTEE ITETT 1001 Bit 0 4 ITETT ITTEE 1011 Bit 0 4 ITETE ITTET 1101 Bit 0 4 ITEET ITTTE 1111 Bit 0 4 ITEEE ITTTT - O assembler automaticamente inverte a condição para ELSE — por isso
ITE LTgeraMOVLTeMOVGE(GE = NOT LT).
Importante: as condições nos mnemônicos (MOVLT, MOVGE) são apenas documentação para o programador. O que realmente define a condição é a instrução IT — o processador lê a máscara do IT e aplica as condições automaticamente. Se você escrever MOVLT fora de um bloco IT, o assembler vai reclamar: sem o IT, não existe execução condicional em Thumb.
Quando usar IT vs branches
- IT: blocos curtos (1–4 instruções), condições simples, quando a previsibilidade é crítica (tempo real, DSP).
- Branches: blocos longos (>4 instruções), quando o predictor tem boa acurácia, ou quando o código é mais legível com labels.
Glossário: instruções e comandos
| Instrução / Comando | O que faz |
|---|---|
IT {cond} | Inicia bloco de 1 instrução condicional. |
ITE {cond} | Inicia bloco: 1 THEN + 1 ELSE. |
MOV{cond} Rd, #imm | Movimentação condicional (dentro de IT). |
-march=armv7-a -mthumb | Monta Thumb-2 com IT blocks. |
arm-none-eabi-objdump -d | Mostra os bytes IT + instruções condicionais. |
O que o arm-jitter faz com isso
Quando o arm-box executa com --arch=thumb2, o arm-jitter decoda o IT e registra quais instruções seguintes são condicionais. Para cada uma, ele verifica o CPSR antes de executar — se a condição for falsa, a instrução é pulada (como um NOP invisível). É a mesma semântica do hardware: sem branch, sem penalty, só execução condicional.
Próximo passo
Com ARM, Thumb, Thumb-2 e IT blocks no arsenal, o próximo texto pode explorar AArch64 (o modo de 64 bits do ARM, suportado pelo arm-box com --arch=aarch64) ou semihosting e syscalls (como o arm-box traduz chamadas de sistema EABI para o host). Até lá, tente montar um ITE com 3 instruções ELSE e conte os bytes — a codificação da máscara vai fazer sentido.