summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/strlenopt-70.c
blob: 0853023c3b6814ef35a53d76c6214f852fabf162 (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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/* PR tree-optimization/91183 - strlen of a strcpy result with a conditional
   source not folded
   Test to verify that strlen can determine string lengths from wider stores
   than narrow characters.  This matters because on targets that can handle
   unaligned stores and where GCC lowers multi-character stores into smaller
   numbers of wider stores.
   { dg-do compile }
   { dg-options "-O2 -fdump-tree-optimized" }  */

#include "strlenopt.h"

#define CHAR_BIT __CHAR_BIT__

typedef __UINT16_TYPE__  uint16_t;
typedef __UINT32_TYPE__  uint32_t;
typedef __UINT64_TYPE__  uint64_t;
typedef __UINT64_TYPE__  uint64_t;

#define CAT(x, y) x ## y
#define CONCAT(x, y) CAT (x, y)
#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)

#define FAIL(name) do {				\
    extern void FAILNAME (name) (void);		\
    FAILNAME (name)();				\
  } while (0)

/* Macros to emit a call to function named
     call_failed_to_be_eliminated_on_line_NNN()
   for each call that's expected to be eliminated.  The dg-final
   scan-tree-dump-time directive at the bottom of the test verifies
   that no such call appears in output.  */
#define ELIM(expr)					\
  if ((expr)) FAIL (not_eliminated); else (void)0

/* Verify that 'strlen (A) EXPECT' is folded to true.  When non-null,
   the first sizeof (INIT) - 1 bytes of the INIT arrray are stored
   in A first, followed by *(TYPE*)A = ASSIGN.  */
#define T(init, type, off, assign, expect) do {			\
    char a[32];							\
    memcpy (a, init ? init : "", init ? sizeof init - 1 : 0);	\
    *(type*)(a + off) = assign;					\
    ELIM (!(strlen (a) expect));				\
  } while (0)

/* Same as T but works around the optimizer dropping the initializing
   store before the assignment and defeating the strlen optimization.  */
#define TX(init, type, off, assign, expect) do {		\
    char a[32];							\
    strcpy (a, init + 2);					\
    strcat (a, init + sizeof (init) - 3);			\
    *(type*)(a + off) = assign;					\
    ELIM (!(strlen (a) expect));				\
  } while (0)

/* Evaluates to an element at index I of the literal S padded with nuls
   on the right.  */
#define ELT(s, i)   ((s "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")[i])

#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* Form a big-endian 16, 32, 64, and 128-byte integer from a string.  */
#  define I16(s) (((uint16_t)ELT (s, 0) << 8) + (uint16_t)ELT (s, 1))
#  define I32(s)				\
  (((uint32_t)ELT (s, 0) << 24)			\
   + ((uint32_t)ELT (s, 1) << 16)		\
   + ((uint32_t)ELT (s, 2) << 8)		\
   + (uint32_t)ELT (s, 3))
#  define I64(s)				\
  (((uint64_t)ELT (s, 0) << 56)			\
   + ((uint64_t)ELT (s, 1) << 48)		\
   + ((uint64_t)ELT (s, 2) << 40)		\
   + ((uint64_t)ELT (s, 3) << 32)		\
   + ((uint64_t)ELT (s, 4) << 24)		\
   + ((uint64_t)ELT (s, 5) << 16)		\
   + ((uint64_t)ELT (s, 6) << 8)		\
   + ELT (s, 7))
#  define I128(s)				\
  (((uint128_t)ELT (s, 0) << (64 + 56))		\
   + ((uint128_t)ELT (s, 1) << (64 + 48))	\
   + ((uint128_t)ELT (s, 2) << (64 + 40))	\
   + ((uint128_t)ELT (s, 3) << (64 + 32))	\
   + ((uint128_t)ELT (s, 4) << (64 + 24))	\
   + ((uint128_t)ELT (s, 5) << (64 + 16))	\
   + ((uint128_t)ELT (s, 6) << (64 + 8))	\
   + ((uint128_t)ELT (s, 7) << 64)		\
   + ((uint128_t)ELT (s, 8) << 56)		\
   + ((uint128_t)ELT (s, 9) << 48)		\
   + ((uint128_t)ELT (s, 10) << 40)		\
   + ((uint128_t)ELT (s, 11) << 32)		\
   + ((uint128_t)ELT (s, 12) << 24)		\
   + ((uint128_t)ELT (s, 13) << 16)		\
   + ((uint128_t)ELT (s, 14) << 8)		\
   + (uint128_t)ELT (s, 15))

