1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * 128-bit shift helpers. 4 * 5 * gcc open-codes a variable 128-bit shift when optimizing for speed, but 6 * calls these libgcc routines when optimizing for size. 7 */ 8 9 #include <linux/export.h> 10 #include <linux/types.h> 11 #include <asm/asm-prototypes.h> 12 13 union ti { 14 __int128_t val; 15 struct { 16 u64 low; 17 u64 high; 18 }; 19 }; 20 21 noinstr __int128_t __ashlti3(__int128_t a, int shift) 22 { 23 union ti ti = { .val = a }; 24 25 if (!shift) 26 return ti.val; 27 if (shift < 64) { 28 ti.high = (ti.high << shift) | (ti.low >> (64 - shift)); 29 ti.low <<= shift; 30 } else { 31 ti.high = ti.low << (shift - 64); 32 ti.low = 0; 33 } 34 return ti.val; 35 } 36 EXPORT_SYMBOL(__ashlti3); 37 38 noinstr __int128_t __ashrti3(__int128_t a, int shift) 39 { 40 union ti ti = { .val = a }; 41 42 if (!shift) 43 return ti.val; 44 if (shift < 64) { 45 ti.low = (ti.low >> shift) | (ti.high << (64 - shift)); 46 ti.high = (s64)ti.high >> shift; 47 } else { 48 ti.low = (s64)ti.high >> (shift - 64); 49 ti.high = (s64)ti.high >> 63; 50 } 51 return ti.val; 52 } 53 EXPORT_SYMBOL(__ashrti3); 54 55 noinstr __int128_t __lshrti3(__int128_t a, int shift) 56 { 57 union ti ti = { .val = a }; 58 59 if (!shift) 60 return ti.val; 61 if (shift < 64) { 62 ti.low = (ti.low >> shift) | (ti.high << (64 - shift)); 63 ti.high >>= shift; 64 } else { 65 ti.low = ti.high >> (shift - 64); 66 ti.high = 0; 67 } 68 return ti.val; 69 } 70 EXPORT_SYMBOL(__lshrti3); 71