Commit 9b6584e3 authored by Paul Burton's avatar Paul Burton

MIPS: jump_label: Use compact branches for >= r6

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: default avatarPaul Burton <paul.burton@mips.com>
Cc: linux-mips@vger.kernel.org
parent c838b580
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/types.h> #include <linux/types.h>
#include <asm/isa-rev.h>
#define JUMP_LABEL_NOP_SIZE 4 #define JUMP_LABEL_NOP_SIZE 4
...@@ -21,9 +22,14 @@ ...@@ -21,9 +22,14 @@
#endif #endif
#ifdef CONFIG_CPU_MICROMIPS #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 #else
#define B_INSN "b" # define B_INSN "b"
# define J_INSN "j"
#endif #endif
static __always_inline bool arch_static_branch(struct static_key *key, bool branch) static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
...@@ -42,7 +48,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran ...@@ -42,7 +48,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) 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" ".pushsection __jump_table, \"aw\"\n\t"
WORD_INSN " 1b, %l[l_yes], %0\n\t" WORD_INSN " 1b, %l[l_yes], %0\n\t"
".popsection\n\t" ".popsection\n\t"
......
...@@ -40,18 +40,38 @@ void arch_jump_label_transform(struct jump_entry *e, ...@@ -40,18 +40,38 @@ void arch_jump_label_transform(struct jump_entry *e,
{ {
union mips_instruction *insn_p; union mips_instruction *insn_p;
union mips_instruction insn; union mips_instruction insn;
long offset;
insn_p = (union mips_instruction *)msk_isa16_mode(e->code); 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. */ /* Target must have the right alignment and ISA must be preserved. */
BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT); BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
if (type == JUMP_LABEL_JMP) { if (type == JUMP_LABEL_JMP) {
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.opcode = J_ISA_BIT ? mm_j32_op : j_op;
insn.j_format.target = e->target >> J_RANGE_SHIFT; insn.j_format.target = e->target >> J_RANGE_SHIFT;
}
} else { } else {
insn.word = 0; /* nop */ insn.word = 0; /* nop */
} }
......
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