aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/mips/mips.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/mips/mips.md')
-rw-r--r--gcc/config/mips/mips.md101
1 files changed, 94 insertions, 7 deletions
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index ca89cc1..426a97c 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -134,10 +134,14 @@
;; Used in a call expression in place of args_size. It's present for PIC
;; indirect calls where it contains args_size and the function symbol.
UNSPEC_CALL_ATTR
+
+ ;; MIPS16 casesi jump table dispatch.
+ UNSPEC_CASESI_DISPATCH
])
(define_constants
[(TLS_GET_TP_REGNUM 3)
+ (MIPS16_T_REGNUM 24)
(PIC_FUNCTION_ADDR_REGNUM 25)
(RETURN_ADDR_REGNUM 31)
(CPRESTORE_SLOT_REGNUM 76)
@@ -5904,14 +5908,9 @@
[(set (pc)
(match_operand 0 "register_operand"))
(use (label_ref (match_operand 1 "")))]
- ""
+ "!TARGET_MIPS16_SHORT_JUMP_TABLES"
{
- if (TARGET_MIPS16_SHORT_JUMP_TABLES)
- operands[0] = expand_binop (Pmode, add_optab,
- convert_to_mode (Pmode, operands[0], false),
- gen_rtx_LABEL_REF (Pmode, operands[1]),
- 0, 0, OPTAB_WIDEN);
- else if (TARGET_GPWORD)
+ if (TARGET_GPWORD)
operands[0] = expand_binop (Pmode, add_optab, operands[0],
pic_offset_table_rtx, 0, 0, OPTAB_WIDEN);
else if (TARGET_RTP_PIC)
@@ -5937,6 +5936,94 @@
[(set_attr "type" "jump")
(set_attr "mode" "none")])
+;; For MIPS16, we don't know whether a given jump table will use short or
+;; word-sized offsets until late in compilation, when we are able to determine
+;; the sizes of the insns which comprise the containing function. This
+;; necessitates the use of the casesi rather than the tablejump pattern, since
+;; the latter tries to calculate the index of the offset to jump through early
+;; in compilation, i.e. at expand time, when nothing is known about the
+;; eventual function layout.
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "register_operand" "") ; index to jump on
+ (match_operand:SI 1 "const_int_operand" "") ; lower bound
+ (match_operand:SI 2 "const_int_operand" "") ; total range
+ (match_operand 3 "" "") ; table label
+ (match_operand 4 "" "")] ; out of range label
+ "TARGET_MIPS16_SHORT_JUMP_TABLES"
+{
+ if (operands[1] != const0_rtx)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ rtx offset = gen_int_mode (-INTVAL (operands[1]), SImode);
+
+ if (!arith_operand (offset, SImode))
+ offset = force_reg (SImode, offset);
+
+ emit_insn (gen_addsi3 (reg, operands[0], offset));
+ operands[0] = reg;
+ }
+
+ if (!arith_operand (operands[0], SImode))
+ operands[0] = force_reg (SImode, operands[0]);
+
+ operands[2] = GEN_INT (INTVAL (operands[2]) + 1);
+
+ emit_jump_insn (PMODE_INSN (gen_casesi_internal_mips16,
+ (operands[0], operands[2],
+ operands[3], operands[4])));
+
+ DONE;
+})
+
+(define_insn "casesi_internal_mips16_<mode>"
+ [(set (pc)
+ (if_then_else
+ (leu (match_operand:SI 0 "register_operand" "d")
+ (match_operand:SI 1 "arith_operand" "dI"))
+ (unspec:P
+ [(match_dup 0)
+ (label_ref (match_operand 2 "" ""))]
+ UNSPEC_CASESI_DISPATCH)
+ (label_ref (match_operand 3 "" ""))))
+ (clobber (match_scratch:P 4 "=d"))
+ (clobber (match_scratch:P 5 "=d"))
+ (clobber (reg:SI MIPS16_T_REGNUM))]
+ "TARGET_MIPS16_SHORT_JUMP_TABLES"
+{
+ rtx diff_vec = PATTERN (next_real_insn (operands[2]));
+
+ gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
+
+ output_asm_insn ("sltu\t%0, %1", operands);
+ output_asm_insn ("bteqz\t%3", operands);
+
+ switch (GET_MODE (diff_vec))
+ {
+ case HImode:
+ output_asm_insn ("sll\t%5, %0, 1", operands);
+ output_asm_insn ("la\t%4, %2", operands);
+ output_asm_insn ("<d>addu\t%5, %4, %5", operands);
+ output_asm_insn ("lh\t%5, 0(%5)", operands);
+ break;
+
+ case SImode:
+ output_asm_insn ("sll\t%5, %0, 2", operands);
+ output_asm_insn ("la\t%4, %2", operands);
+ output_asm_insn ("<d>addu\t%5, %4, %5", operands);
+ output_asm_insn ("lw\t%5, 0(%5)", operands);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ output_asm_insn ("addu\t%4, %4, %5", operands);
+
+ return "j\t%4";
+}
+ [(set_attr "length" "32")])
+
;; For TARGET_USE_GOT, we save the gp in the jmp_buf as well.
;; While it is possible to either pull it off the stack (in the
;; o32 case) or recalculate it given t9 and our target label,