#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Form a little-endian 16, 32, 64, and 128-byte integer from a string.  */
#  define I16(s) (((uint16_t)ELT (s, 1) << 8) + (uint16_t)ELT (s, 0))
#  define I32(s)				\
  (((uint32_t)ELT (s, 3) << 24)			\
   + ((uint32_t)ELT (s, 2) << 16)		\
   + ((uint32_t)ELT (s, 1) << 8)		\
   + (uint32_t)ELT (s, 0))
#  define I64(s)				\
  (((uint64_t)ELT (s, 7) << 56)			\
   + ((uint64_t)ELT (s, 6) << 48)		\
   + ((uint64_t)ELT (s, 5) << 40)		\
   + ((uint64_t)ELT (s, 4) << 32)		\
   + ((uint64_t)ELT (s, 3) << 24)		\
   + ((uint64_t)ELT (s, 2) << 16)		\
   + ((uint64_t)ELT (s, 1) << 8)		\
   + ELT (s, 0))
#  define I128(s)				\
  (((uint128_t)ELT (s, 15) << (64 + 56))	\
   + ((uint128_t)ELT (s, 14) << (64 + 48))	\
   + ((uint128_t)ELT (s, 13) << (64 + 40))	\
   + ((uint128_t)ELT (s, 12) << (64 + 32))	\
   + ((uint128_t)ELT (s, 11) << (64 + 24))	\
   + ((uint128_t)ELT (s, 10) << (64 + 16))	\
   + ((uint128_t)ELT (s, 9) << (64 + 8))	\
   + ((uint128_t)ELT (s, 8) << 64)		\
   + ((uint128_t)ELT (s, 7) << 56)		\
   + ((uint128_t)ELT (s, 6) << 48)		\
   + ((uint128_t)ELT (s, 5) << 40)		\
   + ((uint128_t)ELT (s, 4) << 32)		\
   + ((uint128_t)ELT (s, 3) << 24)		\
   + ((uint128_t)ELT (s, 2) << 16)		\
   + ((uint128_t)ELT (s, 1) << 8)		\
   + (uint128_t)ELT (s, 0))
#endif

#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__

void store_16bit_be (void)
{
  T ("xxx", uint16_t, 0, 0x0001, == 0);
  T ("xxx", uint16_t, 0, 0x0010, == 0);
  T ("xxx", uint16_t, 0, 0x0011, == 0);
  T ("xxx", uint16_t, 0, 0x0100, == 1);
  T ("xxx", uint16_t, 0, 0x1000, == 1);
  T ("xxx", uint16_t, 0, 0x1100, == 1);
}

#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

void store_16bit_le (int i)
{
  uint16_t x0000 = I16 ("\0\0");
  uint16_t x0001 = 0x0001;
  uint16_t x0010 = 0x0010;
  uint16_t x0011 = 0x0011;
  uint16_t x0100 = 0x0100;
  uint16_t x1000 = 0x1000;
  uint16_t x1100 = 0x1100;

  T (0,        uint16_t, 0, x0000, == 0);
  T ("x",      uint16_t, 0, x0000, == 0);
  T ("xx",     uint16_t, 0, x0000, == 0);
  T ("xxxx",   uint16_t, 0, x0000, == 0);
  T (0,        uint16_t, 0, x0001, == 1);
  T ("\0\0\0", uint16_t, 0, x0001, == 1);
  T (0,        uint16_t, 0, x0010, == 1);
  T ("x\0\0",  uint16_t, 0, x0010, == 1);
  T (0,        uint16_t, 0, x0011, == 1);
  T ("xx\0",   uint16_t, 0, x0011, == 1);
  T (0,        uint16_t, 0, x0100, == 0);
  T ("\0\0\0", uint16_t, 0, x0100, == 0);
  T (0,        uint16_t, 0, x1000, == 0);
  T ("x\0\0",  uint16_t, 0, x1000, == 0);
  T (0,        uint16_t, 0, x1100, == 0);
  T ("xx\0",   uint16_t, 0, x1100, == 0);

  // FIXME: This fails because of the next test but succeeds on its own.
  // T (0,        uint16_t, 0, i ? x0001 : x0010, == 1);
  T ("xxx",    uint16_t, 0, i ? x0100 : x1100, == 0);
}

