Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why unsigned types are more efficient in arm cpu?

Tags:

arm

I'm reading an arm manual and come to this suggestion, but the reason is not mentioned.

Why unsigned types are faster?

like image 622
Felix Avatar asked Jun 22 '10 13:06

Felix


3 Answers

Prior to ARMv4, ARM had no native support for loading halfwords and signed bytes. To load a signed byte you had to LDRB then sign extend the value (LSL it up then ASR it back down). This is painful so char is unsigned by default.

In ARMv4 instructions were added to handle halfwords and signed values. These new instructions had to be squeezed into the available instruction space. Limits on the space available meant that they could not be made as flexible as the original instructions, which are able to do various address computations when loading the value.

So you may find that LDRSB, for example, is unable to combine a fetch from memory with an address computation whereas LDRB could. This can cost cycles. Sometimes we can rework short-heavy code to operate on pairs of ints to avoid this.

There's more info on my site here: http://www.davespace.co.uk/arm/efficient-c-for-arm/memaccess.html

like image 149
David Thomas Avatar answered Nov 12 '22 21:11

David Thomas


I think it's just that the instruction set for ARM CPUs is optimized for unsigned. Some operations can be done with one instruction for unsigned types but will need multiple instructions if it's signed. That's why I think if compiling for ARM in most (all?) C and C++ compilers it defaults to unsigned char rather than the more usual signed char.

like image 3
Hans Olsson Avatar answered Nov 12 '22 23:11

Hans Olsson


The only advantages of unsigned types I can think of are that division and modulo implementations may be slightly faster, and you can do tests like if (unsigned_value < limit) rather than if (signed_value >= 0 && signed_value < limit).

I suspect your manual may be out of date. Any ARM in use today will have v4 or later of the instruction set, and I'm pretty sure that no instructions are faster or slower depending on signedness.

On older ARMs, I believe that signed multiplication could be slower; I think that early termination only looked for all zeros in the top bits, not all ones, so multiplications involving negative numbers would always take the maximum time. Although this depended on the value, not on whether the type was signed or unsigned. On at least ARMv4 and later, early termination works for negative values.

Also, I think very early ARMs couldn't load a single byte, only a word. So you'd need two instructions to load an unsigned byte, and three to load a signed one:

ldr r0, [r1]
and r0, r0, #0xff

versus

ldr r0, [r1]
mov r0, r0, asl #24
mov r0, r0, asr #24   ; but this could maybe be combined with later instructions

versus (these days) ldrb r0, [r1] or ldrsb r0, [r1] to do a single-byte load.

On a modern processor, it's very unlikely that using unsigned types will have a measurable impact on performance. Use whichever type makes most sense, then look at the code in detail once you've identified any performance bottlenecks.

like image 2
Mike Seymour Avatar answered Nov 12 '22 21:11

Mike Seymour