OSDN Git Service

powerpc/uaccess: Use asm goto for get_user when compiler supports it
authorChristophe Leroy <christophe.leroy@csgroup.eu>
Wed, 10 Mar 2021 17:46:54 +0000 (17:46 +0000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sat, 3 Apr 2021 10:22:16 +0000 (21:22 +1100)
clang 11 and future GCC are supporting asm goto with outputs.

Use it to implement get_user in order to get better generated code.

Note that clang requires to set x in the default branch of
__get_user_size_goto() otherwise is compliant about x not being
initialised :puzzled:

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/403745b5aaa1b315bb4e8e46c1ba949e77eecec0.1615398265.git.christophe.leroy@csgroup.eu
arch/powerpc/include/asm/uaccess.h

index 797a144..77d837b 100644 (file)
@@ -136,6 +136,59 @@ do {                                                               \
                : "=r" (err)                    \
                : "b" (uaddr), "b" (kaddr), "i" (-EFAULT), "0" (err))
 
+#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
+
+#define __get_user_asm_goto(x, addr, label, op)                        \
+       asm_volatile_goto(                                      \
+               "1:     "op"%U1%X1 %0, %1       # get_user\n"   \
+               EX_TABLE(1b, %l2)                               \
+               : "=r" (x)                                      \
+               : "m"UPD_CONSTR (*addr)                         \
+               :                                               \
+               : label)
+
+#ifdef __powerpc64__
+#define __get_user_asm2_goto(x, addr, label)                   \
+       __get_user_asm_goto(x, addr, label, "ld")
+#else /* __powerpc64__ */
+#define __get_user_asm2_goto(x, addr, label)                   \
+       asm_volatile_goto(                                      \
+               "1:     lwz%X1 %0, %1\n"                        \
+               "2:     lwz%X1 %L0, %L1\n"                      \
+               EX_TABLE(1b, %l2)                               \
+               EX_TABLE(2b, %l2)                               \
+               : "=r" (x)                                      \
+               : "m" (*addr)                                   \
+               :                                               \
+               : label)
+#endif /* __powerpc64__ */
+
+#define __get_user_size_goto(x, ptr, size, label)                              \
+do {                                                                           \
+       BUILD_BUG_ON(size > sizeof(x));                                         \
+       switch (size) {                                                         \
+       case 1: __get_user_asm_goto(x, (u8 __user *)ptr, label, "lbz"); break;  \
+       case 2: __get_user_asm_goto(x, (u16 __user *)ptr, label, "lhz"); break; \
+       case 4: __get_user_asm_goto(x, (u32 __user *)ptr, label, "lwz"); break; \
+       case 8: __get_user_asm2_goto(x, (u64 __user *)ptr, label);  break;      \
+       default: x = 0; BUILD_BUG();                                            \
+       }                                                                       \
+} while (0)
+
+#define __get_user_size_allowed(x, ptr, size, retval)                  \
+do {                                                                   \
+               __label__ __gus_failed;                                 \
+                                                                       \
+               __get_user_size_goto(x, ptr, size, __gus_failed);       \
+               retval = 0;                                             \
+               break;                                                  \
+__gus_failed:                                                          \
+               x = 0;                                                  \
+               retval = -EFAULT;                                       \
+} while (0)
+
+#else /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
+
 #define __get_user_asm(x, addr, err, op)               \
        __asm__ __volatile__(                           \
                "1:     "op"%U2%X2 %1, %2       # get_user\n"   \
@@ -192,6 +245,8 @@ do {                                                                \
                goto label;                                     \
 } while (0)
 
+#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
+
 /*
  * This is a type: either unsigned long, if the argument fits into
  * that type, or otherwise unsigned long long.