Patchwork [m32c] new pragma, optimize volatile bitops

login
register
mail settings
Submitter DJ Delorie
Date June 26, 2010, 3:30 a.m.
Message ID <201006260330.o5Q3UNAe032513@greed.delorie.com>
Download mbox | patch
Permalink /patch/57049/
State New
Headers show

Comments

DJ Delorie - June 26, 2010, 3:30 a.m.
This new pragma is intended to support Renesas's distributed sfr.h files,
which define the peripherals for each chip.  They use a syntax like this:

	#pragma ADDRESS p3 00E4H
	char p3;

The pragma makes "p3" static, volatile, and located at address 0xE4.

This patch adds most of that, with a few caveats:

* The 123H syntax isn't supported.  In theory, pragmas should have
  access to the low-level token data so they could parse these
  themselves, but gcc doesn't currently allow that.  I have a patch
  for libcpp to allow this syntax, but I don't know if it would be
  acceptable.

* The mechanism to tag all those variables as volatile doesn't work in
  C++ (at the moment?) because the insert_attribute hook isn't called.
  I don't know why.  The documentation says it should work.


The predicate changes allow us to do load/set/store for volatiles with a single
operation:

	or.b #0xe4, 0x80

general_operand() and memory_operand() sometimes reject volatile MEMs,
so I made my predicates allow them again.

Committed.


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.

Patch

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 161424)
+++ doc/extend.texi	(working copy)
@@ -12263,21 +12263,36 @@  subsequent functions.
 @end table
 
 @node M32C Pragmas
 @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
 file, and mixing different memregs values in different objects may
 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
 @subsection MeP Pragmas
 
 @table @code
Index: config/m32c/predicates.md
===================================================================
--- config/m32c/predicates.md	(revision 161424)
+++ config/m32c/predicates.md	(working copy)
@@ -23,23 +23,27 @@ 
 
 ; TRUE for any valid operand.  We do this because general_operand
 ; refuses to match volatile memory refs.
 
 (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);
   }
 )
 
 ; Likewise for nonimmediate_operand.
 
 (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"
   (ior (and (match_code "reg")
 	    (match_test "REGNO(op) >= FIRST_PSEUDO_REGISTER"))
        (and (match_code "subreg")
@@ -132,13 +136,13 @@ 
   (and (and (match_operand 0 "register_operand" "")
 	    (not (match_operand 1 "cr_operand" "")))
        (not (match_operand 2 "m32c_wide_subreg" ""))))
 
 ; 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" ""))))
 
 ; Likewise, plus TRUE for subregs.
 (define_predicate "mras_operand"
   (and (match_operand 0 "nonimmediate_operand" "")
Index: config/m32c/m32c.c
===================================================================
--- config/m32c/m32c.c	(revision 161424)
+++ config/m32c/m32c.c	(working copy)
@@ -80,12 +80,15 @@  static bool m32c_strict_argument_naming 
 static rtx m32c_struct_value_rtx (tree, int);
 static rtx m32c_subreg (enum machine_mode, rtx, enum machine_mode, int);
 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)
 
 #define streq(a,b) (strcmp ((a), (b)) == 0)
 
@@ -2926,13 +2929,113 @@  m32c_comp_type_attributes (const_tree ty
 #undef TARGET_INSERT_ATTRIBUTES
 #define TARGET_INSERT_ATTRIBUTES m32c_insert_attributes
 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 */
 
 /* This is a list of legal subregs of hard regs.  */
 static const struct {
@@ -2957,20 +3060,26 @@  static const struct {
   {2, 4, 0x01, 24, A1_REGNO}, /* a1 a0 */
 
   {4, 8, 0x55, 1, R0_REGNO}, /* r3 r1 r2 r0 */
 };
 
 /* 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)
 {
   int offset;
   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;
 
   dest_mode = GET_MODE (op);
   offset = SUBREG_BYTE (op);
   op = SUBREG_REG (op);
Index: config/m32c/m32c.h
===================================================================
--- config/m32c/m32c.h	(revision 161424)
+++ config/m32c/m32c.h	(working copy)
@@ -641,12 +641,19 @@  typedef struct m32c_cumulative_args
 #undef USER_LABEL_PREFIX
 #define USER_LABEL_PREFIX "_"
 
 #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) \
 	fprintf (S, "\t.word L%d\n", V)
 
 /* Assembler Commands for Exception Regions */
Index: config/m32c/m32c-pragma.c
===================================================================
--- config/m32c/m32c-pragma.c	(revision 161424)
+++ config/m32c/m32c-pragma.c	(working copy)
@@ -84,12 +84,50 @@  m32c_pragma_memregs (cpp_reader * reader
 	}
     }
 
   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);
 }
Index: config/m32c/m32c-protos.h
===================================================================
--- config/m32c/m32c-protos.h	(revision 161424)
+++ config/m32c/m32c-protos.h	(working copy)
@@ -39,12 +39,13 @@  void m32c_output_reg_pop (FILE *, int);
 void m32c_output_reg_push (FILE *, int);
 void m32c_override_options (void);
 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);
 
 #if defined(RTX_CODE) && defined(TREE_CODE)
 
@@ -101,11 +102,13 @@  int  m32c_split_psi_p (rtx *);
 
 void m32c_function_arg_advance (CUMULATIVE_ARGS *, MM, tree, int);
 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
 
 #undef MM
 #undef UINT