forked from Minki/linux
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: Paul Burton <paul.burton@mips.com> Cc: linux-mips@vger.kernel.org
This commit is contained in:
parent
c838b580ca
commit
9b6584e35f
@ -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 @@
|
|||||||
#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 @@ l_yes:
|
|||||||
|
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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 */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user