Adding #line directives for md-derived code

Richard Sandiford rsandifo@redhat.com
Wed Mar 2 21:53:00 GMT 2005


This patch (from my long-term to-do list) adds #line directives
to the files that are automatically generated from .md files.
First of all, the drawbacks (or at least the ones I know about):

  (1) We don't maintain indentation information while reading the .md file.
      This means that, if an automatically-generated file quotes something
      from the .md file, column numbers for the first line are often wrong.

  (2) We don't maintain a line counter for the output files, so once we've
      used #line to switch to the .md file, it isn't really possible to
      switch back.

  (3) Some of the output is uglier than it used to be, with lots of newlines
      to accomodate the preprocessor directives.

  (4) The patch might make it harder to single-step through files like
      genrecog.c in a debugger.

(2) and (3) will make it difficult to track down errors in the
automatically-generated parts of the code.  I think that's mostly
going to be a problem for people working on gen* programs, which
isn't as common as modifying .md files.

Wrt (2)-(4), all the #lines are printed by a single routine, so it's
easy enough to turn them off if they're getting in the way.

As for the implementation: a new hash table in read-rtl.c attaches
a file/lineno position to arbitrary pointer values.  At the moment,
these pointer values are all strings, but the same infrastructure
could be used for things like rtxes as well.  The public interface is:

    copy_rtx_ptr_loc (new, old)
        associate NEW with the same file position as OLD

    print_rtx_ptr_loc (ptr)
        print a #line directive for PTR, if it has a known file position

The most complicated part of the patch is dealing with concatenated
C conditions.  These occur in three places: define_cond_execs,
define_insn_and_splits, and mode/code macros.  The patch introduces
two more functions for dealing with them:

    join_c_conditions (cond1, cond2)
        Return a new condition satisfying both COND1 and COND2.
        Remember that it came from COND1 and COND2 originally.

    print_c_condition (cond)
        Print condition COND, with original source location if known.
        If COND was created by join_c_conditions, recursively call
        print_c_condition for the two subconditions and join them
        with "&&".  Each subcondition then gets its own #line where
        appropriate.

I tested this by introducing warnings to various bits of i386.md and
mips.md and checking that their locations were reported correctly.
Also bootstrapped and regression tested on i686-pc-linux-gnu
(with an unchanged i386.md).  OK to install?

Richard


	* rtl.h (copy_rtx_ptr_loc, print_rtx_ptr_loc, join_c_conditions)
	(print_c_condition): Declare.
	* read-rtl.c (ptr_loc): New structure.
	(ptr_locs, ptr_loc_obstack, joined_conditions)
	(joined_conditions_obstack): New variables.
	(leading_ptr_hash, leading_ptr_eq_p, set_rtx_ptr_loc)
	(get_rtx_ptr_loc, copy_rtx_ptr_loc, print_rtx_ptr_loc)
	(join_c_conditions, print_c_condition): New functions.
	(apply_macro_to_string): Associate the new string with the same
	source location as the old one.
	(add_condition_to_string): Use join_c_conditions.
	(read_string): Use set_rtx_ptr_loc to record a filename and line
	number for the string.
	(read_rtx): Initialize the new variables above.
	* genattrtab.c (write_test_expr, write_attr_value): Use
	print_c_condition.
	* genconditions.c (write_header): Don't define MAYBE_EVAL.  Move its
	comment above the GCC_VERSION check.
	(write_one_condition): Use print_rtx_ptr_loc and print_c_condition.
	Inline the definition of MAYBE_EVAL.
	* genemit.c (gen_expand, gen_split): Use print_rtx_ptr_loc.
	* genoutput.c (process_template): Likewise.
	* genpreds.c (write_predicate_subfunction): Likewise.
	(write_predicate_expr): Use print_c_condition.
	* genrecog.c (write_cond): Likewise.
	* gensupport.c (process_rtx): Use join_c_conditions to join the
	conditions of a define_insn_and_split.  Record a source location
	for the string after the "&&".
	(alter_test_for_insn): Use join_c_conditions.

Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.538
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.538 rtl.h
--- rtl.h	28 Feb 2005 18:18:24 -0000	1.538
+++ rtl.h	2 Mar 2005 20:53:01 -0000
@@ -2118,6 +2118,10 @@ struct md_constant { char *name, *value;
 /* In read-rtl.c */
 extern int read_skip_spaces (FILE *);
 extern bool read_rtx (FILE *, rtx *, int *);
+extern void copy_rtx_ptr_loc (const void *, const void *);
+extern void print_rtx_ptr_loc (const void *);
+extern const char *join_c_conditions (const char *, const char *);
+extern void print_c_condition (const char *);
 extern const char *read_rtx_filename;
 extern int read_rtx_lineno;
 
Index: read-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/read-rtl.c,v
retrieving revision 1.34
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.34 read-rtl.c
--- read-rtl.c	13 Feb 2005 19:05:03 -0000	1.34
+++ read-rtl.c	2 Mar 2005 20:53:02 -0000
@@ -79,6 +79,14 @@ struct macro_group {
   void (*apply_macro) (rtx, int);
 };
 
+/* Associates PTR (which can be a string, etc.) with the file location
+   specified by FILENAME and LINENO.  */
+struct ptr_loc {
+  const void *ptr;
+  const char *filename;
+  int lineno;
+};
+
 /* If CODE is the number of a code macro, return a real rtx code that
    has the same format.  Return CODE otherwise.  */
 #define BELLWETHER_CODE(CODE) \
@@ -105,6 +113,10 @@ static struct map_value **add_map_value 
 					 int, const char *);
 static void initialize_macros (void);
 static void read_name (char *, FILE *);
