diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 2672971b83f3..bed3f1c8d9d2 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -16,6 +16,7 @@ config ALPHA select ARCH_NO_PREEMPT select ARCH_NO_SG_CHAIN select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 select ARCH_USE_CMPXCHG_LOCKREF select FORCE_PCI select PCI_DOMAINS if PCI diff --git a/arch/alpha/include/asm/asm-prototypes.h b/arch/alpha/include/asm/asm-prototypes.h index c8ae46fc2e74..672fea15032f 100644 --- a/arch/alpha/include/asm/asm-prototypes.h +++ b/arch/alpha/include/asm/asm-prototypes.h @@ -17,3 +17,9 @@ extern void __remlu(void); extern void __divqu(void); extern void __remqu(void); extern unsigned long __udiv_qrnnd(unsigned long *, unsigned long, unsigned long , unsigned long); + +#ifdef CONFIG_ARCH_SUPPORTS_INT128 +extern __int128_t __ashlti3(__int128_t a, int shift); +extern __int128_t __ashrti3(__int128_t a, int shift); +extern __int128_t __lshrti3(__int128_t a, int shift); +#endif diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 84046e730e6d..f77d4a46f2e6 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -35,6 +35,8 @@ lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \ callback_srm.o srm_puts.o srm_printk.o \ fls.o +obj-$(CONFIG_ARCH_SUPPORTS_INT128) += tishift.o + # The division routines are built from single source, with different defines. AFLAGS___divqu.o = -DDIV AFLAGS___remqu.o = -DREM diff --git a/arch/alpha/lib/tishift.c b/arch/alpha/lib/tishift.c new file mode 100644 index 000000000000..8319907d8150 --- /dev/null +++ b/arch/alpha/lib/tishift.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 128-bit shift helpers. + * + * gcc open-codes a variable 128-bit shift when optimizing for speed, but + * calls these libgcc routines when optimizing for size. + */ + +#include +#include +#include + +union ti { + __int128_t val; + struct { + u64 low; + u64 high; + }; +}; + +noinstr __int128_t __ashlti3(__int128_t a, int shift) +{ + union ti ti = { .val = a }; + + if (!shift) + return ti.val; + if (shift < 64) { + ti.high = (ti.high << shift) | (ti.low >> (64 - shift)); + ti.low <<= shift; + } else { + ti.high = ti.low << (shift - 64); + ti.low = 0; + } + return ti.val; +} +EXPORT_SYMBOL(__ashlti3); + +noinstr __int128_t __ashrti3(__int128_t a, int shift) +{ + union ti ti = { .val = a }; + + if (!shift) + return ti.val; + if (shift < 64) { + ti.low = (ti.low >> shift) | (ti.high << (64 - shift)); + ti.high = (s64)ti.high >> shift; + } else { + ti.low = (s64)ti.high >> (shift - 64); + ti.high = (s64)ti.high >> 63; + } + return ti.val; +} +EXPORT_SYMBOL(__ashrti3); + +noinstr __int128_t __lshrti3(__int128_t a, int shift) +{ + union ti ti = { .val = a }; + + if (!shift) + return ti.val; + if (shift < 64) { + ti.low = (ti.low >> shift) | (ti.high << (64 - shift)); + ti.high >>= shift; + } else { + ti.low = ti.high >> (shift - 64); + ti.high = 0; + } + return ti.val; +} +EXPORT_SYMBOL(__lshrti3);