aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/branch.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/branch.c')
-rw-r--r--arch/mips/kernel/branch.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index f9cb13c56595..a1fd8786d716 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -399,6 +399,16 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs)
399 * @returns: -EFAULT on error and forces SIGBUS, and on success 399 * @returns: -EFAULT on error and forces SIGBUS, and on success
400 * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after 400 * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
401 * evaluating the branch. 401 * evaluating the branch.
402 *
403 * MIPS R6 Compact branches and forbidden slots:
404 * Compact branches do not throw exceptions because they do
405 * not have delay slots. The forbidden slot instruction ($PC+4)
406 * is only executed if the branch was not taken. Otherwise the
407 * forbidden slot is skipped entirely. This means that the
408 * only possible reason to be here because of a MIPS R6 compact
409 * branch instruction is that the forbidden slot has thrown one.
410 * In that case the branch was not taken, so the EPC can be safely
411 * set to EPC + 8.
402 */ 412 */
403int __compute_return_epc_for_insn(struct pt_regs *regs, 413int __compute_return_epc_for_insn(struct pt_regs *regs,
404 union mips_instruction insn) 414 union mips_instruction insn)
@@ -590,6 +600,27 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
590 if (NO_R6EMU) 600 if (NO_R6EMU)
591 goto sigill_r6; 601 goto sigill_r6;
592 case blez_op: 602 case blez_op:
603 /*
604 * Compact branches for R6 for the
605 * blez and blezl opcodes.
606 * BLEZ | rs = 0 | rt != 0 == BLEZALC
607 * BLEZ | rs = rt != 0 == BGEZALC
608 * BLEZ | rs != 0 | rt != 0 == BGEUC
609 * BLEZL | rs = 0 | rt != 0 == BLEZC
610 * BLEZL | rs = rt != 0 == BGEZC
611 * BLEZL | rs != 0 | rt != 0 == BGEC
612 *
613 * For real BLEZ{,L}, rt is always 0.
614 */
615
616 if (cpu_has_mips_r6 && insn.i_format.rt) {
617 if ((insn.i_format.opcode == blez_op) &&
618 ((!insn.i_format.rs && insn.i_format.rt) ||
619 (insn.i_format.rs == insn.i_format.rt)))
620 regs->regs[31] = epc + 4;
621 regs->cp0_epc += 8;
622 break;
623 }
593 /* rt field assumed to be zero */ 624 /* rt field assumed to be zero */
594 if ((long)regs->regs[insn.i_format.rs] <= 0) { 625 if ((long)regs->regs[insn.i_format.rs] <= 0) {
595 epc = epc + 4 + (insn.i_format.simmediate << 2); 626 epc = epc + 4 + (insn.i_format.simmediate << 2);