summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/gcc/gcc-4.6.0/gcc-4_6-branch-backports/0349-PR-tree-optimization-49161.patch
blob: 80f89fd4182a31e70f45180ed077c8e06151e2fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
From a6f15e84e042ffb95afa499d2bd2d6b2758f85f9 Mon Sep 17 00:00:00 2001
From: jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu, 26 May 2011 10:20:34 +0000
Subject: [PATCH] 	PR tree-optimization/49161
 	* tree-vrp.c (struct case_info): New type.
 	(compare_case_labels): Sort case_info structs instead of
 	trees, and not primarily by CASE_LABEL uids but by
 	label_for_block indexes.
 	(find_switch_asserts): Put case labels into struct case_info
 	array instead of TREE_VEC, adjust sorting, compare label_for_block
 	values instead of CASE_LABELs.

	* gcc.c-torture/execute/pr49161.c: New test.


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_6-branch@174272 138bc75d-0d04-0410-961f-82ee72b054a4

index 2c4fdd4..b5d9fd3 100644
new file mode 100644
index 0000000..cc822da
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr49161.c
@@ -0,0 +1,46 @@
+/* PR tree-optimization/49161 */
+
+extern void abort (void);
+
+int c;
+
+__attribute__((noinline, noclone)) void
+bar (int x)
+{
+  if (x != c++)
+    abort ();
+}
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+  switch (x)
+    {
+    case 3: goto l1;
+    case 4: goto l2;
+    case 6: goto l3;
+    default: return;
+    }
+l1:
+  goto l4;
+l2:
+  goto l4;
+l3:
+  bar (-1);
+l4:
+  bar (0);
+  if (x != 4)
+    bar (1);
+  if (x != 3)
+    bar (-1);
+  bar (2);
+}
+
+int
+main ()
+{
+  foo (3);
+  if (c != 3)
+    abort ();
+  return 0;
+}
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 7bff5fa..6914a08 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -4672,28 +4672,35 @@ find_conditional_asserts (basic_block bb, gimple last)
   return need_assert;
 }
 
-/* Compare two case labels sorting first by the destination label uid
+struct case_info
+{
+  tree expr;
+  basic_block bb;
+};
+
+/* Compare two case labels sorting first by the destination bb index
    and then by the case value.  */
 
 static int
 compare_case_labels (const void *p1, const void *p2)
 {
-  const_tree const case1 = *(const_tree const*)p1;
-  const_tree const case2 = *(const_tree const*)p2;
-  unsigned int uid1 = DECL_UID (CASE_LABEL (case1));
-  unsigned int uid2 = DECL_UID (CASE_LABEL (case2));
+  const struct case_info *ci1 = (const struct case_info *) p1;
+  const struct case_info *ci2 = (const struct case_info *) p2;
+  int idx1 = ci1->bb->index;
+  int idx2 = ci2->bb->index;
 
-  if (uid1 < uid2)
+  if (idx1 < idx2)
     return -1;
-  else if (uid1 == uid2)
+  else if (idx1 == idx2)
     {
       /* Make sure the default label is first in a group.  */
-      if (!CASE_LOW (case1))
+      if (!CASE_LOW (ci1->expr))
 	return -1;
-      else if (!CASE_LOW (case2))
+      else if (!CASE_LOW (ci2->expr))
 	return 1;
       else
-        return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2));
+	return tree_int_cst_compare (CASE_LOW (ci1->expr),
+				     CASE_LOW (ci2->expr));
     }
   else
     return 1;
@@ -4714,8 +4721,8 @@ find_switch_asserts (basic_block bb, gimple last)
   gimple_stmt_iterator bsi;
   tree op;
   edge e;
-  tree vec2;
-  size_t n = gimple_switch_num_labels(last);
+  struct case_info *ci;
+  size_t n = gimple_switch_num_labels (last);
 #if GCC_VERSION >= 4000
   unsigned int idx;
 #else
@@ -4730,36 +4737,38 @@ find_switch_asserts (basic_block bb, gimple last)
     return false;
 
   /* Build a vector of case labels sorted by destination label.  */
-  vec2 = make_tree_vec (n);
+  ci = XNEWVEC (struct case_info, n);
   for (idx = 0; idx < n; ++idx)
-    TREE_VEC_ELT (vec2, idx) = gimple_switch_label (last, idx);
-  qsort (&TREE_VEC_ELT (vec2, 0), n, sizeof (tree), compare_case_labels);
+    {
+      ci[idx].expr = gimple_switch_label (last, idx);
+      ci[idx].bb = label_to_block (CASE_LABEL (ci[idx].expr));
+    }
+  qsort (ci, n, sizeof (struct case_info), compare_case_labels);
 
   for (idx = 0; idx < n; ++idx)
     {
       tree min, max;
-      tree cl = TREE_VEC_ELT (vec2, idx);
+      tree cl = ci[idx].expr;
+      basic_block cbb = ci[idx].bb;
 
       min = CASE_LOW (cl);
       max = CASE_HIGH (cl);
 
       /* If there are multiple case labels with the same destination
 	 we need to combine them to a single value range for the edge.  */
-      if (idx + 1 < n
-	  && CASE_LABEL (cl) == CASE_LABEL (TREE_VEC_ELT (vec2, idx + 1)))
+      if (idx + 1 < n && cbb == ci[idx + 1].bb)
 	{
 	  /* Skip labels until the last of the group.  */
 	  do {
 	    ++idx;
-	  } while (idx < n
-		   && CASE_LABEL (cl) == CASE_LABEL (TREE_VEC_ELT (vec2, idx)));
+	  } while (idx < n && cbb == ci[idx].bb);
 	  --idx;
 
 	  /* Pick up the maximum of the case label range.  */
-	  if (CASE_HIGH (TREE_VEC_ELT (vec2, idx)))
-	    max = CASE_HIGH (TREE_VEC_ELT (vec2, idx));
+	  if (CASE_HIGH (ci[idx].expr))
+	    max = CASE_HIGH (ci[idx].expr);
 	  else
-	    max = CASE_LOW (TREE_VEC_ELT (vec2, idx));
+	    max = CASE_LOW (ci[idx].expr);
 	}
 
       /* Nothing to do if the range includes the default label until we
@@ -4768,7 +4777,7 @@ find_switch_asserts (basic_block bb, gimple last)
 	continue;
 
       /* Find the edge to register the assert expr on.  */
-      e = find_edge (bb, label_to_block (CASE_LABEL (cl)));
+      e = find_edge (bb, cbb);
 
       /* Register the necessary assertions for the operand in the
 	 SWITCH_EXPR.  */
@@ -4786,6 +4795,7 @@ find_switch_asserts (basic_block bb, gimple last)
 	}
     }
 
+  XDELETEVEC (ci);
   return need_assert;
 }
 
-- 
1.7.0.4