summaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorJinyang He <hejinyang@loongson.cn>2021-01-21 13:31:38 +0800
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>2021-01-25 12:21:23 +0100
commit50886234e846bbf2cbf14a86c727e5fc309fdf25 (patch)
tree5301ada42dc0d4e3e629819a177bb205632bfb82 /arch/mips
parent2d62f64bcc72ba45f73e58199f8e1b8cc5b67489 (diff)
downloadlinux-50886234e846bbf2cbf14a86c727e5fc309fdf25.tar.bz2
MIPS: Add is_jr_ra_ins() to end the loop early
For those leaf functions, they are likely to have no stack operations. Add is_jr_ra_ins() to determine whether jr ra has been touched before the frame_size is found. Without this patch, the get frame_size operation may be out of range and get the frame_size from the next nested function. There is no POOL32A format in uapi/asm/inst.h, so some bits here use the format of r_format instead. e.g. --------------------------------------------------------------------- | format | 31:26 | 25:21 | 20:16 | 15:6 | 5:0 | -----------------+---------+-------+-------+------------+------------ | pool32a_format | pool32a | rt | rs | jalrc | pool32axf | -----------------+---------+-------+-------+------------+------------ | r_format | opcode | rs | rt | rd:5, re:5 | func | --------------------------------------------------------------------- Signed-off-by: Jinyang He <hejinyang@loongson.cn> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/process.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 9bf993f29603..f94f291ee6c6 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -188,6 +188,36 @@ struct mips_frame_info {
#define J_TARGET(pc,target) \
(((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
+static inline int is_jr_ra_ins(union mips_instruction *ip)
+{
+#ifdef CONFIG_CPU_MICROMIPS
+ /*
+ * jr16 ra
+ * jr ra
+ */
+ if (mm_insn_16bit(ip->word >> 16)) {
+ if (ip->mm16_r5_format.opcode == mm_pool16c_op &&
+ ip->mm16_r5_format.rt == mm_jr16_op &&
+ ip->mm16_r5_format.imm == 31)
+ return 1;
+ return 0;
+ }
+
+ if (ip->r_format.opcode == mm_pool32a_op &&
+ ip->r_format.func == mm_pool32axf_op &&
+ ((ip->u_format.uimmediate >> 6) & GENMASK(9, 0)) == mm_jalr_op &&
+ ip->r_format.rt == 31)
+ return 1;
+ return 0;
+#else
+ if (ip->r_format.opcode == spec_op &&
+ ip->r_format.func == jr_op &&
+ ip->r_format.rs == 31)
+ return 1;
+ return 0;
+#endif
+}
+
static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
{
#ifdef CONFIG_CPU_MICROMIPS
@@ -400,7 +430,9 @@ static int get_frame_info(struct mips_frame_info *info)
last_insn_size = 4;
}
- if (!info->frame_size) {
+ if (is_jr_ra_ins(ip)) {
+ break;
+ } else if (!info->frame_size) {
is_sp_move_ins(&insn, &info->frame_size);
continue;
} else if (!saw_jump && is_jump_ins(ip)) {