aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/m32c/m32c.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/m32c/m32c.c')
-rw-r--r--gcc/config/m32c/m32c.c113
1 files changed, 111 insertions, 2 deletions
diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c
index 3280d14..443325f 100644
--- a/gcc/config/m32c/m32c.c
+++ b/gcc/config/m32c/m32c.c
@@ -83,6 +83,9 @@ static int need_to_save (int);
static rtx m32c_function_value (const_tree, const_tree, bool);
static rtx m32c_libcall_value (enum machine_mode, const_rtx);
+/* Returns true if an address is specified, else false. */
+static bool m32c_get_pragma_address (const char *varname, unsigned *addr);
+
int current_function_special_page_vector (rtx);
#define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0)
@@ -2929,7 +2932,107 @@ static void
m32c_insert_attributes (tree node ATTRIBUTE_UNUSED,
tree * attr_ptr ATTRIBUTE_UNUSED)
{
- /* Nothing to do here. */
+ unsigned addr;
+ /* See if we need to make #pragma address variables volatile. */
+
+ if (TREE_CODE (node) == VAR_DECL)
+ {
+ char *name = IDENTIFIER_POINTER (DECL_NAME (node));
+ if (m32c_get_pragma_address (name, &addr))
+ {
+ TREE_THIS_VOLATILE (node) = true;
+ }
+ }
+}
+
+
+struct GTY(()) pragma_entry {
+ const char *varname;
+ unsigned address;
+};
+typedef struct pragma_entry pragma_entry;
+
+/* Hash table of pragma info. */
+static GTY((param_is (pragma_entry))) htab_t pragma_htab;
+
+static int
+pragma_entry_eq (const void *p1, const void *p2)
+{
+ const pragma_entry *old = (const pragma_entry *) p1;
+ const char *new_name = (const char *) p2;
+
+ return strcmp (old->varname, new_name) == 0;
+}
+
+static hashval_t
+pragma_entry_hash (const void *p)
+{
+ const pragma_entry *old = (const pragma_entry *) p;
+ return htab_hash_string (old->varname);
+}
+
+void
+m32c_note_pragma_address (const char *varname, unsigned address)
+{
+ pragma_entry **slot;
+
+ if (!pragma_htab)
+ pragma_htab = htab_create_ggc (31, pragma_entry_hash,
+ pragma_entry_eq, NULL);
+
+ slot = (pragma_entry **)
+ htab_find_slot_with_hash (pragma_htab, varname,
+ htab_hash_string (varname), INSERT);
+
+ if (!*slot)
+ {
+ *slot = ggc_alloc_pragma_entry ();
+ (*slot)->varname = ggc_strdup (varname);
+ }
+ (*slot)->address = address;
+}
+
+static bool
+m32c_get_pragma_address (const char *varname, unsigned *address)
+{
+ pragma_entry **slot;
+
+ if (!pragma_htab)
+ return false;
+
+ slot = (pragma_entry **)
+ htab_find_slot_with_hash (pragma_htab, varname,
+ htab_hash_string (varname), NO_INSERT);
+ if (slot && *slot)
+ {
+ *address = (*slot)->address;
+ return true;
+ }
+ return false;
+}
+
+void
+m32c_output_aligned_common (FILE *stream, tree decl, const char *name,
+ int size, int align, int global)
+{
+ unsigned address;
+
+ if (m32c_get_pragma_address (name, &address))
+ {
+ /* We never output these as global. */
+ assemble_name (stream, name);
+ fprintf (stream, " = 0x%04x\n", address);
+ return;
+ }
+ if (!global)
+ {
+ fprintf (stream, "\t.local\t");
+ assemble_name (stream, name);
+ fprintf (stream, "\n");
+ }
+ fprintf (stream, "\t.comm\t");
+ assemble_name (stream, name);
+ fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT);
}
/* Predicates */
@@ -2960,7 +3063,7 @@ static const struct {
};
/* Returns TRUE if OP is a subreg of a hard reg which we don't
- support. */
+ support. We also bail on MEMs with illegal addresses. */
bool
m32c_illegal_subreg_p (rtx op)
{
@@ -2968,6 +3071,12 @@ m32c_illegal_subreg_p (rtx op)
unsigned int i;
int src_mode, dest_mode;
+ if (GET_CODE (op) == MEM
+ && ! m32c_legitimate_address_p (Pmode, XEXP (op, 0), false))
+ {
+ return true;
+ }
+
if (GET_CODE (op) != SUBREG)
return false;