aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/cris/cris.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/cris/cris.c')
-rw-r--r--gcc-4.9/gcc/config/cris/cris.c120
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