8

I am working on an ARM Cortex-M3 controller which has the Thumb-2 instruction set.

Thumb mode is used to compress the instruction to a 16-bit size. So size of code is reduced. But with normal Thumb mode, why is it said that performance is reduced?

In case of Thumb-2, it is said performance is improved as per these two links:

Improve performance in cases where a single 16-bit instruction restricts functions available to the compiler.

A stated aim for Thumb-2 was to achieve code density similar to Thumb with performance similar to the ARM instruction set on 32-bit memory.

What exactly is this performance? Can someone give a few examples related to it?

artless noise
  • 21,212
  • 6
  • 68
  • 105
Katoch
  • 2,709
  • 9
  • 51
  • 84
  • 1
    Performance is always relative. There are many cases where `thumb` code runs better than `arm`. Mainly if the memory bus is a bottle neck. Generally the `thumb` doesn't have as many registers, so even though the instruction set is more compact, with some algorithms, it will have to access memory more often to spill registers. – artless noise Apr 06 '13 at 04:01
  • 1
    If I have a delivery truck A and a delivery truck B that is half the size of A. If the amount of stuff being delivered fits in truck A but is two big for truck B it will take truck B twice as many trips to do the same job. Thumb is not half as efficient as ARM, it is more like 10-15% more instructions to do the same thing as ARM. – old_timer Apr 06 '13 at 04:08
  • See also: Stackoverflow's [Gcc -mthumb vs -marm](http://stackoverflow.com/questions/11062936/gcc-mthumb-against-marm), and [Arizona paper](http://www.cs.arizona.edu/~arvind/papers/lctes02.pdf) on Thumb and ARM guided compiles. – artless noise Apr 06 '13 at 04:11

3 Answers3

11

When compared against the ARM 32 bit instruction set, the thumb 16 bit instruction set (not talking about thumb2 extensions yet) takes less space because the instructions are half the size, but there is a performance drop, in general, because it takes more instructions to do the same thing as on arm. There are less features to the instruction set, and most instructions only operate on registers r0-r7. Apples to Apples comparison more instructions to do the same thing is slower.

Now thumb2 extensions take formerly undefined thumb instructions and create 32 bit thumb instructions. Understand that there is more than one set of thumb2 extensions. ARMv6m adds a couple dozen perhaps. ARMv7m adds something like 150 instructions to the thumb instruction set, I dont know what ARMv8 or the future hold. So assuming ARMv7m, they have bridged the gap between what you can do in thumb and what you can do in ARM. So thumb2 is a reduced ARM instruction set as thumb is, but not as reduced. So it might still take more instructions to do the same thing in thumb2 (assume plus thumb) compared to ARM doing the same thing.

This gives a taste of the issue, a single instruction in arm and its equivalent in thumb.

ARM

and r8,r9,r10

THUMB

push {r0,r1}
mov r0,r8
mov r1,r9
and r0,r1
mov r1,r10
and r0,r1
mov r8,r0
pop {r0,r1}

Now a compiler wouldnt do that, the compiler would know it is targeting thumb and do things differently by choosing other registers. You still have fewer registers and fewer features per instruction:

mov r0,r1
and r0,r2

Still takes two instructions/execution cycles to and two registers together, without modifying the operands, and put the result in a third register. Thumb2 has a three register and so you are back to a single instruction using the thumb2 extensions. And that thumb2 instruction allows for r0-r15 on any of those three registers where thumb is limited to r0-r7.

Look at the ARMv5 Architectural Reference Manual, under each thumb instruction it shows you the equivalent ARM instruction. Then go to that ARM instruction and compare what you can do with that arm instruction that you cant do with the thumb instruction. It is a one way path the thumb instructions (not thumb2) have a one to one relationship with an ARM instruction. all thumb instructions have an equivalent arm instruction. but not all arm instructions have an equivalent thumb instruction. You should be able to see from this exercise the limitation on the compilers when using the thumb instruction set. Then get the ARMv7m Architectural Reference Manual and look at the instruction set, and compare the "all thumb variants" encodings (the ones that include ARMv4T) and the ones that are limited to ARMv6 and/or v7 and see the expansion of features between thumb and thumb2 as well as the thumb2 only instructions that have no thumb counterpart. This should clarify what the compilers have to work with between thumb and thumb2. You can then go so far as to compare thumb+thumb2 with the full blown ARM instructions (ARMv7 AR is that what it is called?). And see that thumb2 gets a lot closer to ARM, but you lose for example conditionals on every instruction, so conditional execution in thumb becomes comparisons with branching over code, where in ARM you can sometimes have an if-then-else without branching...

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • also be very careful, cortex-m3 and cortex-m4 are ARMv7m, the cortex-m0 and -m1 are ARMv6m, a lot of difference between the thumb2 extensions on those instruction sets,also the compilers lept forward with the cortex-m3 and added a bunch of thumb2 stuff, and you couldnt use thumb2 on the cortex-m0 when it came out. Not sure if the compilers (gcc/clang) have caught up yet completely. Likewise the cortex-m4 has (can have) floating point which is a reduced flavor of the Cortex-A,and the compilers were struggling with floating point on the cortex-m4 when it came out. not sure if they have caught up – old_timer Apr 06 '13 at 04:05
  • if thumb can access only register R0-R7 ... then how in your example you are using mov instruction on register r8, r9 & r10 ... please suggest ? – Katoch Apr 06 '13 at 07:21
  • *MOST* thumb instructions a few can in particular a specific move high to/from low – old_timer Apr 06 '13 at 11:22
  • I wish the assembler had defined a suffix which meant "use the form that affects flags if more convenient than the one that doesn't" and a suffix which meant "don't use the form that affects flags; refuse assembly if the only available form does affect flags", since in Thumb some instructions must affect flags, others can't, and some grant a choice; worse, some instructions behave differently depending upon the registers used. – supercat Jan 21 '15 at 17:42
