Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.18-rc3 118 lines 3.2 kB view raw
1#ifndef __ASM_ARM_UNALIGNED_H 2#define __ASM_ARM_UNALIGNED_H 3 4#include <asm/types.h> 5 6extern int __bug_unaligned_x(void *ptr); 7 8/* 9 * What is the most efficient way of loading/storing an unaligned value? 10 * 11 * That is the subject of this file. Efficiency here is defined as 12 * minimum code size with minimum register usage for the common cases. 13 * It is currently not believed that long longs are common, so we 14 * trade efficiency for the chars, shorts and longs against the long 15 * longs. 16 * 17 * Current stats with gcc 2.7.2.2 for these functions: 18 * 19 * ptrsize get: code regs put: code regs 20 * 1 1 1 1 2 21 * 2 3 2 3 2 22 * 4 7 3 7 3 23 * 8 20 6 16 6 24 * 25 * gcc 2.95.1 seems to code differently: 26 * 27 * ptrsize get: code regs put: code regs 28 * 1 1 1 1 2 29 * 2 3 2 3 2 30 * 4 7 4 7 4 31 * 8 19 8 15 6 32 * 33 * which may or may not be more efficient (depending upon whether 34 * you can afford the extra registers). Hopefully the gcc 2.95 35 * is inteligent enough to decide if it is better to use the 36 * extra register, but evidence so far seems to suggest otherwise. 37 * 38 * Unfortunately, gcc is not able to optimise the high word 39 * out of long long >> 32, or the low word from long long << 32 40 */ 41 42#define __get_unaligned_2_le(__p) \ 43 (__p[0] | __p[1] << 8) 44 45#define __get_unaligned_4_le(__p) \ 46 (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24) 47 48#define __get_unaligned_le(ptr) \ 49 ({ \ 50 __typeof__(*(ptr)) __v; \ 51 __u8 *__p = (__u8 *)(ptr); \ 52 switch (sizeof(*(ptr))) { \ 53 case 1: __v = *(ptr); break; \ 54 case 2: __v = __get_unaligned_2_le(__p); break; \ 55 case 4: __v = __get_unaligned_4_le(__p); break; \ 56 case 8: { \ 57 unsigned int __v1, __v2; \ 58 __v2 = __get_unaligned_4_le((__p+4)); \ 59 __v1 = __get_unaligned_4_le(__p); \ 60 __v = ((unsigned long long)__v2 << 32 | __v1); \ 61 } \ 62 break; \ 63 default: __v = __bug_unaligned_x(__p); break; \ 64 } \ 65 __v; \ 66 }) 67 68static inline void __put_unaligned_2_le(__u32 __v, register __u8 *__p) 69{ 70 *__p++ = __v; 71 *__p++ = __v >> 8; 72} 73 74static inline void __put_unaligned_4_le(__u32 __v, register __u8 *__p) 75{ 76 __put_unaligned_2_le(__v >> 16, __p + 2); 77 __put_unaligned_2_le(__v, __p); 78} 79 80static inline void __put_unaligned_8_le(const unsigned long long __v, register __u8 *__p) 81{ 82 /* 83 * tradeoff: 8 bytes of stack for all unaligned puts (2 84 * instructions), or an extra register in the long long 85 * case - go for the extra register. 86 */ 87 __put_unaligned_4_le(__v >> 32, __p+4); 88 __put_unaligned_4_le(__v, __p); 89} 90 91/* 92 * Try to store an unaligned value as efficiently as possible. 93 */ 94#define __put_unaligned_le(val,ptr) \ 95 ({ \ 96 switch (sizeof(*(ptr))) { \ 97 case 1: \ 98 *(ptr) = (val); \ 99 break; \ 100 case 2: __put_unaligned_2_le((val),(__u8 *)(ptr)); \ 101 break; \ 102 case 4: __put_unaligned_4_le((val),(__u8 *)(ptr)); \ 103 break; \ 104 case 8: __put_unaligned_8_le((val),(__u8 *)(ptr)); \ 105 break; \ 106 default: __bug_unaligned_x(ptr); \ 107 break; \ 108 } \ 109 (void) 0; \ 110 }) 111 112/* 113 * Select endianness 114 */ 115#define get_unaligned __get_unaligned_le 116#define put_unaligned __put_unaligned_le 117 118#endif