Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

align macro kernel

I am unable to understand what this macro does. These are defined in linux-kernel but my doubt is independent of that. I am unable to understand what does (((x)+(mask))&~(mask)) line does.

#define ALIGN(x,a)              __ALIGN_MASK(x,(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask)    (((x)+(mask))&~(mask))

Any help appreciated.

like image 371
Aman Deep Gautam Avatar asked Oct 29 '12 13:10

Aman Deep Gautam


2 Answers

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

like image 106
ouah Avatar answered Oct 10 '22 11:10

ouah


#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)
like image 22
Daniel Fischer Avatar answered Oct 10 '22 10:10

Daniel Fischer