ARM > Efficient C for ARM > Unsigned Ranges

by David Thomas on

Unsigned Ranges

When testing for a value within a range we can apply the unsigned range optimisation:

  • Shift the range down so its minimum is zero.
  • Cast to unsigned.
  • ⇒ Any negative values become large positive values.

This means we can do a single test rather than two.

Eliminates branching.

Examples

int insideRange1(int v, int min, int max)
{
  return v >= min && v < max;
}
insideRange1 CMP   r0,r1
             BLT   |L1.20|
             CMP   r0,r2
             MOVLT r0,#1
             MOVLT pc,lr
|L1.20|
             MOV   r0,#0
             MOV   pc,lr
int insideRange2(int v, int min, int max)
{
  return (unsigned) (v - min) < (max - min);
}
insideRange2 SUB   r0,r0,r1
             SUB   r1,r2,r1
             CMP   r0,r1
             MOVCS r0,#0
             MOVCC r0,#1
             MOV   pc,lr

Remarks

In some cases the compiler can make this transformation itself.

It’s now branchless but mightn’t terminate as early.

This is especially beneficial when ‘min’ is zero. Of course this becomes even more beneficial when testing 2D and 3D ranges.