Re: [PATCH] x86: support i386 with Clang

From: Nick Desaulniers
Date: Mon May 11 2020 - 13:24:00 EST


Bumping for comment+review.

On Mon, May 4, 2020 at 4:03 PM Nick Desaulniers <ndesaulniers@xxxxxxxxxx> wrote:
>
> GCC and Clang are architecturally different, which leads to subtle
> issues for code that's invalid but clearly dead. This can happen with
> code that emulates polymorphism with the preprocessor and sizeof.
>
> GCC will perform semantic analysis after early inlining and dead code
> elimination, so it will not warn on invalid code that's dead. Clang
> strictly performs optimizations after semantic analysis, so it will warn
> for dead code.
>
> Neither Clang nor GCC like this very much with -m32:
>
> long long ret;
> asm ("movb $5, %0" : "=q" (ret));
>
> However, GCC can tolerate this variant:
>
> long long ret;
> switch (sizeof(ret)) {
> case 1:
> asm ("movb $5, %0" : "=q" (ret));
> break;
> case 8:;
> }
>
> Clang, on the other hand, won't accept that because it validates the
> inline asm for the '1' case *before* the optimisation phase where it
> realises that it wouldn't have to emit it anyway.
>
> If LLVM (Clang's "back end") fails such as during instruction selection
> or register allocation, it cannot provide accurate diagnostics
> (warnings/errors) that contain line information, as the AST has been
> discarded from memory at that point.
>
> While there have been early discussions about having C/C++ specific
> language optimizations in Clang via the use of MLIR, which would enable
> such earlier optimizations, such work is not scoped and likely a
> multi-year endeavor.
>
> We also don't want to swap the use of "=q" with "=r". For 64b, it
> doesn't matter. For 32b, it's possible that a 32b register without a 8b
> lower alias (i.e. ESI, EDI, EBP) is selected which the assembler will
> then reject.
>
> With this, Clang can finally build an i386 defconfig.
>
> Reported-by: Arnd Bergmann <arnd@xxxxxxxx>
> Reported-by: David Woodhouse <dwmw2@xxxxxxxxxxxxx>
> Reported-by: Dmitry Golovin <dima@xxxxxxxxxx>
> Reported-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
> Link: https://bugs.llvm.org/show_bug.cgi?id=33587
> Link: https://github.com/ClangBuiltLinux/linux/issues/3
> Link: https://github.com/ClangBuiltLinux/linux/issues/194
> Link: https://github.com/ClangBuiltLinux/linux/issues/781
> Link: https://lore.kernel.org/lkml/20180209161833.4605-1-dwmw2@xxxxxxxxxxxxx/
> Link: https://lore.kernel.org/lkml/CAK8P3a1EBaWdbAEzirFDSgHVJMtWjuNt2HGG8z+vpXeNHwETFQ@xxxxxxxxxxxxxx/
> Signed-off-by: Nick Desaulniers <ndesaulniers@xxxxxxxxxx>
> ---
> Note: this is a resend of:
> https://lore.kernel.org/lkml/20180209161833.4605-1-dwmw2@xxxxxxxxxxxxx/
> rebased on today's Linux next, and with the additional change to
> uaccess.h.
>
> I'm happy to resend with authorship and reported by tags changed to
> suggested by's or whatever, just let me know.
>
> Part of the commit message is stolen from David, and part from Linus.
> Shall I resend with David's authorship and
> [Nick: reworded]
> ???
>
> I don't really care, I just don't really want to carry this out of tree
> for our CI, which is green for i386 otherwise.
>
>
> arch/x86/include/asm/percpu.h | 12 ++++++++----
> arch/x86/include/asm/uaccess.h | 4 +++-
> 2 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
> index 2278797c769d..826d086f71c9 100644
> --- a/arch/x86/include/asm/percpu.h
> +++ b/arch/x86/include/asm/percpu.h
> @@ -99,7 +99,7 @@ do { \
> case 1: \
> asm qual (op "b %1,"__percpu_arg(0) \
> : "+m" (var) \
> - : "qi" ((pto_T__)(val))); \
> + : "qi" ((unsigned char)(unsigned long)(val))); \
> break; \
> case 2: \
> asm qual (op "w %1,"__percpu_arg(0) \
> @@ -144,7 +144,7 @@ do { \
> else \
> asm qual ("addb %1, "__percpu_arg(0) \
> : "+m" (var) \
> - : "qi" ((pao_T__)(val))); \
> + : "qi" ((unsigned char)(unsigned long)(val))); \
> break; \
> case 2: \
> if (pao_ID__ == 1) \
> @@ -182,12 +182,14 @@ do { \
>
> #define percpu_from_op(qual, op, var) \
> ({ \
> + unsigned char pfo_u8__; \
> typeof(var) pfo_ret__; \
> switch (sizeof(var)) { \
> case 1: \
> asm qual (op "b "__percpu_arg(1)",%0" \
> - : "=q" (pfo_ret__) \
> + : "=q" (pfo_u8__) \
> : "m" (var)); \
> + pfo_ret__ = (typeof(var))(unsigned long)pfo_u8__; \
> break; \
> case 2: \
> asm qual (op "w "__percpu_arg(1)",%0" \
> @@ -211,12 +213,14 @@ do { \
>
> #define percpu_stable_op(op, var) \
> ({ \
> + unsigned char pfo_u8__; \
> typeof(var) pfo_ret__; \
> switch (sizeof(var)) { \
> case 1: \
> asm(op "b "__percpu_arg(P1)",%0" \
> - : "=q" (pfo_ret__) \
> + : "=q" (pfo_u8__) \
> : "p" (&(var))); \
> + pfo_ret__ = (typeof(var))(unsigned long)pfo_u8__; \
> break; \
> case 2: \
> asm(op "w "__percpu_arg(P1)",%0" \
> diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
> index d8f283b9a569..cf8483cd80e1 100644
> --- a/arch/x86/include/asm/uaccess.h
> +++ b/arch/x86/include/asm/uaccess.h
> @@ -314,11 +314,13 @@ do { \
>
> #define __get_user_size(x, ptr, size, retval) \
> do { \
> + unsigned char x_u8__; \
> retval = 0; \
> __chk_user_ptr(ptr); \
> switch (size) { \
> case 1: \
> - __get_user_asm(x, ptr, retval, "b", "=q"); \
> + __get_user_asm(x_u8__, ptr, retval, "b", "=q"); \
> + (x) = x_u8__; \
> break; \
> case 2: \
> __get_user_asm(x, ptr, retval, "w", "=r"); \
> --
> 2.26.2.526.g744177e7f7-goog
>


--
Thanks,
~Nick Desaulniers