1 /* PRE tree-optimization/90626 - fold strcmp(a, b) == 0 to zero when
2    one string length is exact and the other is unequal
3    { dg-do compile }
4    { dg-options "-O2 -Wall -Wno-string-compare -fdump-tree-optimized -ftrack-macro-expansion=0" } */
5 
6 #include "strlenopt.h"
7 
8 #define CAT(x, y) x ## y
9 #define CONCAT(x, y) CAT (x, y)
10 #define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
11 
12 #define FAIL(name) do {				\
13     extern void FAILNAME (name) (void);		\
14     FAILNAME (name)();				\
15   } while (0)
16 
17 /* Macro to emit a call to function named
18      call_in_true_branch_not_eliminated_on_line_NNN()
19    for each call that's expected to be eliminated.  The dg-final
20    scan-tree-dump-time directive at the bottom of the test verifies
21    that no such call appears in output.  */
22 #define ELIM_IF_TRUE(expr)						\
23   if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
24 
25 /* Macro to emit a call to a function named
26      call_made_in_{true,false}_branch_on_line_NNN()
27    for each call that's expected to be retained.  The dg-final
28    scan-tree-dump-time directive at the bottom of the test verifies
29    that the expected number of both kinds of calls appears in output
30    (a pair for each line with the invocation of the KEEP() macro.  */
31 #define TEST_KEEP(expr)				\
32   if (expr)					\
33     FAIL (made_in_true_branch);			\
34   else						\
35     FAIL (made_in_false_branch)
36 
37 #define FOLD(init1, init2, arg1, arg2, bnd)	\
38   do {							\
39     char a[8], b[8];					\
40     sink (a, b);					\
41     memcpy (a, init1, sizeof init1 - 1);		\
42     memcpy (b, init2, sizeof init2 - 1);		\
43     ELIM_IF_TRUE (0 != CMPFUNC (arg1, arg2, bnd));	\
44   } while (0)
45 
46 #define KEEP(init1, init2, arg1, arg2, bnd)	\
47   do {						\
48     char a[8], b[8];				\
49     sink (a, b);				\
50     memcpy (a, init1, sizeof init1 - 1);	\
51     memcpy (b, init2, sizeof init2 - 1);	\
52     TEST_KEEP (0 == CMPFUNC (arg1, arg2, bnd));	\
53   } while (0)
54 
55 const char s0[1] = "";
56 const char s00[2] = "\0";
57 const char s10[2] = "1";
58 const char s20[2] = "2";
59 
60 void sink (void*, ...);
61 
test_strcmp_elim(void)62 void test_strcmp_elim (void)
63 {
64 #undef CMPFUNC
65 #define CMPFUNC(a, b, dummy) strcmp (a, b)
66 
67   FOLD (s00, s10, "\0", "1", -1);
68   FOLD (s00, s10, "\0", b, -1);
69   FOLD (s00, s10, "\0", s10, -1);
70 
71   FOLD (s00, s10, s0, "1", -1);
72   FOLD (s00, s10, s0, b, -1);
73   FOLD (s00, s10, s0, s10, -1);
74 
75   FOLD ("\0", "1", s0, "1", -1);
76   FOLD ("\0", "1", s0, b, -1);
77   FOLD ("\0", "1", s0, s10, -1);
78 
79   FOLD ("2",  "\0", "2", "\0", -1);
80   FOLD ("2",  "\0", s20, s0, -1);
81 
82   FOLD ("\0", "1", a, b, -1);
83   FOLD ("2",  "\0", a, b, -1);
84 
85   FOLD ("4\0", "44", a, b, -1);
86   FOLD ("55", "5\0", a, b, -1);
87 
88   FOLD ("666\0", "6666", a, "6666", -1);
89   FOLD ("666\0", "6666", a, b, -1);
90   FOLD ("7777", "777\0", a, b, -1);
91 
92   /* Avoid testing substrings of equal length with different characters.
93      The optimization doesn't have access to the contents of the strings
94      so it can't determine whether they are equal.
95 
96      FOLD ("111\0", "112", a, b, -1);
97      FOLD ("112", "111\0", a, b, -1);  */
98 }
99 
100 const char s123[] = "123";
101 const char s1230[] = "123\0";
102 
103 const char s1234[] = "1234";
104 const char s12340[] = "1234\0";
105 
test_strncmp_elim(void)106 void test_strncmp_elim (void)
107 {
108 #undef CMPFUNC
109 #define CMPFUNC(a, b, n) strncmp (a, b, n)
110 
111   FOLD (s1230, s1234, "123",  "1234", 4);
112   FOLD (s1234, s1230, "1234", "123",  4);
113 
114   FOLD (s1230, s1234, "123",  s1234, 4);
115   FOLD (s1234, s1230, "1234", s123,  4);
116 
117   FOLD (s1230, s1234, s123,  "1234", 4);
118   FOLD (s1234, s1230, s1234, "123",  4);
119 
120   FOLD (s1230, s1234, s123,  b, 4);
121   FOLD (s1234, s1230, s1234, b, 4);
122 
123   FOLD (s1230, s1234, a, b, 4);
124   FOLD (s1234, s1230, a, b, 4);
125 
126   FOLD ("123\0", "1234",  a, b, 5);
127   FOLD ("1234",  "123\0", a, b, 5);
128 }
129 
130 
131 #line 1000
132 
test_strcmp_keep(const char * s,const char * t)133 void test_strcmp_keep (const char *s, const char *t)
134 {
135 #undef CMPFUNC
136 #define CMPFUNC(a, b, dummy) strcmp (a, b)
137 
138   KEEP ("123", "123\0", a, b, /* bnd = */ -1);
139   KEEP ("123\0", "123", a, b, -1);
140 
141   {
142     char a[8], b[8];
143     sink (a, b);
144     strcpy (a, s);
145     strcpy (b, t);
146     TEST_KEEP (0 == strcmp (a, b));
147   }
148 }
149 
150 
test_strncmp_keep(const char * s,const char * t)151 void test_strncmp_keep (const char *s, const char *t)
152 {
153 #undef CMPFUNC
154 #define CMPFUNC(a, b, n) strncmp (a, b, n)
155 
156   KEEP ("1", "1", a, b, 2);
157 
158   KEEP ("1\0", "1", a, b, 2);
159   KEEP ("1",   "1\0", a, b, 2);
160 
161   KEEP ("12\0", "12", a, b, 2);
162   KEEP ("12",   "12\0", a, b, 2);
163 
164   KEEP ("111\0", "111", a, b, 3);
165   KEEP ("112", "112\0", a, b, 3);
166 
167   {
168     char a[8], b[8];
169     sink (a, b);
170     strcpy (a, s);
171     strcpy (b, t);
172     TEST_KEEP (0 == strncmp (a, b, sizeof a));
173   }
174 }
175 
176 /* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
177 
178    { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 11 "optimized" } }
179    { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 11 "optimized" } } */
180