+static hashval_t leading_ptr_hash (const void *);
+static int leading_ptr_eq_p (const void *, const void *);
+static void set_rtx_ptr_loc (const void *, const char *, int);
+static const struct ptr_loc *get_rtx_ptr_loc (const void *);
 static char *read_string (FILE *, int);
 static char *read_quoted_string (FILE *);
 static char *read_braced_string (FILE *);
@@ -127,6 +139,22 @@ static enum rtx_code *bellwether_codes;
 /* Obstack used for allocating RTL strings.  */
 static struct obstack string_obstack;
 
+/* A table of ptr_locs, hashed on the PTR field.  */
+static htab_t ptr_locs;
+
+/* An obstack for the above.  Plain xmalloc is a bit heavyweight for a
+   small structure like ptr_loc.  */
+static struct obstack ptr_loc_obstack;
+
+/* A hash table of triples (A, B, C), where each of A, B and C is a condition
+   and A is equivalent to "B && C".  This is used to keep track of the source
+   of conditions that are made up of separate rtx strings (such as the split
+   condition of a define_insn_and_split).  */
+static htab_t joined_conditions;
+
+/* An obstack for allocating joined_conditions entries.  */
+static struct obstack joined_conditions_obstack;
+
 /* Subroutines of read_rtx.  */
 
 /* The current line number for the file.  */
@@ -285,7 +313,9 @@ apply_macro_to_string (const char *strin
   if (base != copy)
     {
       obstack_grow (&string_obstack, base, strlen (base) + 1);
-      return (char *) obstack_finish (&string_obstack);
+      copy = obstack_finish (&string_obstack);
+      copy_rtx_ptr_loc (copy, string);
+      return copy;
     }
   return string;
 }
@@ -396,16 +426,9 @@ uses_macro_p (rtx x, struct mapping *mac
 static const char *
 add_condition_to_string (const char *original, const char *extra)
 {
-  char *result;
-
-  if (original == 0 || original[0] == 0)
-    return extra;
-
-  if ((original[0] == '&' && original[1] == '&') || extra[0] == 0)
+  if (original != 0 && original[0] == '&' && original[1] == '&')
     return original;
-
-  asprintf (&result, "(%s) && (%s)", original, extra);
-  return result;
+  return join_c_conditions (original, extra);
 }
 
 /* Like add_condition, but applied to all conditions in rtx X.  */
@@ -568,6 +591,116 @@ initialize_macros (void)
     }
 }
 
