xref: /linux/arch/alpha/lib/tishift.c (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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