NOP instruction after branch on ARMv7 Cortex M3

I'm interested, why for Cortex M3 microcontroller (stm32f103) compiler sometimes generates a NOP instruction after branch. And why it sometimes doesn't.

For example:

0x08000496 2400      MOVS     r4,#0x00
0x08000498 4625      MOV      r5,r4
0x0800049A E006      B        0x080004AA
64: res=res+a[i];
65: }
0x0800049C F85A0034  LDR      r0,[r10,r4,LSL #3] // No NOP after B
0x080004AA 1BA0      SUBS     r0,r4,r6
0x080004AC EB750007  SBCS     r0,r5,r7
0x080004B0 DBF4      BLT      0x0800049C
66: int64_t avg=res/x;
0x080004B2 BF00      NOP      // <------------------- NOP after BLT
69: int v=countbits1(5);
0x080004B4 2005      MOVS     r0,#0x05
0x080004B6 F7FFFFA2  BL.W     countbits1 (0x080003FE)
0x080004BA 9001      STR      r0,[sp,#0x04]     // No NOP after BL.W
73:
0x080004BC 2005      MOVS     r0,#0x05


My initial guess was that long instruction needs word-alignment but BL.W after NOP actually doesn't have it. If this NOP is related to pipeline somehow than why there are branches without nop's after them?

I'm confused.

UPDATE:

It turns out that branch may be not relevant at all. I tried to moving declaration of unused local variable int64_t avg - and NOP moved along with it. So I beleive pjc50 comment is right and this NOP is there just to let debugger put a breakpoint on this line.

• Try moving the int64_t line of C up or down a bit. The first two are clearly part of a for loop; but line 66 has generated no code at all. My guess is that the NOP is for the benefit of the debugger so that every line of C generates at least one instruction. – pjc50 Oct 28 '14 at 23:45
• @pjc50 now that's interesting! This NOP is indeed connected with int64_t avg; moving line 66 moved the NOP. But if I change type of avg to int32_t there is no NOP. This local variable is, actually, unused, so compiler doesn't generate any code at all for it.. Apart from this NOP for 64-bit type. If I change type I can still put a breakpoint on that line (and it will be on the MOVS). Very interesting. – Amomum Oct 29 '14 at 0:24
• Any ideas why 64-bit variable is honored with a NOP? – Amomum Oct 29 '14 at 0:26
• ARM and LinkedIn both have great forums for this sort of question - you could try there. I have a couple of comments to add: sometimes both outcomes of a branch are fetched and depending on the result of the branch, one alternative gets NOPed out. Also, the Cortex M3 may choose not to run NOPs, an interesting point if you are using them for short delays. I hope those comments are relevant. – Ant Nov 4 '14 at 13:08
• Since this is mostly a compiler question that has little to do with EE... you may have better luck asking it on SO. – Fizz Jan 7 '15 at 18:27

Try moving the int64_t line of C up or down a bit. The first two are clearly part of a for loop; but line 66 has generated no code at all. My guess is that the NOP is for the benefit of the debugger so that every line of C generates at least one instruction.

(Not all debuggers do this on all platforms; Visual Studio will simply move your breakpoint to the nearest line that has code associated with it.)

• You are right, moving declaration of the variable moved the NOP instruction; branch instruction turned out to be irrelevant. – Amomum Jan 22 '15 at 11:03

Lots (most? all?) compilers end up putting NOP instructions after some (but not other) jump/branch type instructions.

When the compiler sees a "jump" type instruction, it has two different instructions that can do the job. One is relative, one is absolute.

One is a relative jump, and one is an absolute jump. The relative jump is quicker, and specifies a jump relative to the current instruction - the address to jump to is a single byte, so it can jump forward 128 bytes, or backwards 127 bytes.