+/* Return a hash value for the pointer pointed to by DEF.  */
+
+static hashval_t
+leading_ptr_hash (const void *def)
+{
+  return htab_hash_pointer (*(const void *const *) def);
+}
+
+/* Return true if DEF1 and DEF2 are pointers to the same pointer.  */
+
+static int
+leading_ptr_eq_p (const void *def1, const void *def2)
+{
+  return *(const void *const *) def1 == *(const void *const *) def2;
+}
+
+/* Associate PTR with the file position given by FILENAME and LINENO.  */
+
+static void
+set_rtx_ptr_loc (const void *ptr, const char *filename, int lineno)
+{
+  struct ptr_loc *loc;
+
+  loc = (struct ptr_loc *) obstack_alloc (&ptr_loc_obstack,
+					  sizeof (struct ptr_loc));
+  loc->ptr = ptr;
+  loc->filename = filename;
+  loc->lineno = lineno;
+  *htab_find_slot (ptr_locs, loc, INSERT) = loc;
+}
+
+/* Return the position associated with pointer PTR.  Return null if no
+   position was set.  */
+
+static const struct ptr_loc *
+get_rtx_ptr_loc (const void *ptr)
+{
+  return (const struct ptr_loc *) htab_find (ptr_locs, &ptr);
+}
+
+/* Associate NEW_PTR with the same file position as OLD_PTR.  */
+
+void
+copy_rtx_ptr_loc (const void *new_ptr, const void *old_ptr)
+{
+  const struct ptr_loc *loc = get_rtx_ptr_loc (old_ptr);
+  if (loc != 0)
+    set_rtx_ptr_loc (new_ptr, loc->filename, loc->lineno);
+}
+
+/* If PTR is associated with a known file position, print a #line
+   directive for it.  */
+
+void
+print_rtx_ptr_loc (const void *ptr)
+{
+  const struct ptr_loc *loc = get_rtx_ptr_loc (ptr);
+  if (loc != 0)
+    printf ("#line %d \"%s\"\n", loc->lineno, loc->filename);
+}
+
+/* Return a condition that satisfies both COND1 and COND2.  Either string
+   may be null or empty.  */
+
+const char *
+join_c_conditions (const char *cond1, const char *cond2)
+{
+  char *result;
+  const void **entry;
+
+  if (cond1 == 0 || cond1[0] == 0)
+    return cond2;
+
+  if (cond2 == 0 || cond2[0] == 0)
+    return cond1;
+
+  result = concat ("(", cond1, ") && (", cond2, ")", NULL);
+  obstack_ptr_grow (&joined_conditions_obstack, result);
+  obstack_ptr_grow (&joined_conditions_obstack, cond1);
+  obstack_ptr_grow (&joined_conditions_obstack, cond2);
+  entry = obstack_finish (&joined_conditions_obstack);
+  *htab_find_slot (joined_conditions, entry, INSERT) = entry;
+  return result;
+}
+
+/* Print condition COND, wrapped in brackets.  If COND was created by
+   join_c_conditions, recursively invoke this function for the original
+   conditions and join the result with "&&".  Otherwise print a #line
+   directive for COND if its original file position is known.  */
+
+void
+print_c_condition (const char *cond)
+{
+  const void **halves = htab_find (joined_conditions, &cond);
+  if (halves != 0)
+    {
+      printf ("(");
+      print_c_condition (halves[1]);
+      printf (" && ");
+      print_c_condition (halves[2]);
+      printf (")");
+    }
+  else
+    {
+      putc ('\n', stdout);
+      print_rtx_ptr_loc (cond);
+      printf ("(%s)", cond);
+    }
+}
+
 /* Read chars from INFILE until a non-whitespace char
    and return that.  Comments, both Lisp style and C style,
    are treated as whitespace.
@@ -801,7 +934,7 @@ read_string (FILE *infile, int star_if_b
 {
   char *stringbuf;
   int saw_paren = 0;
-  int c;
+  int c, old_lineno;
 
   c = read_skip_spaces (infile);
   if (c == '(')
@@ -810,6 +943,7 @@ read_string (FILE *infile, int star_if_b
       c = read_skip_spaces (infile);
     }
 
+  old_lineno = read_rtx_lineno;
   if (c == '"')
     stringbuf = read_quoted_string (infile);
   else if (c == '{')
@@ -828,6 +962,7 @@ read_string (FILE *infile, int star_if_b
 	fatal_expected_char (infile, ')', c);
     }
 
+  set_rtx_ptr_loc (stringbuf, read_rtx_filename, old_lineno);
   return stringbuf;
 }
 
@@ -1094,6 +1229,11 @@ read_rtx (FILE *infile, rtx *x, int *lin
       initialize_macros ();
       obstack_init (&string_obstack);
       queue_head = rtx_alloc (EXPR_LIST);
+      ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+      obstack_init (&ptr_loc_obstack);
+      joined_conditions = htab_create (161, leading_ptr_hash,
+				       leading_ptr_eq_p, 0);
+      obstack_init (&joined_conditions_obstack);
     }
 
   if (queue_next == 0)
Index: genattrtab.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genattrtab.c,v
retrieving revision 1.154
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.154 genattrtab.c
--- genattrtab.c	9 Sep 2004 20:39:28 -0000	1.154
+++ genattrtab.c	2 Mar 2005 20:53:03 -0000
@@ -3506,7 +3506,7 @@ write_test_expr (rtx exp, int flags)
 
     /* A random C expression.  */
     case SYMBOL_REF:
-      printf ("%s", XSTR (exp, 0));
+      print_c_condition (XSTR (exp, 0));
       break;
 
     /* The address of the branch target.  */
@@ -4035,7 +4035,7 @@ write_attr_value (struct attr_desc *attr
       break;
 
     case SYMBOL_REF:
-      fputs (XSTR (value, 0), stdout);
+      print_c_condition (XSTR (value, 0));
       break;
 
     case ATTR:
Index: genconditions.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genconditions.c,v
retrieving revision 1.14
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.14 genconditions.c
--- genconditions.c	24 Jan 2005 12:08:06 -0000	1.14
+++ genconditions.c	2 Mar 2005 20:53:03 -0000
@@ -86,6 +86,10 @@ write_header (void)
 
   puts ("\
 #include \"system.h\"\n\
+/* If we don't have __builtin_constant_p, or it's not acceptable in array\n\
+   initializers, fall back to assuming that all conditions potentially\n\
+   vary at run time.  It works in 3.0.1 and later; 3.0 only when not\n\
+   optimizing.  */\n\
 #if GCC_VERSION < 3001\n\
 #include \"dummy-conditions.c\"\n\
 #else\n\
@@ -122,19 +126,15 @@ #define MAX_INSNS_PER_SPLIT 5\n");
 extern rtx insn;\n\
 extern rtx ins1;\n\
 extern rtx operands[];\n");
-
-  puts ("\
-/* If we don't have __builtin_constant_p, or it's not acceptable in\n\
-   array initializers, fall back (by using dummy-conditions.c above)\n\
-   to assuming that all conditions potentially vary at run time.  It\n\
-   works in 3.0.1 and later; 3.0 only when not optimizing.  */\n\
-#define MAYBE_EVAL(expr) (__builtin_constant_p(expr) ? (int) (expr) : -1)\n");
 }
 
 /* Write out one entry in the conditions table, using the data pointed
    to by SLOT.  Each entry looks like this:
-  { "! optimize_size && ! TARGET_READ_MODIFY_WRITE",
-    MAYBE_EVAL (! optimize_size && ! TARGET_READ_MODIFY_WRITE) },  */
+
+   { "! optimize_size && ! TARGET_READ_MODIFY_WRITE",
+     __builtin_constant_p (! optimize_size && ! TARGET_READ_MODIFY_WRITE)
+     ? (int) (! optimize_size && ! TARGET_READ_MODIFY_WRITE)
+     : -1) },  */
 
 static int
 write_one_condition (void **slot, void * ARG_UNUSED (dummy))