#endif

void store_32bit (volatile int i)
{
  T (0,      uint32_t, 0, 0, == 0);
  T ("x",    uint32_t, 0, 0, == 0);
  T ("xx",   uint32_t, 0, 0, == 0);
  T ("xxx",  uint32_t, 0, 0, == 0);
  T ("xxxx", uint32_t, 0, 0, == 0);

  T ("\0",   uint32_t, 1, 0, == 0);
  T ("x",    uint32_t, 1, 0, == 1);
  T ("xx",   uint32_t, 2, 0, == 2);
  T ("xxx",  uint32_t, 3, 0, == 3);

  T ("xxx",  uint32_t, 0, I32 ("\1\0\0\0"), == 1);
  T ("xxx",  uint32_t, 0, I32 ("\0\1\0\0"), == 0);
  T ("xxx",  uint32_t, 0, I32 ("\0\0\1\0"), == 0);
  T ("xxx",  uint32_t, 0, I32 ("\0\0\0\1"), == 0);

  T ("xxx",  uint32_t, 0, I32 ("\1\2\0\0"), == 2);
  T ("xxx",  uint32_t, 0, I32 ("\0\1\2\0"), == 0);
  T ("xxx",  uint32_t, 0, I32 ("\0\0\1\2"), == 0);

  T ("xxx",  uint32_t, 0, I32 ("\1\2\3\0"), == 3);
  T ("xxx",  uint32_t, 0, I32 ("\0\1\2\3"), == 0);

  uint32_t x123_ = I32 ("123\0");
  uint32_t x12__ = I32 ("12\0\0");
  uint32_t x1___ = I32 ("1\0\0\0");

  // FIXME: Upper bound not implemented yet.
  /* T ("xxxx", uint32_t, 0, i ? x123_ : x12__, <= 3); */
  T ("xxxx", uint32_t, 0, i ? x123_ : x12__, >= 2);
  T ("xxxx", uint32_t, 0, i ? x12__ : x123_, >= 2);
  /* T ("xxxx", uint32_t, 0, i ? x123_ : x1___, <= 3); */
  T ("xxxx", uint32_t, 0, i ? x123_ : x1___, >= 1);
  T ("xxxx", uint32_t, 0, i ? x1___ : x123_, >= 1);

  TX ("abcde",  uint32_t, 0, i ? I32 ("1234") : I32 ("1235"), == 5);
  TX ("abcde",  uint32_t, 1, i ? I32 ("1234") : I32 ("1235"), == 5);

  TX ("abcdef", uint32_t, 0, i ? I32 ("1235") : I32 ("1234"), == 6);
  TX ("abcdef", uint32_t, 1, i ? I32 ("1235") : I32 ("1234"), == 6);
  TX ("abcdef", uint32_t, 2, i ? I32 ("1235") : I32 ("1234"), == 6);
  TX ("abcdef", uint32_t, 3, i ? I32 ("124\0") : I32 ("123\0"), == 6);
  TX ("abcdef", uint32_t, 3, i ? I32 ("12\0\0") : I32 ("13\0\0"), == 5);

  TX ("abcdef", uint32_t, 3, i ? I32 ("12\0\0") : I32 ("123\0"), >= 5);
  /* FIXME: Upper bound not implemented yet.  */
  /* TX ("abcdef", uint32_t, 3, i ? I32 ("12\0\0") : I32 ("123\0"), < 7); */
}

