public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* genattrab.c generate switch
@ 2016-01-13  0:53 Jesper Broge Jørgensen
  2016-01-18 14:15 ` Bernd Schmidt
  2016-02-01 19:20 ` Patrick Palka
  0 siblings, 2 replies; 10+ messages in thread
From: Jesper Broge Jørgensen @ 2016-01-13  0:53 UTC (permalink / raw)
  To: gcc-patches

Hello

genattrab.c can generate if statements that have very deep bracket 
nesting causing clang to produce errors (when target=arm-none-eabi) as 
explained at https://gcc.gnu.org/ml/gcc/2014-05/msg00032.html
At the above link it was suggested that genattrab.c generated a switch 
statement instead. I have made a patch that does just that.



gcc/ChangeLog:

2016-01-13  Jesper Broge Jørgensen  <jesperbroge@gmail.com>

     * genattrtab.c (check_attr_set_switch): implemented the function
     (write_attr_set): Check if expression can be written as a switch


diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index 2caf8f6..b6de642 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -275,6 +275,8 @@ static bool attr_alt_subset_of_compl_p (rtx, rtx);
  static void clear_struct_flag      (rtx);
  static void write_attr_valueq       (FILE *, struct attr_desc *, const 
char *);
  static struct attr_value *find_most_used  (struct attr_desc *);
+static int check_attr_set_switch (FILE *outf, rtx exp,
+                    unsigned int attrs_cached, int write_cases, int 
indent);
  static void write_attr_set       (FILE *, struct attr_desc *, int, rtx,
                      const char *, const char *, rtx,
                      int, int, unsigned int);
@@ -4113,6 +4115,102 @@ eliminate_known_true (rtx known_true, rtx exp, 
int insn_code, int insn_index)
    return exp;
  }