@@ -142,6 +142,7 @@ write_one_condition (void **slot, void *
   const struct c_test *test = * (const struct c_test **) slot;
   const char *p;
 
+  print_rtx_ptr_loc (test->expr);
   fputs ("  { \"", stdout);
   for (p = test->expr; *p; p++)
     {
@@ -153,7 +154,11 @@ write_one_condition (void **slot, void *
 	putchar (*p);
     }
 
-  printf ("\",\n    MAYBE_EVAL (%s) },\n", test->expr);
+  printf ("\",\n    __builtin_constant_p ");
+  print_c_condition (test->expr);
+  printf ("\n    ? (int) ");
+  print_c_condition (test->expr);
+  printf ("\n    : -1 },\n");
   return 1;
 }
 
Index: genemit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genemit.c,v
retrieving revision 1.96
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.96 genemit.c
--- genemit.c	9 Sep 2004 13:22:33 -0000	1.96
+++ genemit.c	2 Mar 2005 20:53:03 -0000
@@ -509,6 +509,7 @@ gen_expand (rtx expand)
 
       /* Output the special code to be executed before the sequence
 	 is generated.  */
+      print_rtx_ptr_loc (XSTR (expand, 3));
       printf ("%s\n", XSTR (expand, 3));
 
       /* Output code to copy the arguments back out of `operands'
@@ -630,7 +631,10 @@ gen_split (rtx split)
      before the actual construction.  */
 
   if (XSTR (split, 3))
-    printf ("%s\n", XSTR (split, 3));
+    {
+      print_rtx_ptr_loc (XSTR (split, 3));
+      printf ("%s\n", XSTR (split, 3));
+    }
 
   /* Output code to copy the arguments back out of `operands'  */
   for (i = 0; i < operands; i++)
Index: genoutput.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genoutput.c,v
retrieving revision 1.84
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.84 genoutput.c
--- genoutput.c	9 Sep 2004 13:22:34 -0000	1.84
+++ genoutput.c	2 Mar 2005 20:53:03 -0000
@@ -668,7 +668,7 @@ process_template (struct data *d, const 
       printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
 	      d->code_number);
       puts ("{");
-
+      print_rtx_ptr_loc (template);
       puts (template + 1);
       puts ("}");
     }
Index: genpreds.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genpreds.c,v
retrieving revision 1.14
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.14 genpreds.c
--- genpreds.c	23 Feb 2005 15:14:36 -0000	1.14
+++ genpreds.c	2 Mar 2005 20:53:03 -0000
@@ -138,6 +138,7 @@ write_predicate_subfunction (struct pred
   printf ("static inline int\n"
 	  "%s_1 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n",
 	  p->name);
+  print_rtx_ptr_loc (p->c_block);
   if (p->c_block[0] == '{')
     fputs (p->c_block, stdout);
   else
@@ -377,7 +378,7 @@ write_predicate_expr (const char *name, 
       break;
 
     case MATCH_TEST:
-      fputs (XSTR (exp, 0), stdout);
+      print_c_condition (XSTR (exp, 0));
       break;
 
     default:
Index: genrecog.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genrecog.c,v
retrieving revision 1.152
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.152 genrecog.c
--- genrecog.c	28 Dec 2004 07:56:09 -0000	1.152
+++ genrecog.c	2 Mar 2005 20:53:04 -0000
@@ -2113,7 +2113,7 @@ write_cond (struct decision_test *p, int
       break;
 
     case DT_c_test:
-      printf ("(%s)", p->u.c_test);
+      print_c_condition (p->u.c_test);
       break;
 
     case DT_accept_insn:
Index: gensupport.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gensupport.c,v
retrieving revision 1.58
diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.58 gensupport.c
--- gensupport.c	16 Dec 2004 17:31:58 -0000	1.58
+++ gensupport.c	2 Mar 2005 20:53:04 -0000
@@ -317,7 +317,10 @@ process_rtx (rtx desc, int lineno)
 	   insn condition to create the new split condition.  */
 	split_cond = XSTR (desc, 4);
 	if (split_cond[0] == '&' && split_cond[1] == '&')
-	  split_cond = concat (XSTR (desc, 2), split_cond, NULL);
+	  {
+	    copy_rtx_ptr_loc (split_cond + 2, split_cond);
+	    split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2);
+	  }
 	XSTR (split, 1) = split_cond;
 	XVEC (split, 2) = XVEC (desc, 5);
 	XSTR (split, 3) = XSTR (desc, 6);
@@ -663,16 +666,8 @@ static const char *
 alter_test_for_insn (struct queue_elem *ce_elem,
 		     struct queue_elem *insn_elem)
 {
-  const char *ce_test, *insn_test;
-
-  ce_test = XSTR (ce_elem->data, 1);
-  insn_test = XSTR (insn_elem->data, 2);
-  if (!ce_test || *ce_test == '\0')
-    return insn_test;
-  if (!insn_test || *insn_test == '\0')
-    return ce_test;
-
-  return concat ("(", ce_test, ") && (", insn_test, ")", NULL);
+  return join_c_conditions (XSTR (ce_elem->data, 1),
+			    XSTR (insn_elem->data, 2));
 }
 
 /* Adjust all of the operand numbers in SRC to match the shift they'll



More information about the Gcc-patches mailing list