Commit 5cd29b1f authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/uaccess: Use asm goto for get_user when compiler supports it

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: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/403745b5aaa1b315bb4e8e46c1ba949e77eecec0.1615398265.git.christophe.leroy@csgroup.eu
parent 035785ab
...@@ -136,6 +136,59 @@ do { \ ...@@ -136,6 +136,59 @@ do { \
: "=r" (err) \ : "=r" (err) \
: "b" (uaddr), "b" (kaddr), "i" (-EFAULT), "0" (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) \ #define __get_user_asm(x, addr, err, op) \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: "op"%U2%X2 %1, %2 # get_user\n" \ "1: "op"%U2%X2 %1, %2 # get_user\n" \
...@@ -192,6 +245,8 @@ do { \ ...@@ -192,6 +245,8 @@ do { \
goto label; \ goto label; \
} while (0) } while (0)
#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
/* /*
* This is a type: either unsigned long, if the argument fits into * This is a type: either unsigned long, if the argument fits into
* that type, or otherwise unsigned long long. * that type, or otherwise unsigned long long.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment