RISC-V: Stop relying on GCC's register allocator's hueristics
authorPalmer Dabbelt <palmerdabbelt@google.com>
Thu, 27 Feb 2020 19:07:28 +0000 (11:07 -0800)
committerPalmer Dabbelt <palmerdabbelt@google.com>
Tue, 3 Mar 2020 18:28:13 +0000 (10:28 -0800)
GCC allows users to hint to the register allocation that a variable should be
placed in a register by using a syntax along the lines of

    function(...) {
        register long in_REG __asm__("REG");
    }

We've abused this a bit throughout the RISC-V port to access fixed registers
directly as C variables.  In practice it's never going to blow up because GCC
isn't going to allocate these registers, but it's not a well defined syntax so
we really shouldn't be relying upon this.  Luckily there is a very similar but
well defined syntax that allows us to still access these registers directly as
C variables, which is to simply declare the register variables globally.  For
fixed variables this doesn't change the ABI.

LLVM disallows this ambiguous syntax, so this isn't just strictly a formatting
change.

Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
arch/riscv/include/asm/current.h
arch/riscv/kernel/process.c
arch/riscv/kernel/stacktrace.c

index dd973efe5d7cefb85e1a892ecaf2002cef9f4dae..1de233d8e8de215d9fd34d3ddbb0312d3617cc0d 100644 (file)
@@ -17,6 +17,8 @@
 
 struct task_struct;
 
+register struct task_struct *riscv_current_is_tp __asm__("tp");
+
 /*
  * This only works because "struct thread_info" is at offset 0 from "struct
  * task_struct".  This constraint seems to be necessary on other architectures
@@ -26,8 +28,7 @@ struct task_struct;
  */
 static __always_inline struct task_struct *get_current(void)
 {
-       register struct task_struct *tp __asm__("tp");
-       return tp;
+       return riscv_current_is_tp;
 }
 
 #define current get_current()
index 817cf7b0974ced30d75d536b192b73b4e3c25bdf..610c11e91606878985ef243cc3151ffcec09a5c3 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/switch_to.h>
 #include <asm/thread_info.h>
 
+unsigned long gp_in_global __asm__("gp");
+
 extern asmlinkage void ret_from_fork(void);
 extern asmlinkage void ret_from_kernel_thread(void);
 
@@ -107,9 +109,8 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
        /* p->thread holds context to be restored by __switch_to() */
        if (unlikely(p->flags & PF_KTHREAD)) {
                /* Kernel thread */
-               const register unsigned long gp __asm__ ("gp");
                memset(childregs, 0, sizeof(struct pt_regs));
-               childregs->gp = gp;
+               childregs->gp = gp_in_global;
                /* Supervisor/Machine, irqs on: */
                childregs->status = SR_PP | SR_PIE;
 
index 0940681d2f682d4bbda28401f8ec7b24d69685e5..02087fe539c61514b6e276029231e717b31126b6 100644 (file)
@@ -19,6 +19,8 @@ struct stackframe {
        unsigned long ra;
 };
 
+register unsigned long sp_in_global __asm__("sp");
+
 void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                             bool (*fn)(unsigned long, void *), void *arg)
 {
@@ -29,7 +31,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                sp = user_stack_pointer(regs);
                pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
-               const register unsigned long current_sp __asm__ ("sp");
+               const register unsigned long current_sp = sp_in_global;
                fp = (unsigned long)__builtin_frame_address(0);
                sp = current_sp;
                pc = (unsigned long)walk_stackframe;
@@ -73,8 +75,7 @@ static void notrace walk_stackframe(struct task_struct *task,
                sp = user_stack_pointer(regs);
                pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
-               const register unsigned long current_sp __asm__ ("sp");
-               sp = current_sp;
+               sp = sp_in_global;
                pc = (unsigned long)walk_stackframe;
        } else {
                /* task blocked in __switch_to */