8

Thumb-2 introduced variable length instructions to the original Thumb; now instructions can be a mixture of 16-bit and 32-bit. That means you retain the size advantage of the original Thumb in everyday code, but now have access to almost the full ARM feature-set in more complex code, but without the ARM-interworking overhead previously incurred by Thumb.

Aside from the aforementioned access to the full register set from all register operations, Thumb-2 added back branchless conditional execution in the form of the IF-THEN (IT) block. The original Thumb removed the trademark ARM feature of conditional execution on nearly all instructions; this is now achieved in Thumb-2 by prepending the IT instruction with conditions for up to four succeeding instructions.

In addition, the instruction set itself has been vastly expanded; for example, the Cortex-M4F implements the DSP extension as well as the FPv4-SP floating point extension. In fact, I believe even NEON can be encoded in Thumb2.

Tony K
  • 281
  • 1
  • 7
0

ARM 32bit

ARM is a 32bit instruction set. All opcodes are 32bits. The leading bits denote conditional execution. This is generally wasteful as 90+% of code executes unconditionally. The ARM mode supports 16 registers nearly symmetric (with some special cases for PC, LR and SP).

Most instruction included an 's' suffix to set condition codes.

Thumb 16bit

The original thumb is 16bit only opcodes. It does not support conditional execution and access was mainly restricted to the lower eight registers. All arithmetic instructions set condition codes. Some instructions could retrieve data from the higher registers. It can be looked at as a compression engine on the instruction decode.

For some algorithms and memory topology, thumb can be faster than ARM. However it is fairly rare and needs slow (non-zero wait state) instruction memory for this to be the case.

As a practical example, some 'Game boy advance' code would be mainly execute in thumb mode, but would jump to zero wait state RAM and transition to ARM mode for a performance critical routine.

Thumb2 mixed mode

Thumb2 extended the thumb ISA but allows for both 16bit and 32bit opcodes. Almost the entire original ARM instruction set functionality can be achieved with Thumb2. Since the instruction stream is more dense, it is higher performance than the original ARM in almost every case due to lower instruction fetch overhead.

Thumb2 allows conditional execution for four instructions with 'if/else' opcode conditions. It allows use of all 16 registers and .unified code can be written to produce either ARM 32bit or mixed Thumb2 code.

Unified code will always be faster when Thumb2 is selected. There are fairly rare ARM sequences that can not be encoded directly to Thumb2. These few cases snippets could be faster. But generally, for any large code base, Thumb2 is faster.

This mode can be confusing with loop unrolling and jump tables. It is something that an x86 programmer would naturally think of. Ie, there are '.n'/narrow/16bit and '.w'/wide/32bit encodings of identical instructions. So if you treat code as an 'array' of tasks, the computations can be more complex. You also have transfer of control to mid-instruction possibilities.

As an example of 'un-encodeable' Thumb2 ARM code,

   movlo r0,#1
   moveq r0,#0
   movhi r0,#-1

Above is only possible in ARM mode. However, such sequences are very rare and would only matter if you are porting assembler code from ARM to Thumb2. If it is selecting a compiler mode, Thumb2 should always produce better code (faster and smaller).

Summary

Each mode has variations on available opcodes depending on CPU model. However, the general concepts of each mode and performance are as stated.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • Here is [a paper on ARM vs Thumb performance](https://www.cs.ucr.edu/~gupta/research/Publications/Comp/L14-krishnaswamy.pdf), where some real algorithms are compared in these two modes. The paper also compares 'energy consumption' in the two modes, which is of interest for some application domains. ARM always recommends using Thumb2 if available (and this is good advice). – artless noise Jun 11 '22 at 17:37