align macro kernel
Say you have a number: 0x1006
For some reasons you want to align it to a 4
bytes boundary.
With a 4-byte boundary, you know aligned values are 0x1000
, 0x1004
, 0x1008
, etc.
You then also know the aligned value of 0x1006
is 0x1008
.
How would you get 0x1008
? The alignment mask for alignment value 4
is (4 - 1) = 0x03
Now 0x1006 + 0x03 = 0x1009
and 0x1009 & ~0x03 = 0x1008
This operation is the __ALIGN_MASK
macro.
If you want to pass the value 4
(the alignment) instead of directly 0x03
(the alignment mask), you have the ALIGN
macro
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
the alignment, a
, is cast to x
's type, and then one is subtracted. The alignment should be a power of 2, so that results in a number of the bit-pattern 00..011..11
of x
's type, the mask (k
1s if a = 2^k
).
Then
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
adds the value of the mask to x
, so that (x)+ (mask)
is at least as large as the smallest multiple of the alignment that is not smaller than x
and smaller than the next larger multiple. Then the bitwise and with the complement of the mask reduces that number to that multiple of the alignment.
For masks of the form 2^k - 1
, the computation
(x + mask) & ~mask
is the same as
(x + 2^k - 1) - ((x + 2^k - 1) % (2^k))
or
((x + 2^k - 1)/(2^k)) * (2^k)