1 #ifndef __ASM_ARM_UNALIGNED_H 2 #define __ASM_ARM_UNALIGNED_H 3 4 #include <asm/types.h> 5 6 extern 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_2_be(__p) \ 46 (__p[0] << 8 | __p[1]) 47 48 #define __get_unaligned_4_le(__p) \ 49 (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24) 50 51 #define __get_unaligned_4_be(__p) \ 52 (__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3]) 53 54 #define __get_unaligned_le(ptr) \ 55 ({ \ 56 __typeof__(*(ptr)) __v; \ 57 __u8 *__p = (__u8 *)(ptr); \ 58 switch (sizeof(*(ptr))) { \ 59 case 1: __v = *(ptr); break; \ 60 case 2: __v = __get_unaligned_2_le(__p); break; \ 61 case 4: __v = __get_unaligned_4_le(__p); break; \ 62 case 8: { \ 63 unsigned int __v1, __v2; \ 64 __v2 = __get_unaligned_4_le((__p+4)); \ 65 __v1 = __get_unaligned_4_le(__p); \ 66 __v = ((unsigned long long)__v2 << 32 | __v1); \ 67 } \ 68 break; \ 69 default: __v = __bug_unaligned_x(__p); break; \ 70 } \ 71 __v; \ 72 }) 73 74 #define __get_unaligned_be(ptr) \ 75 ({ \ 76 __typeof__(*(ptr)) __v; \ 77 __u8 *__p = (__u8 *)(ptr); \ 78 switch (sizeof(*(ptr))) { \ 79 case 1: __v = *(ptr); break; \ 80 case 2: __v = __get_unaligned_2_be(__p); break; \ 81 case 4: __v = __get_unaligned_4_be(__p); break; \ 82 case 8: { \ 83 unsigned int __v1, __v2; \ 84 __v2 = __get_unaligned_4_be(__p); \ 85 __v1 = __get_unaligned_4_be((__p+4)); \ 86 __v = ((unsigned long long)__v2 << 32 | __v1); \ 87 } \ 88 break; \ 89 default: __v = __bug_unaligned_x(__p); break; \ 90 } \ 91 __v; \ 92 }) 93 94 95 static inline void __put_unaligned_2_le(__u32 __v, register __u8 *__p) 96 { 97 *__p++ = __v; 98 *__p++ = __v >> 8; 99 } 100 101 static inline void __put_unaligned_2_be(__u32 __v, register __u8 *__p) 102 { 103 *__p++ = __v >> 8; 104 *__p++ = __v; 105 } 106 107 static inline void __put_unaligned_4_le(__u32 __v, register __u8 *__p) 108 { 109 __put_unaligned_2_le(__v >> 16, __p + 2); 110 __put_unaligned_2_le(__v, __p); 111 } 112 113 static inline void __put_unaligned_4_be(__u32 __v, register __u8 *__p) 114 { 115 __put_unaligned_2_be(__v >> 16, __p); 116 __put_unaligned_2_be(__v, __p + 2); 117 } 118 119 static inline void __put_unaligned_8_le(const unsigned long long __v, register __u8 *__p) 120 { 121 /* 122 * tradeoff: 8 bytes of stack for all unaligned puts (2 123 * instructions), or an extra register in the long long 124 * case - go for the extra register. 125 */ 126 __put_unaligned_4_le(__v >> 32, __p+4); 127 __put_unaligned_4_le(__v, __p); 128 } 129 130 static inline void __put_unaligned_8_be(const unsigned long long __v, register __u8 *__p) 131 { 132 /* 133 * tradeoff: 8 bytes of stack for all unaligned puts (2 134 * instructions), or an extra register in the long long 135 * case - go for the extra register. 136 */ 137 __put_unaligned_4_be(__v >> 32, __p); 138 __put_unaligned_4_be(__v, __p+4); 139 } 140 141 /* 142 * Try to store an unaligned value as efficiently as possible. 143 */ 144 #define __put_unaligned_le(val,ptr) \ 145 ({ \ 146 switch (sizeof(*(ptr))) { \ 147 case 1: \ 148 *(ptr) = (val); \ 149 break; \ 150 case 2: __put_unaligned_2_le((val),(__u8 *)(ptr)); \ 151 break; \ 152 case 4: __put_unaligned_4_le((val),(__u8 *)(ptr)); \ 153 break; \ 154 case 8: __put_unaligned_8_le((val),(__u8 *)(ptr)); \ 155 break; \ 156 default: __bug_unaligned_x(ptr); \ 157 break; \ 158 } \ 159 (void) 0; \ 160 }) 161 162 #define __put_unaligned_be(val,ptr) \ 163 ({ \ 164 switch (sizeof(*(ptr))) { \ 165 case 1: \ 166 *(ptr) = (val); \ 167 break; \ 168 case 2: __put_unaligned_2_be((val),(__u8 *)(ptr)); \ 169 break; \ 170 case 4: __put_unaligned_4_be((val),(__u8 *)(ptr)); \ 171 break; \ 172 case 8: __put_unaligned_8_be((val),(__u8 *)(ptr)); \ 173 break; \ 174 default: __bug_unaligned_x(ptr); \ 175 break; \ 176 } \ 177 (void) 0; \ 178 }) 179 180 /* 181 * Select endianness 182 */ 183 #ifndef __ARMEB__ 184 #define get_unaligned __get_unaligned_le 185 #define put_unaligned __put_unaligned_le 186 #else 187 #define get_unaligned __get_unaligned_be 188 #define put_unaligned __put_unaligned_be 189 #endif 190 191 #endif 192