summaryrefslogtreecommitdiff
path: root/gcc/config/mn10300/mn10300.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/mn10300/mn10300.c')
-rw-r--r--gcc/config/mn10300/mn10300.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index bb14b4c9023..e4ef4bffe8b 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -44,6 +44,10 @@ Boston, MA 02111-1307, USA. */
#include "target.h"
#include "target-def.h"
+/* This is used by GOTaddr2picreg to uniquely identify
+ UNSPEC_INT_LABELs. */
+int mn10300_unspec_int_label_counter;
+
/* The size of the callee register save area. Right now we save everything
on entry since it costs us nothing in code size. It does cost us from a
speed standpoint, so we want to optimize this sooner or later. */
@@ -75,6 +79,10 @@ static void mn10300_file_start PARAMS ((void));
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info
+
+static void mn10300_encode_section_info (tree, rtx, int);
struct gcc_target targetm = TARGET_INITIALIZER;
static void
@@ -410,6 +418,7 @@ print_operand (file, x, code)
case CONST:
case LABEL_REF:
case CODE_LABEL:
+ case UNSPEC:
print_operand_address (file, x);
break;
default:
@@ -881,6 +890,24 @@ expand_prologue ()
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (-size)));
+ if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
+ {
+ rtx insn = get_last_insn ();
+ rtx last = emit_insn (gen_GOTaddr2picreg ());
+
+ /* Mark these insns as possibly dead. Sometimes, flow2 may
+ delete all uses of the PIC register. In this case, let it
+ delete the initialization too. */
+ do
+ {
+ insn = NEXT_INSN (insn);
+
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
+ const0_rtx,
+ REG_NOTES (insn));
+ }
+ while (insn != last);
+ }
}
void
@@ -1269,6 +1296,9 @@ call_address_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
+ if (flag_pic)
+ return (EXTRA_CONSTRAINT (op, 'S') || GET_CODE (op) == REG);
+
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
}
@@ -1756,6 +1786,9 @@ legitimize_address (x, oldx, mode)
rtx oldx ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
+ if (flag_pic && ! legitimate_pic_operand_p (x))
+ x = legitimize_pic_address (oldx, NULL_RTX);
+
/* Uh-oh. We might have an address for x[n-100000]. This needs
special handling to avoid creating an indexed memory address
with x-100000 as the base. */
@@ -1786,6 +1819,75 @@ legitimize_address (x, oldx, mode)
return x;
}
+/* Convert a non-PIC address in `orig' to a PIC address using @GOT or
+ @GOTOFF in `reg'. */
+rtx
+legitimize_pic_address (orig, reg)
+ rtx orig;
+ rtx reg;
+{
+ if (GET_CODE (orig) == LABEL_REF
+ || (GET_CODE (orig) == SYMBOL_REF
+ && (CONSTANT_POOL_ADDRESS_P (orig)
+ || ! MN10300_GLOBAL_P (orig))))
+ {
+ if (reg == 0)
+ reg = gen_reg_rtx (Pmode);
+
+ emit_insn (gen_symGOTOFF2reg (reg, orig));
+ return reg;
+ }
+ else if (GET_CODE (orig) == SYMBOL_REF)
+ {
+ if (reg == 0)
+ reg = gen_reg_rtx (Pmode);
+
+ emit_insn (gen_symGOT2reg (reg, orig));
+ return reg;
+ }
+ return orig;
+}
+
+/* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol
+ isn't protected by a PIC unspec; non-zero otherwise. */
+int
+legitimate_pic_operand_p (x)
+ rtx x;
+{
+ register const char *fmt;
+ register int i;
+
+ if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
+ return 0;
+
+ if (GET_CODE (x) == UNSPEC
+ && (XINT (x, 1) == UNSPEC_PIC
+ || XINT (x, 1) == UNSPEC_GOT
+ || XINT (x, 1) == UNSPEC_GOTOFF
+ || XINT (x, 1) == UNSPEC_PLT))
+ return 1;
+
+ if (GET_CODE (x) == QUEUED)
+ return legitimate_pic_operand_p (QUEUED_VAR (x));
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ register int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (! legitimate_pic_operand_p (XVECEXP (x, i, j)))
+ return 0;
+ }
+ else if (fmt[i] == 'e' && ! legitimate_pic_operand_p (XEXP (x, i)))
+ return 0;
+ }
+
+ return 1;
+}
+
static int
mn10300_address_cost_1 (x, unsig)
rtx x;
@@ -1973,3 +2075,23 @@ mn10300_wide_const_load_uses_clr (operands)
return val[0] == 0 || val[1] == 0;
}
+/* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we
+ may access it using GOTOFF instead of GOT. */
+
+static void
+mn10300_encode_section_info (decl, rtl, first)
+ tree decl;
+ rtx rtl;
+ int first;
+{
+ rtx symbol;
+
+ if (GET_CODE (rtl) != MEM)
+ return;
+ symbol = XEXP (rtl, 0);
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return;
+
+ if (flag_pic)
+ SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl);
+}