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.le...@csgroup.eu>
---
 arch/powerpc/include/asm/uaccess.h | 55 ++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/arch/powerpc/include/asm/uaccess.h 
b/arch/powerpc/include/asm/uaccess.h
index e3e53e88cb26..960ab5c04b11 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -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.
-- 
2.25.0

Reply via email to