diff options
Diffstat (limited to 'gcc/config/mips/mips.md')
-rw-r--r-- | gcc/config/mips/mips.md | 101 |
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, |