Skip to content

Commit

Permalink
MIPS: jump_label: Use compact branches for >= r6
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Paul Burton committed Apr 9, 2019
1 parent c838b58 commit 9b6584e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 8 deletions.
12 changes: 9 additions & 3 deletions arch/mips/include/asm/jump_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#ifndef __ASSEMBLY__

#include <linux/types.h>
#include <asm/isa-rev.h>

#define JUMP_LABEL_NOP_SIZE 4

Expand All @@ -21,9 +22,14 @@
#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)
Expand All @@ -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)
{
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"
Expand Down
30 changes: 25 additions & 5 deletions arch/mips/kernel/jump_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
}
Expand Down

0 comments on commit 9b6584e

Please sign in to comment.