Linux "yin"才们的奇"yin"小技巧 --请用东北发音夸他们
1. include/linux/bits.h GENMASK(h, l)
/*
* Create a contiguous bitmask starting at bit position @l and ending at
* position @h. For example
* GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
*/
#define GENMASK(h, l) \
(((~UL(0)) - (UL(1) << (l)) + 1) & \ ||1
(~UL(0) >> (BITS_PER_LONG - 1 - (h)))) ||2
Exp. (6,4) of 0x1111 1111
1-->0x1111 1111 - (0x1<<4) = 0x1110 1111 + 1 = 0x1111 0000
2-->0x1111 1111 >> (8-1-6) = 0x0111 1111
1&2 = 0x0111 0000
2. include/linux/bitfield.h
/* * Bitfield access macros * * FIELD_{GET,PREP} macros take as first parameter shifted mask * from which they extract the base mask and shift amount. * Mask must be a compilation time constant. * * Example: * * #define REG_FIELD_A GENMASK(6, 0) * #define REG_FIELD_B BIT(7) * #define REG_FIELD_C GENMASK(15, 8) * #define REG_FIELD_D GENMASK(31, 16) * * Get: * a = FIELD_GET(REG_FIELD_A, reg); * b = FIELD_GET(REG_FIELD_B, reg); * * Set: * reg = FIELD_PREP(REG_FIELD_A, 1) | * FIELD_PREP(REG_FIELD_B, 0) | * FIELD_PREP(REG_FIELD_C, c) | * FIELD_PREP(REG_FIELD_D, 0x40); * * Modify: * reg &= ~REG_FIELD_C; * reg |= FIELD_PREP(REG_FIELD_C, c); */ #define __bf_shf(x) (__builtin_ffsll(x) - 1)
3.
#include <stdio.h> #define UL (unsigned long) #define GENMASK(h, l, H, L) \ ({typeof(h) H = (h); \ typeof(l) L = (l); \ (((~UL(0)) >>(L)<< (L)) & \ (~UL(0) >> (64 - 1 - (H))));}) #define GENMASK_OLD(h, l) \ (((~UL(0)) >>(l)<< (l)) & \ (~UL(0) >> (64 - 1 - (h)))) void main(){ int i = 6, j = 4; printf("output:%lx\n", GENMASK_OLD(6,4)); printf("output:%lx\n", GENMASK_OLD(i++,j++)); printf("output:%lx\n", GENMASK(i++,j++, H, L)); }
4. 完整测试代码,运行效率比原生态高,而且易读懂
#include <stdio.h> #define UL (unsigned long) #define BITS_PER_LONG sizeof(unsigned long) #define GENMASK_NEW(h, l, H, L) \ ({typeof(h) H = (h); \ typeof(l) L = (l); \ (((~UL(0)) >>(L)<< (L)) & \ (~UL(0) >> (64 - 1 - (H))));}) #define GENMASK(h, l) \ (((~UL(0)) - (UL(1) << (l)) + 1) & \ (~UL(0) >> (64 - 1 - (h)))) #define GENMASK_YIN(h, l) \ (((~UL(0))>>(64-1-(h))) & \ (~UL(0))>>(l)<<(l)) void main(){ unsigned long loop1 = 1000; unsigned long loop2 = 10000000; int i = 6, j=4; #if 0 printf("output:%lx\n", GENMASK_NEW(i++,j++, H, L)); i = 6; j = 4; printf("output:%lx\n", GENMASK_NEW(++i,++j, H, L)); //org: i = 6; j = 4; printf("output:%lx\n", GENMASK(i++,j++)); i = 6; j = 4; printf("output:%lx\n", GENMASK(++i,++j)); return; #endif //printf("GENMASK(i+1, j+1):%lx\n", GENMASK(i+1, j+1)); printf("GENMASK_NEW(i+1, j+1):%lx\n", GENMASK_NEW(i+1, j+1,H,L)); while(loop1--){ loop2 = 10000000; while(loop2--){ //printf("%lx\n", GENMASK(6, 4)); //GENMASK(i+1, j+1); //GENMASK_YIN(i, j); GENMASK_NEW(i,j, H, L); } } //printf("hello%ld, BITS_PER_LONG:%ld\n", sizeof UL, BITS_PER_LONG); }
https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/barrier.h#L130