diff options
author | Julian Brown <julian@codesourcery.com> | 2012-08-23 15:42:03 +0000 |
---|---|---|
committer | Sandra Loosemore <sandra@gcc.gnu.org> | 2012-08-23 11:42:03 -0400 |
commit | 545ca0f2785bd261c13392cb6191640282a73ee9 (patch) | |
tree | 2facdea4b5e6621f78227ef010d5ac4afd8e6332 /gcc/config | |
parent | a147b6d28fa9db1c7533d53e19837009f3f7fd05 (diff) | |
download | gcc-545ca0f2785bd261c13392cb6191640282a73ee9.zip gcc-545ca0f2785bd261c13392cb6191640282a73ee9.tar.gz gcc-545ca0f2785bd261c13392cb6191640282a73ee9.tar.bz2 |
2012-08-23 Julian Brown <julian@codesourcery.com>
Sandra Loosemore <sandra@codesourcery.com>
gcc/
* config/mips/mips.md
(UNSPEC_CASESI_DISPATCH): New.
(MIPS16_T_REGNUM): New constant.
(tablejump): Don't use for MIPS16_SHORT_JUMP_TABLES.
(casesi): New.
(casesi_internal_mips16_<mode>): New.
* config/mips/mips.c (mips16_split_long_branches): Adjust test
to ignore casesi jump tables.
* config/mips/mips.h (TARGET_MIPS16_SHORT_JUMP_TABLES): Update
comment.
(CASE_VECTOR_MODE): Use SImode unconditionally.
(CASE_VECTOR_SHORTEN_MODE): Define.
(ASM_OUTPUT_ADDR_DIFF_ELT): Output word-sized addr_diff_elts
when necessary for MIPS16_SHORT_JUMP_TABLES.
gcc/testsuite/
* gcc.target/mips/code-readable-1.c: Add -O to options.
Co-Authored-By: Sandra Loosemore <sandra@codesourcery.com>
From-SVN: r190625
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/mips/mips.c | 3 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 21 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 101 |
3 files changed, 112 insertions, 13 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 051f3b3..dc9f9cf 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -15575,7 +15575,8 @@ mips16_split_long_branches (void) for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) if (JUMP_P (insn) && USEFUL_INSN_P (insn) - && get_attr_length (insn) > 8) + && get_attr_length (insn) > 8 + && (any_condjump_p (insn) || any_uncondjump_p (insn))) { rtx old_label, new_label, temp, saved_temp; rtx target, jump, jump_sequence; diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 073c82e..9ff36b3 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -2330,13 +2330,18 @@ typedef struct mips_args { /* True if we're generating a form of MIPS16 code in which jump tables are stored in the text section and encoded as 16-bit PC-relative offsets. This is only possible when general text loads are allowed, - since the table access itself will be an "lh" instruction. */ -/* ??? 16-bit offsets can overflow in large functions. */ + since the table access itself will be an "lh" instruction. If the + PC-relative offsets grow too large, 32-bit offsets are used instead. */ #define TARGET_MIPS16_SHORT_JUMP_TABLES TARGET_MIPS16_TEXT_LOADS #define JUMP_TABLES_IN_TEXT_SECTION TARGET_MIPS16_SHORT_JUMP_TABLES -#define CASE_VECTOR_MODE (TARGET_MIPS16_SHORT_JUMP_TABLES ? HImode : ptr_mode) +#define CASE_VECTOR_MODE SImode + +/* Only use short offsets if their range will not overflow. */ +#define CASE_VECTOR_SHORTEN_MODE(MIN, MAX, BODY) \ + (TARGET_MIPS16_SHORT_JUMP_TABLES && ((MIN) >= -32768 && (MAX) < 32768) \ + ? HImode : SImode) #define CASE_VECTOR_PC_RELATIVE TARGET_MIPS16_SHORT_JUMP_TABLES @@ -2636,8 +2641,14 @@ while (0) #define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \ do { \ if (TARGET_MIPS16_SHORT_JUMP_TABLES) \ - fprintf (STREAM, "\t.half\t%sL%d-%sL%d\n", \ - LOCAL_LABEL_PREFIX, VALUE, LOCAL_LABEL_PREFIX, REL); \ + { \ + if (GET_MODE (BODY) == HImode) \ + fprintf (STREAM, "\t.half\t%sL%d-%sL%d\n", \ + LOCAL_LABEL_PREFIX, VALUE, LOCAL_LABEL_PREFIX, REL); \ + else \ + fprintf (STREAM, "\t.word\t%sL%d-%sL%d\n", \ + LOCAL_LABEL_PREFIX, VALUE, LOCAL_LABEL_PREFIX, REL); \ + } \ else if (TARGET_GPWORD) \ fprintf (STREAM, "\t%s\t%sL%d\n", \ ptr_mode == DImode ? ".gpdword" : ".gpword", \ 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, |