aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDJ Delorie <dj@redhat.com>2010-06-25 23:30:19 -0400
committerDJ Delorie <dj@gcc.gnu.org>2010-06-25 23:30:19 -0400
commitf6052f8680a5510f3f29c51fb69dd2ec3765925a (patch)
tree029a9ae4281f830a057e8a006a023187ac8c6199
parent19bbf2c4b8041b1ecb367187fe2555243a70d341 (diff)
downloadgcc-f6052f8680a5510f3f29c51fb69dd2ec3765925a.zip
gcc-f6052f8680a5510f3f29c51fb69dd2ec3765925a.tar.gz
gcc-f6052f8680a5510f3f29c51fb69dd2ec3765925a.tar.bz2
m32c-protos.h (m32c_note_pragma_address): Declare.
* config/m32c/m32c-protos.h (m32c_note_pragma_address): Declare. (m32c_output_aligned_common): Likewise. * config/m32c/m32c.h (ASM_OUTPUT_ALIGNED_DECL_COMMON): New. (ASM_OUTPUT_ALIGNED_DECL_LOCAL): New. * config/m32c/m32c-pragma.c (m32c_pragma_address): New. (m32c_register_pragmas): Register it. * config/m32c/m32c.c (m32c_get_pragma_address): New. (m32c_insert_attributes): Set #pragma address decls volatile. (pragma_entry_eq): New. (pragma_entry_hash): New. (m32c_note_pragma_address): New. (m32c_get_pragma_address): New. (m32c_output_aligned_common): New. * doc/extend.texi: Document the new pragma. * config/m32c/m32c.c (m32c_illegal_subreg_p): Reject illegal MEMs also. * config/m32c/predicates.md (m32c_any_operand): Check the code instead of memory_operand so as to allow matching volatile MEMs. (m32c_nonimmediate_operand): Likewise. (mra_operand): Allow volatiles. From-SVN: r161425
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/config/m32c/m32c-pragma.c38
-rw-r--r--gcc/config/m32c/m32c-protos.h3
-rw-r--r--gcc/config/m32c/m32c.c113
-rw-r--r--gcc/config/m32c/m32c.h7
-rw-r--r--gcc/config/m32c/predicates.md10
-rw-r--r--gcc/doc/extend.texi17
7 files changed, 206 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5b08e5d..797f74d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,27 @@
+2010-06-25 DJ Delorie <dj@redhat.com>
+
+ * config/m32c/m32c-protos.h (m32c_note_pragma_address): Declare.
+ (m32c_output_aligned_common): Likewise.
+ * config/m32c/m32c.h (ASM_OUTPUT_ALIGNED_DECL_COMMON): New.
+ (ASM_OUTPUT_ALIGNED_DECL_LOCAL): New.
+ * config/m32c/m32c-pragma.c (m32c_pragma_address): New.
+ (m32c_register_pragmas): Register it.
+ * config/m32c/m32c.c (m32c_get_pragma_address): New.
+ (m32c_insert_attributes): Set #pragma address decls volatile.
+ (pragma_entry_eq): New.
+ (pragma_entry_hash): New.
+ (m32c_note_pragma_address): New.
+ (m32c_get_pragma_address): New.
+ (m32c_output_aligned_common): New.
+ * doc/extend.texi: Document the new pragma.
+
+ * config/m32c/m32c.c (m32c_illegal_subreg_p): Reject illegal MEMs
+ also.
+ * config/m32c/predicates.md (m32c_any_operand): Check the code
+ instead of memory_operand so as to allow matching volatile MEMs.
+ (m32c_nonimmediate_operand): Likewise.
+ (mra_operand): Allow volatiles.
+
2010-06-25 Alexandre Oliva <aoliva@redhat.com>
PR debug/44610
diff --git a/gcc/config/m32c/m32c-pragma.c b/gcc/config/m32c/m32c-pragma.c
index 49fe023..b576152 100644
--- a/gcc/config/m32c/m32c-pragma.c
+++ b/gcc/config/m32c/m32c-pragma.c
@@ -87,9 +87,47 @@ m32c_pragma_memregs (cpp_reader * reader ATTRIBUTE_UNUSED)
error ("#pragma GCC memregs takes a number [0..16]");
}
+/* Implements the "pragma ADDRESS" pragma. This pragma takes a
+ variable name and an address, and arranges for that variable to be
+ "at" that address. The variable is also made volatile. */
+static void
+m32c_pragma_address (cpp_reader * reader ATTRIBUTE_UNUSED)
+{
+ /* on off */
+ tree var, addr;
+ enum cpp_ttype type;
+ const char *var_str;
+
+ type = pragma_lex (&var);
+ if (type == CPP_NAME)
+ {
+ var_str = IDENTIFIER_POINTER (var);
+
+ type = pragma_lex (&addr);
+ if (type == CPP_NUMBER)
+ {
+ if (var != error_mark_node)
+ {
+ unsigned uaddr = tree_low_cst (addr, 1);
+ m32c_note_pragma_address (IDENTIFIER_POINTER (var), uaddr);
+ }
+
+ type = pragma_lex (&var);
+ if (type != CPP_EOF)
+ {
+ error ("junk at end of #pragma ADDRESS");
+ }
+ return;
+ }
+ }
+ error ("malformed #pragma ADDRESS variable address");
+}
+
/* Implements REGISTER_TARGET_PRAGMAS. */
void
m32c_register_pragmas (void)
{
c_register_pragma ("GCC", "memregs", m32c_pragma_memregs);
+ c_register_pragma (NULL, "ADDRESS", m32c_pragma_address);
+ c_register_pragma (NULL, "address", m32c_pragma_address);
}
diff --git a/gcc/config/m32c/m32c-protos.h b/gcc/config/m32c/m32c-protos.h
index 42b92fe..89231fc 100644
--- a/gcc/config/m32c/m32c-protos.h
+++ b/gcc/config/m32c/m32c-protos.h
@@ -42,6 +42,7 @@ int m32c_print_operand_punct_valid_p (int);
int m32c_push_rounding (int);
int m32c_reg_class_from_constraint (char, const char *);
void m32c_register_pragmas (void);
+void m32c_note_pragma_address (const char *, unsigned);
int m32c_regno_ok_for_base_p (int);
int m32c_trampoline_alignment (void);
int m32c_trampoline_size (void);
@@ -104,6 +105,8 @@ tree m32c_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
void m32c_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
bool m32c_promote_function_return (const_tree);
int m32c_special_page_vector_p (tree);
+void m32c_output_aligned_common (FILE *, tree, const char *,
+ int, int, int);
#endif
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;
diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h
index 85dc2d1..a98005c 100644
--- a/gcc/config/m32c/m32c.h
+++ b/gcc/config/m32c/m32c.h
@@ -644,6 +644,13 @@ typedef struct m32c_cumulative_args
#define ASM_OUTPUT_REG_PUSH(S,R) m32c_output_reg_push (S, R)
#define ASM_OUTPUT_REG_POP(S,R) m32c_output_reg_pop (S, R)
+#define ASM_OUTPUT_ALIGNED_DECL_COMMON(STREAM, DECL, NAME, SIZE, ALIGNMENT) \
+ m32c_output_aligned_common (STREAM, DECL, NAME, SIZE, ALIGNMENT, 1)
+
+#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGNMENT) \
+ m32c_output_aligned_common (STREAM, DECL, NAME, SIZE, ALIGNMENT, 0)
+
+
/* Output of Dispatch Tables */
#define ASM_OUTPUT_ADDR_VEC_ELT(S,V) \
diff --git a/gcc/config/m32c/predicates.md b/gcc/config/m32c/predicates.md
index 321debf..98a1c16 100644
--- a/gcc/config/m32c/predicates.md
+++ b/gcc/config/m32c/predicates.md
@@ -26,7 +26,7 @@
(define_predicate "m32c_any_operand"
(ior (match_operand 0 "general_operand")
- (match_operand 1 "memory_operand"))
+ (match_code "mem,const_int,const_double"))
{
return ! m32c_illegal_subreg_p (op);
}
@@ -36,7 +36,11 @@
(define_predicate "m32c_nonimmediate_operand"
(ior (match_operand 0 "nonimmediate_operand")
- (match_operand 1 "memory_operand")))
+ (match_code "mem"))
+ {
+ return ! m32c_illegal_subreg_p (op);
+ }
+)
; TRUE if the operand is a pseudo-register.
(define_predicate "m32c_pseudo"
@@ -135,7 +139,7 @@
; Likewise, plus TRUE for memory references.
(define_predicate "mra_operand"
- (and (and (match_operand 0 "nonimmediate_operand" "")
+ (and (and (match_operand 0 "m32c_nonimmediate_operand" "")
(not (match_operand 1 "cr_operand" "")))
(not (match_operand 2 "m32c_wide_subreg" ""))))
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 795b6bf..86de226 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12266,7 +12266,7 @@ subsequent functions.
@subsection M32C Pragmas
@table @code
-@item memregs @var{number}
+@item GCC memregs @var{number}
@cindex pragma, memregs
Overrides the command-line option @code{-memregs=} for the current
file. Use with care! This pragma must be before any function in the
@@ -12275,6 +12275,21 @@ make them incompatible. This pragma is useful when a
performance-critical function uses a memreg for temporary values,
as it may allow you to reduce the number of memregs used.
+@item ADDRESS @var{name} @var{address}
+@cindex pragma, address
+For any declared symbols matching @var{name}, this does three things
+to that symbol: it forces the symbol to be located at the given
+address (a number), it forces the symbol to be volatile, and it
+changes the symbol's scope to be static. This pragma exists for
+compatibility with other compilers, but note that the common
+@code{1234H} numeric syntax is not supported (use @code{0x1234}
+instead). Example:
+
+@example
+#pragma ADDRESS port3 0x103
+char port3;
+@end example
+
@end table
@node MeP Pragmas