diff options
Diffstat (limited to 'gcc-4.9/gcc/config/cris/cris.c')
-rw-r--r-- | gcc-4.9/gcc/config/cris/cris.c | 120 |
1 files changed, 91 insertions, 29 deletions
diff --git a/gcc-4.9/gcc/config/cris/cris.c b/gcc-4.9/gcc/config/cris/cris.c index 209f127a6..c15139f51 100644 --- a/gcc-4.9/gcc/config/cris/cris.c +++ b/gcc-4.9/gcc/config/cris/cris.c @@ -147,6 +147,7 @@ static rtx cris_function_incoming_arg (cumulative_args_t, static void cris_function_arg_advance (cumulative_args_t, enum machine_mode, const_tree, bool); static tree cris_md_asm_clobbers (tree, tree, tree); +static bool cris_cannot_force_const_mem (enum machine_mode, rtx); static void cris_option_override (void); @@ -214,6 +215,9 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION; #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P cris_legitimate_address_p +#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P cris_legitimate_constant_p + #undef TARGET_PREFERRED_RELOAD_CLASS #define TARGET_PREFERRED_RELOAD_CLASS cris_preferred_reload_class @@ -248,6 +252,10 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION; #define TARGET_FUNCTION_ARG_ADVANCE cris_function_arg_advance #undef TARGET_MD_ASM_CLOBBERS #define TARGET_MD_ASM_CLOBBERS cris_md_asm_clobbers + +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM cris_cannot_force_const_mem + #undef TARGET_FRAME_POINTER_REQUIRED #define TARGET_FRAME_POINTER_REQUIRED cris_frame_pointer_required @@ -506,6 +514,21 @@ cris_cfun_uses_pic_table (void) return crtl->uses_pic_offset_table; } +/* Worker function for TARGET_CANNOT_FORCE_CONST_MEM. + We can't put PIC addresses in the constant pool, not even the ones that + can be reached as pc-relative as we can't tell when or how to do that. */ + +static bool +cris_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + enum cris_symbol_type t = cris_symbol_type_of (x); + + return + t == cris_unspec + || t == cris_got_symbol + || t == cris_rel_symbol; +} + /* Given an rtx, return the text string corresponding to the CODE of X. Intended for use in the assembly language output section of a define_insn. */ @@ -601,7 +624,7 @@ cris_print_index (rtx index, FILE *file) if (REG_P (index)) fprintf (file, "$%s.b", reg_names[REGNO (index)]); - else if (CONSTANT_P (index)) + else if (CRIS_CONSTANT_P (index)) cris_output_addr_const (file, index); else if (GET_CODE (index) == MULT) { @@ -1041,7 +1064,7 @@ cris_print_operand (FILE *file, rtx x, int code) /* If this is a GOT symbol, force it to be emitted as :GOT and :GOTPLT regardless of -fpic (i.e. not as :GOT16, :GOTPLT16). Avoid making this too much of a special case. */ - if (flag_pic == 1 && CONSTANT_P (operand)) + if (flag_pic == 1 && CRIS_CONSTANT_P (operand)) { int flag_pic_save = flag_pic; @@ -1161,7 +1184,7 @@ cris_print_operand (FILE *file, rtx x, int code) default: /* No need to handle all strange variants, let output_addr_const do it for us. */ - if (CONSTANT_P (operand)) + if (CRIS_CONSTANT_P (operand)) { cris_output_addr_const (file, operand); return; @@ -1358,7 +1381,7 @@ reg_ok_for_index_p (const_rtx x, bool strict) bool cris_constant_index_p (const_rtx x) { - return (CONSTANT_P (x) && (!flag_pic || cris_valid_pic_const (x, true))); + return (CRIS_CONSTANT_P (x) && (!flag_pic || cris_valid_pic_const (x, true))); } /* True if X is a valid base register. */ @@ -1467,6 +1490,29 @@ cris_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) return false; } +/* Worker function for TARGET_LEGITIMATE_CONSTANT_P. We have to handle + PIC constants that aren't legitimized. FIXME: there used to be a + guarantee that the target LEGITIMATE_CONSTANT_P didn't have to handle + PIC constants, but no more (4.7 era); testcase: glibc init-first.c. + While that may be seen as a bug, that guarantee seems a wart by design, + so don't bother; fix the documentation instead. */ + +bool +cris_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + enum cris_symbol_type t; + + if (flag_pic) + return LEGITIMATE_PIC_OPERAND_P (x); + + t = cris_symbol_type_of (x); + + return + t == cris_no_symbol + || t == cris_offsettable_symbol + || t == cris_unspec; +} + /* Worker function for LEGITIMIZE_RELOAD_ADDRESS. */ bool @@ -2214,7 +2260,7 @@ cris_address_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED, return (2 + 2) / 2; /* A BDAP with some other constant is 2 bytes extra. */ - if (CONSTANT_P (tem2)) + if (CRIS_CONSTANT_P (tem2)) return (2 + 2 + 2) / 2; /* BDAP with something indirect should have a higher cost than @@ -2312,7 +2358,7 @@ cris_side_effect_mode_ok (enum rtx_code code, rtx *ops, return 0; /* Check allowed cases, like [r(+)?].[bwd] and const. */ - if (CONSTANT_P (val_rtx)) + if (CRIS_CONSTANT_P (val_rtx)) return 1; if (MEM_P (val_rtx) @@ -2464,32 +2510,34 @@ cris_valid_pic_const (const_rtx x, bool any_operand) gcc_unreachable (); } - return cris_pic_symbol_type_of (x) == cris_no_symbol; + return cris_symbol_type_of (x) == cris_no_symbol; } -/* Helper function to find the right PIC-type symbol to generate, +/* Helper function to find the right symbol-type to generate, given the original (non-PIC) representation. */ -enum cris_pic_symbol_type -cris_pic_symbol_type_of (const_rtx x) +enum cris_symbol_type +cris_symbol_type_of (const_rtx x) { switch (GET_CODE (x)) { case SYMBOL_REF: - return SYMBOL_REF_LOCAL_P (x) - ? cris_rel_symbol : cris_got_symbol; + return flag_pic + ? (SYMBOL_REF_LOCAL_P (x) + ? cris_rel_symbol : cris_got_symbol) + : cris_offsettable_symbol; case LABEL_REF: - return cris_rel_symbol; + return flag_pic ? cris_rel_symbol : cris_offsettable_symbol; case CONST: - return cris_pic_symbol_type_of (XEXP (x, 0)); + return cris_symbol_type_of (XEXP (x, 0)); case PLUS: case MINUS: { - enum cris_pic_symbol_type t1 = cris_pic_symbol_type_of (XEXP (x, 0)); - enum cris_pic_symbol_type t2 = cris_pic_symbol_type_of (XEXP (x, 1)); + enum cris_symbol_type t1 = cris_symbol_type_of (XEXP (x, 0)); + enum cris_symbol_type t2 = cris_symbol_type_of (XEXP (x, 1)); gcc_assert (t1 == cris_no_symbol || t2 == cris_no_symbol); @@ -2504,9 +2552,7 @@ cris_pic_symbol_type_of (const_rtx x) return cris_no_symbol; case UNSPEC: - /* Likely an offsettability-test attempting to add a constant to - a GOTREAD symbol, which can't be handled. */ - return cris_invalid_pic_symbol; + return cris_unspec; default: fatal_insn ("unrecognized supposed constant", x); @@ -3714,19 +3760,19 @@ cris_emit_movem_store (rtx dest, rtx nregs_rtx, int increment, /* Worker function for expanding the address for PIC function calls. */ void -cris_expand_pic_call_address (rtx *opp) +cris_expand_pic_call_address (rtx *opp, rtx *markerp) { rtx op = *opp; - gcc_assert (MEM_P (op)); + gcc_assert (flag_pic && MEM_P (op)); op = XEXP (op, 0); /* It might be that code can be generated that jumps to 0 (or to a specific address). Don't die on that. (There is a testcase.) */ - if (CONSTANT_ADDRESS_P (op) && !CONST_INT_P (op)) + if (CONSTANT_P (op) && !CONST_INT_P (op)) { - enum cris_pic_symbol_type t = cris_pic_symbol_type_of (op); + enum cris_symbol_type t = cris_symbol_type_of (op); CRIS_ASSERT (can_create_pseudo_p ()); @@ -3752,18 +3798,21 @@ cris_expand_pic_call_address (rtx *opp) } else op = force_reg (Pmode, op); + + /* A local call. */ + *markerp = const0_rtx; } else if (t == cris_got_symbol) { if (TARGET_AVOID_GOTPLT) { /* Change a "jsr sym" into (allocate register rM, rO) - "move.d (const (unspec [sym rPIC] CRIS_UNSPEC_PLT_GOTREL)),rM" + "move.d (const (unspec [sym] CRIS_UNSPEC_PLT_GOTREL)),rM" "add.d rPIC,rM,rO", "jsr rO" for pre-v32 and - "jsr (const (unspec [sym rPIC] CRIS_UNSPEC_PLT_PCREL))" + "jsr (const (unspec [sym] CRIS_UNSPEC_PLT_PCREL))" for v32. */ rtx tem, rm, ro; - gcc_assert (can_create_pseudo_p ()); + crtl->uses_pic_offset_table = 1; tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), TARGET_V32 @@ -3817,14 +3866,27 @@ cris_expand_pic_call_address (rtx *opp) MEM_NOTRAP_P (mem) = 1; op = mem; } + + /* We need to prepare this call to go through the PLT; we + need to make GOT available. */ + *markerp = pic_offset_table_rtx; } else - /* Can't possibly get a GOT-needing-fixup for a function-call, - right? */ + /* Can't possibly get anything else for a function-call, right? */ fatal_insn ("unidentifiable call op", op); - *opp = replace_equiv_address (*opp, op); + /* If the validizing variant is called, it will try to validize + the address as a valid any-operand constant, but as it's only + valid for calls and moves, it will fail and always be forced + into a register. */ + *opp = replace_equiv_address_nv (*opp, op); } + else + /* Can't tell what locality a call to a non-constant address has; + better make the GOT register alive at it. + FIXME: Can we see whether the register has known constant + contents? */ + *markerp = pic_offset_table_rtx; } /* Make sure operands are in the right order for an addsi3 insn as |