MIPS: jump_label: Use compact branches for >= r6
authorPaul Burton <paul.burton@mips.com>
Fri, 5 Apr 2019 22:50:36 +0000 (22:50 +0000)
committerPaul Burton <paul.burton@mips.com>
Tue, 9 Apr 2019 23:21:30 +0000 (16:21 -0700)
MIPSr6 introduced compact branches which have no delay slots. Make use
of them for jump labels in order to avoid the need for a nop to fill the
branch or jump delay slot, saving 4 bytes of code for each static branch.

Signed-off-by: Paul Burton <paul.burton@mips.com>
Cc: linux-mips@vger.kernel.org
arch/mips/include/asm/jump_label.h
arch/mips/kernel/jump_label.c

index df04449b261b0b24ddec2b90f065278f8a0322dc..3185fd3220ec217d73d320a710f7bd2c5902b757 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <asm/isa-rev.h>
 
 #define JUMP_LABEL_NOP_SIZE 4
 
 #endif
 
 #ifdef CONFIG_CPU_MICROMIPS
-#define B_INSN "b32"
+# define B_INSN "b32"
+# define J_INSN "j32"
+#elif MIPS_ISA_REV >= 6
+# define B_INSN "bc"
+# define J_INSN "bc"
 #else
-#define B_INSN "b"
+# define B_INSN "b"
+# define J_INSN "j"
 #endif
 
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
@@ -42,7 +48,7 @@ l_yes:
 
 static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
 {
-       asm_volatile_goto("1:\tj %l[l_yes]\n\t"
+       asm_volatile_goto("1:\t" J_INSN " %l[l_yes]\n\t"
                ".pushsection __jump_table,  \"aw\"\n\t"
                WORD_INSN " 1b, %l[l_yes], %0\n\t"
                ".popsection\n\t"
index ab943927f97ab20271d3fb255c36e4dc14f5fcc7..662c8db9f45ba96bc3caeb3126aaa2f102f27ae5 100644 (file)
@@ -40,18 +40,38 @@ void arch_jump_label_transform(struct jump_entry *e,
 {
        union mips_instruction *insn_p;
        union mips_instruction insn;
+       long offset;
 
        insn_p = (union mips_instruction *)msk_isa16_mode(e->code);
 
-       /* Jump only works within an aligned region its delay slot is in. */
-       BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK));
-
        /* Target must have the right alignment and ISA must be preserved. */
        BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
 
        if (type == JUMP_LABEL_JMP) {
-               insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
-               insn.j_format.target = e->target >> J_RANGE_SHIFT;
+               if (!IS_ENABLED(CONFIG_CPU_MICROMIPS) && MIPS_ISA_REV >= 6) {
+                       offset = e->target - ((unsigned long)insn_p + 4);
+                       offset >>= 2;
+
+                       /*
+                        * The branch offset must fit in the instruction's 26
+                        * bit field.
+                        */
+                       WARN_ON((offset >= BIT(25)) ||
+                               (offset < -(long)BIT(25)));
+
+                       insn.j_format.opcode = bc6_op;
+                       insn.j_format.target = offset;
+               } else {
+                       /*
+                        * Jump only works within an aligned region its delay
+                        * slot is in.
+                        */
+                       WARN_ON((e->target & ~J_RANGE_MASK) !=
+                               ((e->code + 4) & ~J_RANGE_MASK));
+
+                       insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
+                       insn.j_format.target = e->target >> J_RANGE_SHIFT;
+               }
        } else {
                insn.word = 0; /* nop */
        }