Search code examples
assemblyarmstm32thumb

Questions about IT conditional codes in assembly


Most examples have IT commands such as the following,

ITTE   NE        ; IT can be omitted
ANDNE  r0,r0,r1  ; 16-bit AND, not ANDS
ADDSNE r2,r2,#1  ; 32-bit ADDS (16-bit ADDS does not set flags in IT block)
MOVEQ  r2,r3     ; 16-bit MOV

ITT    AL        ; emit 2 non-flag setting 16-bit instructions
ADDAL  r0,r0,r1  ; 16-bit ADD, not ADDS
SUBAL  r2,r2,#1  ; 16-bit SUB, not SUB
ADD    r0,r0,r1  ; expands into 32-bit ADD, and is not in IT block

ITT    EQ        
MOVEQ  r0,r1
BEQ    dloop     ; branch at end of IT block is permitted

ITT    EQ
MOVEQ  r0,r1
BKPT   #1        ; BKPT always executes
ADDEQ  r0,r0,#1   

I want to look at for example the last IT block in the examples. Im really confused what is happening. For MOVEQ, I thought it was checking if r0 = r1, and moving r1 into r0 if they were equal. But that doesn't make sense if they are equal. What is really going on?

I wrote a thumb code that checks which number is greater:

cmp r0, r1
ITE HS
movhs r0, r0
movlo r0, r1

Here I needed to compare registers before the IT block... But why do all the examples not include a comparison atleast before hand? Would there been another way to write an IT block for my example that doesn't include a comparison? What's really going on in these examples?


Solution

  • Flags are an input to predicated instructions inside an IT block. Yes, you do put a cmp or adds or whatever other flag-setting instruction at some point before an it. It doesn't have to be right before.

    The examples you show exist to document corner cases for IT, not full/complete examples of using it to actually do something specific.

    The documentation for a conditional branch instruction doesn't typically show flag-setting instructions either.


    According to ARM's docs

    With the exception of CMP, CMN, and TST, the 16-bit instructions that normally affect the condition code flags, do not affect them when used inside an IT block.

    But one of the examples does clearly show that you can change flags with a 32-bit adds inside an IT block, and this tells us that regular compare/test instructions are allowed.

    The docs don't make it clear that changes to flags within an IT block have an effect on later predicated instructions inside the block. @DanLewis's answer confirms that they do.

    In ARM mode, no IT block is needed to predicate execution (4 bits in every instruction encode a predicate) so flag-setting instructions obviously affect later instructions. It makes sense that it works the same way in Thumb mode, especially since IT is optional in some syntaxes. (Some assemblers will insert it for you in unified syntax if assembling for thumb mode.)