Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

m68k: Use kernel's generic muldi3 libgcc function

Use the kernels own generic lib/muldi3.c implementation of muldi3 for
68K machines. Some 68K CPUs support 64bit multiplies so move the arch
specific umul_ppmm() macro into a header file that is included by
lib/muldi3.c. That way it can take advantage of the single instruction
when available.

There does not appear to be any existing mechanism for the generic
lib/muldi3.c code to pick up an external arch definition of umul_ppmm().
Create an arch specific libgcc.h that can optionally be included by
the system include/linux/libgcc.h to allow for this.

Somewhat oddly there is also a similar definition of umul_ppmm() in
the non-architecture code in lib/crypto/mpi/longlong.h for a wide range
or machines. Its presence ends up complicating the include setup and
means not being able to use something like compiler.h instead. Actually
there is a few other defines of umul_ppmm() macros spread around in
various architectures, but not directly usable for the m68k case.

Signed-off-by: Greg Ungerer <gerg@linux-m68k.org>
Link: https://lore.kernel.org/20231113133209.1367286-1-gerg@linux-m68k.org
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>

authored by

Greg Ungerer and committed by
Geert Uytterhoeven
e419ddea 40384c84

+35 -98
+8
arch/Kconfig
··· 1526 1526 linux/compiler-*.h in order to override macro definitions that those 1527 1527 headers generally provide. 1528 1528 1529 + config HAVE_ARCH_LIBGCC_H 1530 + bool 1531 + help 1532 + An architecture can select this if it provides an 1533 + asm/libgcc.h header that should be included after 1534 + linux/libgcc.h in order to override macro definitions that 1535 + header generally provides. 1536 + 1529 1537 config HAVE_ARCH_PREL32_RELOCATIONS 1530 1538 bool 1531 1539 help
+2
arch/m68k/Kconfig
··· 23 23 select GENERIC_LIB_ASHLDI3 24 24 select GENERIC_LIB_ASHRDI3 25 25 select GENERIC_LIB_LSHRDI3 26 + select GENERIC_LIB_MULDI3 26 27 select HAS_IOPORT if PCI || ISA || ATARI_ROM_ISA 28 + select HAVE_ARCH_LIBGCC_H 27 29 select HAVE_ARCH_SECCOMP 28 30 select HAVE_ARCH_SECCOMP_FILTER 29 31 select HAVE_ASM_MODVERSIONS
+20
arch/m68k/include/asm/libgcc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __ASM_M68K_LIBGCC_H 3 + #define __ASM_M68K_LIBGCC_H 4 + 5 + #ifndef CONFIG_CPU_HAS_NO_MULDIV64 6 + /* 7 + * For those 68K CPUs that support 64bit multiply define umul_ppm() 8 + * for the common muldi3 libgcc helper function (in lib/muldi3.c). 9 + * CPUs that don't have it (like the original 68000 and ColdFire) 10 + * will fallback to using the C-coded version of umul_ppmm(). 11 + */ 12 + #define umul_ppmm(w1, w0, u, v) \ 13 + __asm__ ("mulu%.l %3,%1:%0" \ 14 + : "=d" ((unsigned long)(w0)), \ 15 + "=d" ((unsigned long)(w1)) \ 16 + : "%0" ((unsigned long)(u)), \ 17 + "dmi" ((unsigned long)(v))) 18 + #endif /* !CONFIG_CPU_HAS_NO_MULDIV64 */ 19 + 20 + #endif /* __ASM_M68K_LIBGCC_H */
+1 -1
arch/m68k/lib/Makefile
··· 4 4 # Makefile for m68k-specific library files.. 5 5 # 6 6 7 - lib-y := muldi3.o memcpy.o memset.o memmove.o 7 + lib-y := memcpy.o memset.o memmove.o 8 8 9 9 lib-$(CONFIG_MMU) += uaccess.o 10 10 lib-$(CONFIG_CPU_HAS_NO_MULDIV64) += mulsi3.o divsi3.o udivsi3.o
-97
arch/m68k/lib/muldi3.c
··· 1 - /* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 2 - gcc-2.7.2.3/longlong.h which is: */ 3 - /* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. 4 - 5 - This file is part of GNU CC. 6 - 7 - GNU CC is free software; you can redistribute it and/or modify 8 - it under the terms of the GNU General Public License as published by 9 - the Free Software Foundation; either version 2, or (at your option) 10 - any later version. 11 - 12 - GNU CC is distributed in the hope that it will be useful, 13 - but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - GNU General Public License for more details. */ 16 - 17 - #include <linux/compiler.h> 18 - #include <linux/export.h> 19 - #include <linux/libgcc.h> 20 - 21 - #ifdef CONFIG_CPU_HAS_NO_MULDIV64 22 - 23 - #define SI_TYPE_SIZE 32 24 - #define __BITS4 (SI_TYPE_SIZE / 4) 25 - #define __ll_B (1L << (SI_TYPE_SIZE / 2)) 26 - #define __ll_lowpart(t) ((USItype) (t) % __ll_B) 27 - #define __ll_highpart(t) ((USItype) (t) / __ll_B) 28 - 29 - #define umul_ppmm(w1, w0, u, v) \ 30 - do { \ 31 - USItype __x0, __x1, __x2, __x3; \ 32 - USItype __ul, __vl, __uh, __vh; \ 33 - \ 34 - __ul = __ll_lowpart (u); \ 35 - __uh = __ll_highpart (u); \ 36 - __vl = __ll_lowpart (v); \ 37 - __vh = __ll_highpart (v); \ 38 - \ 39 - __x0 = (USItype) __ul * __vl; \ 40 - __x1 = (USItype) __ul * __vh; \ 41 - __x2 = (USItype) __uh * __vl; \ 42 - __x3 = (USItype) __uh * __vh; \ 43 - \ 44 - __x1 += __ll_highpart (__x0);/* this can't give carry */ \ 45 - __x1 += __x2; /* but this indeed can */ \ 46 - if (__x1 < __x2) /* did we get it? */ \ 47 - __x3 += __ll_B; /* yes, add it in the proper pos. */ \ 48 - \ 49 - (w1) = __x3 + __ll_highpart (__x1); \ 50 - (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ 51 - } while (0) 52 - 53 - #else 54 - 55 - #define umul_ppmm(w1, w0, u, v) \ 56 - __asm__ ("mulu%.l %3,%1:%0" \ 57 - : "=d" ((USItype)(w0)), \ 58 - "=d" ((USItype)(w1)) \ 59 - : "%0" ((USItype)(u)), \ 60 - "dmi" ((USItype)(v))) 61 - 62 - #endif 63 - 64 - #define __umulsidi3(u, v) \ 65 - ({DIunion __w; \ 66 - umul_ppmm (__w.s.high, __w.s.low, u, v); \ 67 - __w.ll; }) 68 - 69 - typedef int SItype __mode(SI); 70 - typedef unsigned int USItype __mode(SI); 71 - typedef int DItype __mode(DI); 72 - typedef int word_type __mode(__word__); 73 - 74 - struct DIstruct {SItype high, low;}; 75 - 76 - typedef union 77 - { 78 - struct DIstruct s; 79 - DItype ll; 80 - } DIunion; 81 - 82 - DItype 83 - __muldi3 (DItype u, DItype v) 84 - { 85 - DIunion w; 86 - DIunion uu, vv; 87 - 88 - uu.ll = u; 89 - vv.ll = v; 90 - 91 - w.ll = __umulsidi3 (uu.s.low, vv.s.low); 92 - w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high 93 - + (USItype) uu.s.high * (USItype) vv.s.low); 94 - 95 - return w.ll; 96 - } 97 - EXPORT_SYMBOL(__muldi3);
+4
include/linux/libgcc.h
··· 34 34 long long notrace __muldi3(long long u, long long v); 35 35 word_type notrace __ucmpdi2(unsigned long long a, unsigned long long b); 36 36 37 + #ifdef CONFIG_HAVE_ARCH_LIBGCC_H 38 + #include <asm/libgcc.h> 39 + #endif 40 + 37 41 #endif /* __ASM_LIBGCC_H */