diff options
author | Jinyang He <hejinyang@loongson.cn> | 2021-01-21 06:31:38 +0100 |
---|---|---|
committer | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 2021-01-25 12:21:23 +0100 |
commit | 50886234e846bbf2cbf14a86c727e5fc309fdf25 (patch) | |
tree | 5301ada42dc0d4e3e629819a177bb205632bfb82 /arch/mips | |
parent | MIPS: Fix get_frame_info() handing of function size (diff) | |
download | linux-50886234e846bbf2cbf14a86c727e5fc309fdf25.tar.xz linux-50886234e846bbf2cbf14a86c727e5fc309fdf25.zip |
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.c | 34 |
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)) { |