+/* Check if exp contains a series of IOR conditions on the same attr_name.
+   If it does it can be turned into a switch statement and returns true.
+   If write_cases is true it will write the cases of the switch to 
outf.  */
+
+static int
+check_attr_set_switch (FILE *outf, rtx exp, unsigned int attrs_cached,
+                        int write_cases, int indent)
+{
+  if (GET_CODE (exp) != IOR)
+    return 0;
+  if (GET_CODE (XEXP (exp, 0)) != EQ_ATTR)
+    return 0;
+
+  rtx next = exp;
+  int ior_depth = 0;
+  int is_first = 1;
+
+  const char *attr_name_cmp = XSTR (XEXP (exp, 0), 0);
+
+  while (1)
+  {
+    rtx op1 = XEXP (next, 0);
+    rtx op2 = XEXP (next, 1);
+
+    if (GET_CODE (op1) != EQ_ATTR)
+      return 0;
+
+    const char *attr_name = XSTR (op1, 0);
+    const char *cmp_val = XSTR (op1, 1);
+
+    /* pointer compare is enough.  */
+    if (attr_name_cmp != attr_name)
+      return 0;
+
+    if (write_cases)
+    {
+      struct attr_desc *attr = find_attr (&attr_name, 0);
+      gcc_assert (attr);
+      if (is_first)
+      {
+        fprintf (outf, "(");
+        is_first = 0;
+        int i;
+        for (i = 0; i < cached_attr_count; i++)
+          if (attr->name == cached_attrs[i])
+            break;
+
+        if (i < cached_attr_count && (attrs_cached & (1U << i)) != 0)
+          fprintf (outf, "cached_%s", attr->name);
+        else if (i < cached_attr_count && (attrs_to_cache & (1U << i)) 
!= 0)
+          fprintf (outf, "(cached_%s = get_attr_%s (insn))", attr->name,
+                            attr->name);
+        else
+          fprintf (outf, "get_attr_%s (insn)", attr->name);
+        fprintf (outf, ")\n");
+        write_indent (outf, indent);
+        fprintf (outf, "{\n");
+      }
+      write_indent (outf, indent);
+      fprintf (outf, "case ");
+      write_attr_valueq (outf, attr, cmp_val);
+      fprintf (outf, ":\n");
+    }
+
+    const int code = GET_CODE (op2);
+    if (code != IOR)
+    {
+      if (code == EQ_ATTR)
+      {
+        const char *attr_name = XSTR (op2, 0);
+        const char *cmp_val = XSTR (op2, 1);
+
+        if (attr_name == alternative_name)
+          return 0;
+
+        struct attr_desc *attr = find_attr (&attr_name, 0);
+        gcc_assert (attr);
+
+        if (attr->is_const)
+          return 0;
+        else if (write_cases)
+        {
+          write_indent (outf, indent);
+          fprintf (outf, "case ");
+          write_attr_valueq (outf, attr, cmp_val);
+          fprintf (outf, ":\n");
+        }
+      }
+      break;
+    }
+    next = op2;
+    ior_depth++;
+  }
+  return ior_depth > 2;
+}
+
  /* Write out a series of tests and assignment statements to perform 
tests and
     sets of an attribute value.  We are passed an indentation amount 
and prefix
     and suffix strings to write around each attribute value (e.g., "return"
@@ -4123,6 +4221,7 @@ write_attr_set (FILE *outf, struct attr_desc 
*attr, int indent, rtx value,
          const char *prefix, const char *suffix, rtx known_true,
          int insn_code, int insn_index, unsigned int attrs_cached)
  {
+  int n_switches = 0;
    if (GET_CODE (value) == COND)
      {
        /* Assume the default value will be the default of the COND 
unless we
@@ -4132,6 +4231,7 @@ write_attr_set (FILE *outf, struct attr_desc 
*attr, int indent, rtx value,
        rtx newexp;
        int first_if = 1;
        int i;
+      int is_switch = 0;

        if (cached_attr_count)
      {
@@ -4176,40 +4276,68 @@ write_attr_set (FILE *outf, struct attr_desc 
*attr, int indent, rtx value,
        if (inner_true == false_rtx)
          continue;

+      is_switch = check_attr_set_switch (outf, testexp, attrs_cached, 0,
+          indent);
+
        attrs_cached_inside = attrs_cached;
        attrs_cached_after = attrs_cached;
        write_indent (outf, indent);
-      fprintf (outf, "%sif ", first_if ? "" : "else ");
-      first_if = 0;
-      write_test_expr (outf, testexp, attrs_cached,
-               (FLG_AFTER | FLG_INSIDE | FLG_OUTSIDE_AND));
-      attrs_cached = attrs_cached_after;
-      fprintf (outf, "\n");
-      write_indent (outf, indent + 2);
-      fprintf (outf, "{\n");
+      if (is_switch)
+        {
+          fprintf (outf, "switch ");
+          n_switches++;
+          first_if = 1;
+          check_attr_set_switch (outf, testexp, attrs_cached, 1, indent);
+          indent += 4;
+        }
+      else
+        {
+            fprintf (outf, "%sif ", first_if ? "" : "else ");
+            first_if = 0;
+            write_test_expr (outf, testexp, attrs_cached,
+                (FLG_AFTER | FLG_INSIDE | FLG_OUTSIDE_AND));
+                attrs_cached = attrs_cached_after;
+            fprintf (outf, "\n");
+        }
+        if (! is_switch)
+        {
+          write_indent (outf, indent + 2);
+          fprintf (outf, "{\n");
+        }
+

        write_attr_set (outf, attr, indent + 4,
                XVECEXP (value, 0, i + 1), prefix, suffix,
                inner_true, insn_code, insn_index,
                attrs_cached_inside);
        write_indent (outf, indent + 2);
-      fprintf (outf, "}\n");
+      if (is_switch)
+      {
+        fprintf (outf, "break;\n");
+        write_indent (outf, indent);
+        fprintf (outf, "default:\n");
+        indent += 4;
+      }
+      else
+        fprintf (outf, "}\n");
        our_known_true = newexp;
      }

-      if (! first_if)
+      if (! first_if && ! is_switch)
      {
        write_indent (outf, indent);
        fprintf (outf, "else\n");
        write_indent (outf, indent + 2);
        fprintf (outf, "{\n");
      }
+    else if (is_switch)
+        write_indent (outf, indent);

-      write_attr_set (outf, attr, first_if ? indent : indent + 4, 
default_val,
+      write_attr_set (outf, attr, (first_if || is_switch) ? indent : 
indent + 4, default_val,
                prefix, suffix, our_known_true, insn_code, insn_index,
                attrs_cached);

-      if (! first_if)
+      if (! first_if && ! is_switch)
      {
        write_indent (outf, indent + 2);
        fprintf (outf, "}\n");
@@ -4222,6 +4350,12 @@ write_attr_set (FILE *outf, struct attr_desc 
*attr, int indent, rtx value,
        write_attr_value (outf, attr, value);
        fprintf (outf, "%s\n", suffix);
      }
+    while (n_switches--)
+      {
+        indent -= 2;
+        write_indent (outf, indent);
+        fprintf (outf, "}\n");
+      }
  }

  /* Write a series of case statements for every instruction in list IE.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-02-01 20:05 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-13  0:53 genattrab.c generate switch Jesper Broge Jørgensen
2016-01-18 14:15 ` Bernd Schmidt
2016-01-18 14:22   ` Jakub Jelinek
2016-01-18 14:39   ` Jesper Broge Jørgensen
2016-01-18 17:39     ` Manuel López-Ibáñez
2016-01-18 22:44       ` Jesper Broge Jørgensen
2016-01-19 12:18         ` Bernd Schmidt
2016-02-01 18:11           ` Jesper Broge Jørgensen
2016-02-01 19:20 ` Patrick Palka
2016-02-01 20:05   ` Jesper Broge Jørgensen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).