summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/strlenopt-73.c
blob: 65239490628686b702ce3dcc88b3049363152641 (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
/* 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 stores
   involving PHI nodes with distinct strings of the same length of at
   least 16 bytes.

   { dg-do compile }
   { dg-options "-O2 -fdump-tree-optimized" }
   On strictly aligned targets the consecutive char assignments used
   by the test aren't merged.  When they involve multiple trailing nuls
   these assignments then defeat the strlen optimization as a result of
   pr83821.  When the bug is resolved the directive below can be removed.
   { dg-require-effective-target non_strict_align } */

#include "strlenopt.h"

#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

#define T(expect, N, ncpy, cond) do {		\
    char CONCAT (arr_, __LINE__)[N];		\
    char *pa = CONCAT (arr_, __LINE__);		\
    memcpy (pa, cond, ncpy);			\
    ELIM (!(expect strlen (pa)));		\
    sink (pa);					\
  } while (0)

void sink (void*);

const char a32[33] = "0123456789abcdef0123456789abcdef";
const char b32[33] = "fedcba9876543210fedcba9876543210";

const char a16[33] = "0123456789abcdef";
const char b16[33] = "fedcba9876543210";

int i0, i1, i2;

void test_copy_cond_equal_length (void)
{
  // The test below is represented as this:
  //   # iftmp.0_3 = PHI <&b16(2), &a16(3)>
  //   MEM <unsigned char[17]> [(char * {ref-all})&a]
  //     = MEM <unsigned char[17]> [(char * {ref-all})iftmp.0_3];
  //   _2 = strlen (&a);
  T (16 ==, 17, 17, i0 ? a16 : b16);
  T (16 ==, 17, 17, i0 ? a16 : b16);
  T (15 ==, 17, 16, (i0 ? a16 : b16) +  1);
  T (14 ==, 17, 15, (i0 ? a16 : b16) +  2);
  T ( 0 ==, 17,  1, (i0 ? a16 : b16) + 16);

  T (31 ==, 33, 32, (i0 ? a32 : b32) +  1);
  T (30 ==, 33, 31, (i0 ? a32 : b32) +  2);
  T (29 ==, 33, 30, (i0 ? a32 : b32) +  3);
  T ( 1 ==, 33,  2, (i0 ? a32 : b32) + 31);
  T ( 0 ==, 33,  1, (i0 ? a32 : b32) + 32);
}


const char a4[16] = "0123";
const char b4[16] = "3210";

void test_copy_cond_unequal_length_i64 (void)
{
  T (2 <, 16, 8, i0 ? a4 + 1 : b4 + 0);
  T (1 <, 16, 8, i0 ? a4 + 1 : b4 + 2);
  T (0 <, 16, 8, i0 ? a4 + 1 : b4 + 3);

  T (1 <, 16, 8, i0 ? a4 + 2 : b4 + 0);
  T (1 <, 16, 8, i0 ? a4 + 2 : b4 + 1);
  T (0 <, 16, 8, i0 ? a4 + 2 : b4 + 3);
}


#if __i386__ && __SIZEOF_INT128__ == 16

/* The following tests assume GCC transforms the memcpy calls into
   int128_t assignments which it does only on targets that define
   the MOVE_MAX macro to 16.  That's only s390 and i386 with
   int128_t support.  */

const char a8[32] = "01234567";
const char b8[32] = "76543210";

void test_copy_cond_unequal_length_i128 (void)
{
  T (6 <, 32, 16, i0 ? a8 + 1 : b8 + 0);
  T (5 <, 32, 16, i0 ? a8 + 1 : b8 + 2);
  T (4 <, 32, 16, i0 ? a8 + 1 : b8 + 3);
  T (3 <, 32, 16, i0 ? a8 + 1 : b8 + 4);
  T (2 <, 32, 16, i0 ? a8 + 1 : b8 + 5);
  T (1 <, 32, 16, i0 ? a8 + 1 : b8 + 6);
  T (0 <, 32, 16, i0 ? a8 + 1 : b8 + 7);

  T (5 <, 32, 16, i0 ? a8 + 2 : b8 + 0);
  T (5 <, 32, 16, i0 ? a8 + 2 : b8 + 1);
  T (3 <, 32, 16, i0 ? a8 + 2 : b8 + 3);
  T (2 <, 32, 16, i0 ? a8 + 2 : b8 + 4);
  T (1 <, 32, 16, i0 ? a8 + 2 : b8 + 5);
  T (0 <, 32, 16, i0 ? a8 + 2 : b8 + 6);

  T (4 <, 32, 16, i0 ? a8 + 3 : b8 + 0);
  T (4 <, 32, 16, i0 ? a8 + 3 : b8 + 1);
  T (4 <, 32, 16, i0 ? a8 + 3 : b8 + 2);
  T (3 <, 32, 16, i0 ? a8 + 3 : b8 + 4);
  T (2 <, 32, 16, i0 ? a8 + 3 : b8 + 5);
  T (1 <, 32, 16, i0 ? a8 + 3 : b8 + 6);
  T (0 <, 32, 16, i0 ? a8 + 3 : b8 + 7);

  T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 0);
  T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 1);
  T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 2);
  T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 3);
  T (2 <, 32, 16, i0 ? a8 + 4 : b8 + 5);
  T (1 <, 32, 16, i0 ? a8 + 4 : b8 + 6);
  T (0 <, 32, 16, i0 ? a8 + 4 : b8 + 7);
}

#endif   /* Support for i128_t stores.  */

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