void store_64bit (int i)
{
  T ("xxxxxxx", uint64_t, 0, I64 ("\1\0\0\0\0\0\0\0\0"), == 1);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\1\0\0\0\0\0\0\0"), == 0);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\0\1\0\0\0\0\0\0"), == 0);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\0\0\1\0\0\0\0\0"), == 0);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\0\0\0\1\0\0\0\0"), == 0);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\0\0\0\0\1\0\0\0"), == 0);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\0\0\0\0\0\1\0\0"), == 0);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\0\0\0\0\0\0\1\0"), == 0);

  T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\0\0\0\0\0\0\0"), == 2);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\1\2\0\0\0\0\0\0"), == 0);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\0\1\2\0\0\0\0\0"), == 0);

  T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\3\0\0\0\0\0\0"), == 3);
  T ("xxxxxxx", uint64_t, 0, I64 ("\0\1\2\3\0\0\0\0\0"), == 0);

  T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\3\4\0\0\0\0\0"), == 4);
  T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\3\4\5\0\0\0\0"), == 5);
  T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\3\4\5\6\0\0\0"), == 6);
  T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\3\4\5\6\7\0\0"), == 7);

  uint64_t x7777777_ = I64 ("\7\7\7\7\7\7\7");
  uint64_t x666666__ = I64 ("\6\6\6\6\6\6\0");
  uint64_t x4444____ = I64 ("\4\4\4\4\0\0\0");
  uint64_t x4343____ = I64 ("\4\3\4\3\0\0\0");
  uint64_t x1_______ = I64 ("\1\0\0\0\0\0\0");

  /* FIXME: Upper bound not implemented yet.  */
  /* T ("x\0xxxxxx", uint64_t, 0, i ? x7777777_ : x666666__, <= 7); */
  T ("xx\0xxxxx", uint64_t, 0, i ? x7777777_ : x666666__, >= 6);
  T ("xxx\0xxxx", uint64_t, 1, i ? x7777777_ : x666666__, >= 7);
  /* T ("xxx\0xxxx", uint64_t, 0, i ? x666666__ : x1, <= 6); */
  T ("xxxx\0xxx", uint64_t, 0, i ? x666666__ : x1_______, >= 1);
  T ("xxxxxx\0x", uint64_t, 0, i ? x4444____ : x4343____, == 4);
}

#if __SIZEOF_INT128__

typedef __uint128_t     uint128_t;

void store_128bit (void)
{
  uint128_t x1    = I128 ("\1");
  uint128_t x1z1  = I128 ("\0\1");
  uint128_t x2z1  = I128 ("\0\0\1");
  uint128_t x3z1  = I128 ("\0\0\0\1");
  uint128_t x4z1  = I128 ("\0\0\0\0\1");
  uint128_t x5z1  = I128 ("\0\0\0\0\0\1");
  uint128_t x6z1  = I128 ("\0\0\0\0\0\0\1");
  uint128_t x7z1  = I128 ("\0\0\0\0\0\0\0\1");
  uint128_t x8z1  = I128 ("\0\0\0\0\0\0\0\0\1");
  uint128_t x9z1  = I128 ("\0\0\0\0\0\0\0\0\0\1");
  uint128_t x10z1 = I128 ("\0\0\0\0\0\0\0\0\0\0\1");
  uint128_t x11z1 = I128 ("\0\0\0\0\0\0\0\0\0\0\0\1");
  uint128_t x12z1 = I128 ("\0\0\0\0\0\0\0\0\0\0\0\0\1");
  uint128_t x13z1 = I128 ("\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
  uint128_t x14z1 = I128 ("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
  uint128_t x15z1 = I128 ("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");

  T ("xxxxxxx", uint128_t, 0, x1, == 1);
  T ("xxxxxxx", uint128_t, 0, x1z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x2z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x3z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x4z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x5z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x6z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x7z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x8z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x9z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x10z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x11z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x12z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x13z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x14z1, == 0);
  T ("xxxxxxx", uint128_t, 0, x15z1, == 0);

  T ("xxxxxxx", uint128_t, 0, I128 ("\2\1"), == 2);
  T ("xxxxxxx", uint128_t, 0, I128 ("\0\2\1"), == 0);

  T ("xxxxxxx", uint128_t, 0, I128 ("\3\2\1"), == 3);
  T ("xxxxxxx", uint128_t, 0, I128 ("\0\3\2\1"), == 0);

  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4"), == 4);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5"), == 5);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6"), == 6);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7"), == 7);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10"), == 8);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10\11"), == 9);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10\11\12"), == 10);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10\11\12\13"), == 11);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10\11\12\13\14"), == 12);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10\11\12\13\14\15"), == 13);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10\11\12\13\14\15\16"), == 14);
  T ("xxxxxxx", uint128_t, 0, I128 ("\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"), == 15);
}

#endif   // __SIZEOF_INT128__

/* { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
   { dg-final { scan-tree-dump-times "_not_eliminated_" 0 "optimized" } } */