aboutsummaryrefslogtreecommitdiff
path: root/gcc/genopinit.c
blob: 3efb71e249e44259e5154bf94d6f2b325dcea327 (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
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
/* Generate code to initialize optabs from machine description.
   Copyright (C) 1993-2013 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */


#include "bconfig.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "errors.h"
#include "gensupport.h"


#define DEF_RTL_EXPR(V, N, X, C) #V,

static const char * const rtx_upname[] = {
#include "rtl.def"
};

#undef DEF_RTL_EXPR


/* The entries in optabs.def are categorized:
     C: A "conversion" optab, which uses two modes; has libcall data.
     N: A "normal" optab, which uses one mode; has libcall data.
     D: A "direct" optab, which uses one mode; does not have libcall data.
     V: An "oVerflow" optab.  Like N, but does not record its code in
        code_to_optab.

     CX, NX, VX: An extra pattern entry for a conversion or normal optab.

   These patterns may be present in the MD file with names that contain
   the mode(s) used and the name of the operation.  This array contains
   a list of optabs that need to be initialized.  Within each name,
   $a and $b are used to match a short mode name (the part of the mode
   name not including `mode' and converted to lower-case).

   $I means that only full integer modes should be considered for the
   next mode, and $F means that only float modes should be considered.
   $P means that both full and partial integer modes should be considered.
   $Q means that only fixed-point modes should be considered.

   The pattern may be NULL if the optab exists only for the libcalls
   that we plan to attach to it, and there are no named patterns in
   the md files.  */

#define OPTAB_CL(name, pat, c, b, l)		name,
#define OPTAB_CX(name, pat)
#define OPTAB_CD(name, pat)			name,
#define OPTAB_NL(name, pat, c, b, s, l)		name,
#define OPTAB_NC(name, pat, c)			name,
#define OPTAB_NX(name, pat)
#define OPTAB_VL(name, pat, c, b, s, l)		name,
#define OPTAB_VC(name, pat, c)			name,
#define OPTAB_VX(name, pat)
#define OPTAB_DC(name, pat, c)			name,
#define OPTAB_D(name, pat)			name,

typedef enum optab_tag {
  unknown_optab,
#include "optabs.def"
  NUM_OPTABS
} optab;

#undef OPTAB_CL
#undef OPTAB_CX
#undef OPTAB_CD
#undef OPTAB_NL
#undef OPTAB_NC
#undef OPTAB_NX
#undef OPTAB_VL
#undef OPTAB_VC
#undef OPTAB_VX
#undef OPTAB_DC
#undef OPTAB_D

#define NS "NULL"
#define ZS "'\\0'"
#define OPTAB_CL(o, p, c, b, l)    { #o, p, #b, ZS, #l, o, c, UNKNOWN, 1 },
#define OPTAB_CX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 1 },
#define OPTAB_CD(o, p) { #o, p, NS, ZS, NS, o, UNKNOWN, UNKNOWN, 2 },
#define OPTAB_NL(o, p, c, b, s, l) { #o, p, #b, #s, #l, o, c, c, 3 },
#define OPTAB_NC(o, p, c)          { #o, p, NS, ZS, NS, o, c, c, 3 },
#define OPTAB_NX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 3 },
#define OPTAB_VL(o, p, c, b, s, l) { #o, p, #b, #s, #l, o, c, UNKNOWN, 3 },
#define OPTAB_VC(o, p, c)          { #o, p, NS, ZS, NS, o, c, UNKNOWN, 3 },
#define OPTAB_VX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 3 },
#define OPTAB_DC(o, p, c)          { #o, p, NS, ZS, NS, o, c, c, 4 },
#define OPTAB_D(o, p)  { #o, p, NS, ZS, NS, o, UNKNOWN, UNKNOWN, 4 },

typedef struct optab_def_d
{
  const char *name;
  const char *pattern;
  const char *base;
  const char *suffix;
  const char *libcall;
  unsigned int op;
  enum rtx_code fcode;
  enum rtx_code rcode;
  unsigned int kind;
} optab_def;

static optab_def optabs[] = {
  { "unknown_optab", NULL, NS, ZS, NS, unknown_optab, UNKNOWN, UNKNOWN, 0 },
#include "optabs.def"
};

#undef OPTAB_CL
#undef OPTAB_CX
#undef OPTAB_CD
#undef OPTAB_NL
#undef OPTAB_NC
#undef OPTAB_NX
#undef OPTAB_VL
#undef OPTAB_VC
#undef OPTAB_VX
#undef OPTAB_DC
#undef OPTAB_D

/* Vector in which to collect insns that match.  */

typedef struct pattern_d
{
  const char *name;
  unsigned int op;
  unsigned int m1, m2;
  unsigned int sort_num;
} pattern;


static vec<pattern> patterns;

static bool
match_pattern (pattern *p, const char *name, const char *pat)
{
  bool force_float = false;
  bool force_int = false;
  bool force_partial_int = false;
  bool force_fixed = false;

  if (pat == NULL)
    return false;
  for (; ; ++pat)
    {
      if (*pat != '$')
	{
	  if (*pat != *name++)
	    return false;
	  if (*pat == '\0')
	    return true;
	  continue;
	}
      switch (*++pat)
	{
	case 'I':
	  force_int = 1;
	  break;
	case 'P':
	  force_partial_int = 1;
	  break;
	case 'F':
	  force_float = 1;
	  break;
	case 'Q':
	  force_fixed = 1;
	  break;

	case 'a':
	case 'b':
	  {
	    int i;

	    /* This loop will stop at the first prefix match, so
	       look through the modes in reverse order, in case
	       there are extra CC modes and CC is a prefix of the
	       CC modes (as it should be).  */
	    for (i = (MAX_MACHINE_MODE) - 1; i >= 0; i--)
	      {
		const char *p, *q;
		for (p = GET_MODE_NAME (i), q = name; *p; p++, q++)
		  if (TOLOWER (*p) != *q)
		    break;
		if (*p == 0
		    && (! force_int || mode_class[i] == MODE_INT
			|| mode_class[i] == MODE_VECTOR_INT)
		    && (! force_partial_int
			|| mode_class[i] == MODE_INT
			|| mode_class[i] == MODE_PARTIAL_INT
			|| mode_class[i] == MODE_VECTOR_INT)
		    && (! force_float
			|| mode_class[i] == MODE_FLOAT
			|| mode_class[i] == MODE_DECIMAL_FLOAT
			|| mode_class[i] == MODE_COMPLEX_FLOAT
			|| mode_class[i] == MODE_VECTOR_FLOAT)
		    && (! force_fixed
			|| mode_class[i] == MODE_FRACT
			|| mode_class[i] == MODE_UFRACT
			|| mode_class[i] == MODE_ACCUM
			|| mode_class[i] == MODE_UACCUM
			|| mode_class[i] == MODE_VECTOR_FRACT
			|| mode_class[i] == MODE_VECTOR_UFRACT
			|| mode_class[i] == MODE_VECTOR_ACCUM
			|| mode_class[i] == MODE_VECTOR_UACCUM))
		  break;
	      }

	    if (i < 0)
	      return false;
	    name += strlen (GET_MODE_NAME (i));
	    if (*pat == 'a')
	      p->m1 = i;
	    else
	      p->m2 = i;

	    force_int = false;
	    force_partial_int = false;
	    force_float = false;
	    force_fixed = false;
	  }
	  break;

	default:
	  gcc_unreachable ();
	}
    }
}

static void
gen_insn (rtx insn)
{
  const char *name = XSTR (insn, 0);
  pattern p;
  unsigned pindex;

  /* Don't mention "unnamed" instructions.  */
  if (*name == 0 || *name == '*')
    return;
  p.name = name;

  /* See if NAME matches one of the patterns we have for the optabs
     we know about.  */
  for (pindex = 0; pindex < ARRAY_SIZE (optabs); pindex++)
    {
      p.m1 = p.m2 = 0;
      if (match_pattern (&p, name, optabs[pindex].pattern))
	{
	  p.op = optabs[pindex].op;
	  p.sort_num = (p.op << 16) | (p.m2 << 8) | p.m1;
	  patterns.safe_push (p);
	  return;
	}
    }
}

static int
pattern_cmp (const void *va, const void *vb)
{
  const pattern *a = (const pattern *)va;
  const pattern *b = (const pattern *)vb;
  return a->sort_num - b->sort_num;
}

static int
optab_kind_cmp (const void *va, const void *vb)
{
  const optab_def *a = (const optab_def *)va;
  const optab_def *b = (const optab_def *)vb;
  int diff = a->kind - b->kind;
  if (diff == 0)
    diff = a->op - b->op;
  return diff;
}

static int
optab_rcode_cmp (const void *va, const void *vb)
{
  const optab_def *a = (const optab_def *)va;
  const optab_def *b = (const optab_def *)vb;
  return a->rcode - b->rcode;
}

static const char *header_file_name = "init-opinit.h";
static const char *source_file_name = "init-opinit.c";

static bool
handle_arg (const char *arg)
{
  switch (arg[1])
    {
    case 'h':
      header_file_name = &arg[2];
      return true;
    case 'c':
      source_file_name = &arg[2];
      return true;
    default:
      return false;
    }
}

static FILE *
open_outfile (const char *file_name)
{
  FILE *f = fopen (file_name, "w");
  if (!f)
    fatal ("cannot open file %s: %s", file_name, xstrerror (errno));
  fprintf (f,
	   "/* Generated automatically by the program `genopinit'\n"
	   "   from the machine description file `md'.  */\n\n");
  return f;
}

int
main (int argc, char **argv)
{
  FILE *h_file, *s_file;
  unsigned int i, j, n, last_kind[5];
  pattern *p;

  progname = "genopinit";

  if (NUM_OPTABS > 0xffff || MAX_MACHINE_MODE >= 0xff)
    fatal ("genopinit range assumptions invalid");

  if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
    return (FATAL_EXIT_CODE);

  h_file = open_outfile (header_file_name);
  s_file = open_outfile (source_file_name);

  /* Read the machine description.  */
  while (1)
    {
      int line_no, insn_code_number = 0;
      rtx desc = read_md_rtx (&line_no, &insn_code_number);
      if (desc == NULL)
	break;
      if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND)
	gen_insn (desc);
    }

  /* Sort the collected patterns.  */
  qsort (patterns.address (), patterns.length (),
	 sizeof (pattern), pattern_cmp);

  /* Now that we've handled the "extra" patterns, eliminate them from
     the optabs array.  That way they don't get in the way below.  */
  n = ARRAY_SIZE (optabs);
  for (i = 0; i < n; )
    if (optabs[i].base == NULL)
      optabs[i] = optabs[--n];
    else
      ++i;

  /* Sort the (real) optabs.  Better than forcing the optabs.def file to
     remain sorted by kind.  We also scrogged any real ordering with the
     purging of the X patterns above.  */
  qsort (optabs, n, sizeof (optab_def), optab_kind_cmp);

  /* Emit the optab enumeration for the header file.  */
  fprintf (h_file, "enum optab_tag {\n");
  for (i = j = 0; i < n; ++i)
    {
      optabs[i].op = i;
      fprintf (h_file, "  %s,\n", optabs[i].name);
      if (optabs[i].kind != j)
	last_kind[j++] = i - 1;
    }
  fprintf (h_file, "  FIRST_CONV_OPTAB = %s,\n", optabs[last_kind[0]+1].name);
  fprintf (h_file, "  LAST_CONVLIB_OPTAB = %s,\n", optabs[last_kind[1]].name);
  fprintf (h_file, "  LAST_CONV_OPTAB = %s,\n", optabs[last_kind[2]].name);
  fprintf (h_file, "  FIRST_NORM_OPTAB = %s,\n", optabs[last_kind[2]+1].name);
  fprintf (h_file, "  LAST_NORMLIB_OPTAB = %s,\n", optabs[last_kind[3]].name);
  fprintf (h_file, "  LAST_NORM_OPTAB = %s\n", optabs[i-1].name);
  fprintf (h_file, "};\n\n");

  fprintf (h_file, "#define NUM_OPTABS          %u\n", n);
  fprintf (h_file, "#define NUM_CONVLIB_OPTABS  %u\n",
	   last_kind[1] - last_kind[0]);
  fprintf (h_file, "#define NUM_NORMLIB_OPTABS  %u\n",
	   last_kind[3] - last_kind[2]);
  fprintf (h_file, "#define NUM_OPTAB_PATTERNS  %u\n",
	   (unsigned) patterns.length ());

  fprintf (s_file,
	   "#include \"config.h\"\n"
	   "#include \"system.h\"\n"
	   "#include \"coretypes.h\"\n"
	   "#include \"tm.h\"\n"
	   "#include \"tree.h\"\n"
	   "#include \"rtl.h\"\n"
	   "#include \"tm_p.h\"\n"
	   "#include \"flags.h\"\n"
	   "#include \"insn-config.h\"\n"
	   "#include \"expr.h\"\n"
	   "#include \"optabs.h\"\n"
	   "\n"
	   "struct optab_pat {\n"
	   "  unsigned scode;\n"
	   "  enum insn_code icode;\n"
	   "};\n\n");

  fprintf (s_file,
	   "static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {\n");
  for (i = 0; patterns.iterate (i, &p); ++i)
    fprintf (s_file, "  { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name);
  fprintf (s_file, "};\n\n");

  fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n");
  fprintf (s_file, "  bool *ena = optabs->pat_enable;\n");
  for (i = 0; patterns.iterate (i, &p); ++i)
    fprintf (s_file, "  ena[%u] = HAVE_%s;\n", i, p->name);
  fprintf (s_file, "}\n\n");

  /* Perform a binary search on a pre-encoded optab+mode*2.  */
  /* ??? Perhaps even better to generate a minimal perfect hash.
     Using gperf directly is awkward since it's so geared to working
     with strings.  Plus we have no visibility into the ordering of
     the hash entries, which complicates the pat_enable array.  */
  fprintf (s_file,
	   "static int\n"
	   "lookup_handler (unsigned scode)\n"
	   "{\n"
	   "  int l = 0, h = ARRAY_SIZE (pats), m;\n"
	   "  while (h > l)\n"
	   "    {\n"
	   "      m = (h + l) / 2;\n"
	   "      if (scode == pats[m].scode)\n"
	   "        return m;\n"
	   "      else if (scode < pats[m].scode)\n"
	   "        h = m;\n"
	   "      else\n"
	   "        l = m + 1;\n"
	   "    }\n"
	   "  return -1;\n"
	   "}\n\n");

  fprintf (s_file,
	   "enum insn_code\n"
	   "raw_optab_handler (unsigned scode)\n"
	   "{\n"
	   "  int i = lookup_handler (scode);\n"
	   "  return (i >= 0 && this_fn_optabs->pat_enable[i]\n"
	   "          ? pats[i].icode : CODE_FOR_nothing);\n"
	   "}\n\n");

  fprintf (s_file,
	   "bool\n"
	   "swap_optab_enable (optab op, enum machine_mode m, bool set)\n"
	   "{\n"
	   "  unsigned scode = (op << 16) | m;\n"
	   "  int i = lookup_handler (scode);\n"
	   "  if (i >= 0)\n"
	   "    {\n"
	   "      bool ret = this_fn_optabs->pat_enable[i];\n"
	   "      this_fn_optabs->pat_enable[i] = set;\n"
	   "      return ret;\n"
	   "    }\n"
	   "  else\n"
	   "    {\n"
	   "      gcc_assert (!set);\n"
	   "      return false;\n"
	   "    }\n"
	   "}\n\n");

  /* C++ (even G++) does not support (non-trivial) designated initializers.
     To work around that, generate these arrays programatically rather than
     by our traditional multiple inclusion of def files.  */

  fprintf (s_file,
	   "const struct convert_optab_libcall_d "
	   "convlib_def[NUM_CONVLIB_OPTABS] = {\n");
  for (i = last_kind[0] + 1; i <= last_kind[1]; ++i)
    fprintf (s_file, "  { %s, %s },\n", optabs[i].base, optabs[i].libcall);
  fprintf (s_file, "};\n\n");

  fprintf (s_file,
	   "const struct optab_libcall_d "
	   "normlib_def[NUM_NORMLIB_OPTABS] = {\n");
  for (i = last_kind[2] + 1; i <= last_kind[3]; ++i)
    fprintf (s_file, "  { %s, %s, %s },\n",
	     optabs[i].suffix, optabs[i].base, optabs[i].libcall);
  fprintf (s_file, "};\n\n");

  fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n");
  for (i = 0; i < n; ++i)
    fprintf (s_file, "  %s,\n", rtx_upname[optabs[i].fcode]);
  fprintf (s_file, "};\n\n");

  qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp);

  fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n");
  for (j = 0; optabs[j].rcode == UNKNOWN; ++j)
    continue;
  for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i)
    {
      if (j < n && optabs[j].rcode == i)
	fprintf (s_file, "  %s,\n", optabs[j++].name);
      else
	fprintf (s_file, "  unknown_optab,\n");
    }
  fprintf (s_file, "};\n\n");

  return (fclose (h_file) == 0 && fclose (s_file) == 0
	  ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
}
id='n2182' href='#n2182'>2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026
/* Optimization of PHI nodes by converting them into straightline code.
   Copyright (C) 2004-2019 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.

GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "insn-codes.h"
#include "rtl.h"
#include "tree.h"
#include "gimple.h"
#include "cfghooks.h"
#include "tree-pass.h"
#include "ssa.h"
#include "optabs-tree.h"
#include "insn-config.h"
#include "gimple-pretty-print.h"
#include "fold-const.h"
#include "stor-layout.h"
#include "cfganal.h"
#include "gimplify.h"
#include "gimple-iterator.h"
#include "gimplify-me.h"
#include "tree-cfg.h"
#include "tree-dfa.h"
#include "domwalk.h"
#include "cfgloop.h"
#include "tree-data-ref.h"
#include "tree-scalar-evolution.h"
#include "tree-inline.h"
#include "params.h"
#include "case-cfn-macros.h"

static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
				   tree, tree);
static bool conditional_replacement (basic_block, basic_block,
				     edge, edge, gphi *, tree, tree);
static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree,
						gimple *);
static int value_replacement (basic_block, basic_block,
			      edge, edge, gimple *, tree, tree);
static bool minmax_replacement (basic_block, basic_block,
				edge, edge, gimple *, tree, tree);
static bool abs_replacement (basic_block, basic_block,
			     edge, edge, gimple *, tree, tree);
static bool cond_removal_in_popcount_pattern (basic_block, basic_block,
					      edge, edge, gimple *, tree, tree);
static bool cond_store_replacement (basic_block, basic_block, edge, edge,
				    hash_set<tree> *);
static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block);
static hash_set<tree> * get_non_trapping ();
static void replace_phi_edge_with_variable (basic_block, edge, gimple *, tree);
static void hoist_adjacent_loads (basic_block, basic_block,
				  basic_block, basic_block);
static bool gate_hoist_loads (void);

/* This pass tries to transform conditional stores into unconditional
   ones, enabling further simplifications with the simpler then and else
   blocks.  In particular it replaces this:

     bb0:
       if (cond) goto bb2; else goto bb1;
     bb1:
       *p = RHS;
     bb2:

   with

     bb0:
       if (cond) goto bb1; else goto bb2;
     bb1:
       condtmp' = *p;
     bb2:
       condtmp = PHI <RHS, condtmp'>
       *p = condtmp;

   This transformation can only be done under several constraints,
   documented below.  It also replaces:

     bb0:
       if (cond) goto bb2; else goto bb1;
     bb1:
       *p = RHS1;
       goto bb3;
     bb2:
       *p = RHS2;
     bb3:

   with

     bb0:
       if (cond) goto bb3; else goto bb1;
     bb1:
     bb3:
       condtmp = PHI <RHS1, RHS2>
       *p = condtmp;  */

static unsigned int
tree_ssa_cs_elim (void)
{
  unsigned todo;
  /* ???  We are not interested in loop related info, but the following
     will create it, ICEing as we didn't init loops with pre-headers.
     An interfacing issue of find_data_references_in_bb.  */
  loop_optimizer_init (LOOPS_NORMAL);
  scev_initialize ();
  todo = tree_ssa_phiopt_worker (true, false, false);
  scev_finalize ();
  loop_optimizer_finalize ();
  return todo;
}

/* Return the singleton PHI in the SEQ of PHIs for edges E0 and E1. */

static gphi *
single_non_singleton_phi_for_edges (gimple_seq seq, edge e0, edge e1)
{
  gimple_stmt_iterator i;
  gphi *phi = NULL;
  if (gimple_seq_singleton_p (seq))
    return as_a <gphi *> (gsi_stmt (gsi_start (seq)));
  for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
    {
      gphi *p = as_a <gphi *> (gsi_stmt (i));
      /* If the PHI arguments are equal then we can skip this PHI. */
      if (operand_equal_for_phi_arg_p (gimple_phi_arg_def (p, e0->dest_idx),
				       gimple_phi_arg_def (p, e1->dest_idx)))
	continue;

      /* If we already have a PHI that has the two edge arguments are
	 different, then return it is not a singleton for these PHIs. */
      if (phi)
	return NULL;

      phi = p;
    }
  return phi;
}

/* The core routine of conditional store replacement and normal
   phi optimizations.  Both share much of the infrastructure in how
   to match applicable basic block patterns.  DO_STORE_ELIM is true
   when we want to do conditional store replacement, false otherwise.
   DO_HOIST_LOADS is true when we want to hoist adjacent loads out
   of diamond control flow patterns, false otherwise.  */
static unsigned int
tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p)
{
  basic_block bb;
  basic_block *bb_order;
  unsigned n, i;
  bool cfgchanged = false;
  hash_set<tree> *nontrap = 0;

  if (do_store_elim)
    /* Calculate the set of non-trapping memory accesses.  */
    nontrap = get_non_trapping ();

  /* Search every basic block for COND_EXPR we may be able to optimize.

     We walk the blocks in order that guarantees that a block with
     a single predecessor is processed before the predecessor.
     This ensures that we collapse inner ifs before visiting the
     outer ones, and also that we do not try to visit a removed
     block.  */
  bb_order = single_pred_before_succ_order ();
  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;

  for (i = 0; i < n; i++)
    {
      gimple *cond_stmt;
      gphi *phi;
      basic_block bb1, bb2;
      edge e1, e2;
      tree arg0, arg1;

      bb = bb_order[i];

      cond_stmt = last_stmt (bb);
      /* Check to see if the last statement is a GIMPLE_COND.  */
      if (!cond_stmt
          || gimple_code (cond_stmt) != GIMPLE_COND)
        continue;

      e1 = EDGE_SUCC (bb, 0);
      bb1 = e1->dest;
      e2 = EDGE_SUCC (bb, 1);
      bb2 = e2->dest;

      /* We cannot do the optimization on abnormal edges.  */
      if ((e1->flags & EDGE_ABNORMAL) != 0
          || (e2->flags & EDGE_ABNORMAL) != 0)
       continue;

      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
      if (EDGE_COUNT (bb1->succs) == 0
          || bb2 == NULL
	  || EDGE_COUNT (bb2->succs) == 0)
        continue;

      /* Find the bb which is the fall through to the other.  */
      if (EDGE_SUCC (bb1, 0)->dest == bb2)
        ;
      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
        {
	  std::swap (bb1, bb2);
	  std::swap (e1, e2);
	}
      else if (do_store_elim
	       && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
	{
	  basic_block bb3 = EDGE_SUCC (bb1, 0)->dest;

	  if (!single_succ_p (bb1)
	      || (EDGE_SUCC (bb1, 0)->flags & EDGE_FALLTHRU) == 0
	      || !single_succ_p (bb2)
	      || (EDGE_SUCC (bb2, 0)->flags & EDGE_FALLTHRU) == 0
	      || EDGE_COUNT (bb3->preds) != 2)
	    continue;
	  if (cond_if_else_store_replacement (bb1, bb2, bb3))
	    cfgchanged = true;
	  continue;
	}
      else if (do_hoist_loads
	       && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
	{
	  basic_block bb3 = EDGE_SUCC (bb1, 0)->dest;

	  if (!FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (cond_stmt)))
	      && single_succ_p (bb1)
	      && single_succ_p (bb2)
	      && single_pred_p (bb1)
	      && single_pred_p (bb2)
	      && EDGE_COUNT (bb->succs) == 2
	      && EDGE_COUNT (bb3->preds) == 2
	      /* If one edge or the other is dominant, a conditional move
		 is likely to perform worse than the well-predicted branch.  */
	      && !predictable_edge_p (EDGE_SUCC (bb, 0))
	      && !predictable_edge_p (EDGE_SUCC (bb, 1)))
	    hoist_adjacent_loads (bb, bb1, bb2, bb3);
	  continue;
	}
      else
	continue;

      e1 = EDGE_SUCC (bb1, 0);

      /* Make sure that bb1 is just a fall through.  */
      if (!single_succ_p (bb1)
	  || (e1->flags & EDGE_FALLTHRU) == 0)
        continue;

      /* Also make sure that bb1 only have one predecessor and that it
	 is bb.  */
      if (!single_pred_p (bb1)
          || single_pred (bb1) != bb)
	continue;

      if (do_store_elim)
	{
	  /* bb1 is the middle block, bb2 the join block, bb the split block,
	     e1 the fallthrough edge from bb1 to bb2.  We can't do the
	     optimization if the join block has more than two predecessors.  */
	  if (EDGE_COUNT (bb2->preds) > 2)
	    continue;
	  if (cond_store_replacement (bb1, bb2, e1, e2, nontrap))
	    cfgchanged = true;
	}
      else
	{
	  gimple_seq phis = phi_nodes (bb2);
	  gimple_stmt_iterator gsi;
	  bool candorest = true;

	  /* Value replacement can work with more than one PHI
	     so try that first. */
	  if (!early_p)
	    for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
	      {
		phi = as_a <gphi *> (gsi_stmt (gsi));
		arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
		arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
		if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2)
		  {
		    candorest = false;
		    cfgchanged = true;
		    break;
		  }
	      }

	  if (!candorest)
	    continue;

	  phi = single_non_singleton_phi_for_edges (phis, e1, e2);
	  if (!phi)
	    continue;

	  arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
	  arg1 = gimple_phi_arg_def (phi, e2->dest_idx);

	  /* Something is wrong if we cannot find the arguments in the PHI
	     node.  */
	  gcc_assert (arg0 != NULL_TREE && arg1 != NULL_TREE);

	  gphi *newphi = factor_out_conditional_conversion (e1, e2, phi,
							    arg0, arg1,
							    cond_stmt);
	  if (newphi != NULL)
	    {
	      phi = newphi;
	      /* factor_out_conditional_conversion may create a new PHI in
		 BB2 and eliminate an existing PHI in BB2.  Recompute values
		 that may be affected by that change.  */
	      arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
	      arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
	      gcc_assert (arg0 != NULL_TREE && arg1 != NULL_TREE);
	    }

	  /* Do the replacement of conditional if it can be done.  */
	  if (two_value_replacement (bb, bb1, e2, phi, arg0, arg1))
	    cfgchanged = true;
	  else if (!early_p
		   && conditional_replacement (bb, bb1, e1, e2, phi,
					       arg0, arg1))
	    cfgchanged = true;
	  else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
	    cfgchanged = true;
	  else if (!early_p
		   && cond_removal_in_popcount_pattern (bb, bb1, e1, e2,
							phi, arg0, arg1))
	    cfgchanged = true;
	  else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
	    cfgchanged = true;
	}
    }

  free (bb_order);

  if (do_store_elim)
    delete nontrap;
  /* If the CFG has changed, we should cleanup the CFG.  */
  if (cfgchanged && do_store_elim)
    {
      /* In cond-store replacement we have added some loads on edges
         and new VOPS (as we moved the store, and created a load).  */
      gsi_commit_edge_inserts ();
      return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
    }
  else if (cfgchanged)
    return TODO_cleanup_cfg;
  return 0;
}

/* Replace PHI node element whose edge is E in block BB with variable NEW.
   Remove the edge from COND_BLOCK which does not lead to BB (COND_BLOCK
   is known to have two edges, one of which must reach BB).  */

static void
replace_phi_edge_with_variable (basic_block cond_block,
				edge e, gimple *phi, tree new_tree)
{
  basic_block bb = gimple_bb (phi);
  basic_block block_to_remove;
  gimple_stmt_iterator gsi;

  /* Change the PHI argument to new.  */
  SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new_tree);

  /* Remove the empty basic block.  */
  if (EDGE_SUCC (cond_block, 0)->dest == bb)
    {
      EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU;
      EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
      EDGE_SUCC (cond_block, 0)->probability = profile_probability::always ();

      block_to_remove = EDGE_SUCC (cond_block, 1)->dest;
    }
  else
    {
      EDGE_SUCC (cond_block, 1)->flags |= EDGE_FALLTHRU;
      EDGE_SUCC (cond_block, 1)->flags
	&= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
      EDGE_SUCC (cond_block, 1)->probability = profile_probability::always ();

      block_to_remove = EDGE_SUCC (cond_block, 0)->dest;
    }
  delete_basic_block (block_to_remove);

  /* Eliminate the COND_EXPR at the end of COND_BLOCK.  */
  gsi = gsi_last_bb (cond_block);
  gsi_remove (&gsi, true);

  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file,
	      "COND_EXPR in block %d and PHI in block %d converted to straightline code.\n",
	      cond_block->index,
	      bb->index);
}

/* PR66726: Factor conversion out of COND_EXPR.  If the arguments of the PHI
   stmt are CONVERT_STMT, factor out the conversion and perform the conversion
   to the result of PHI stmt.  COND_STMT is the controlling predicate.
   Return the newly-created PHI, if any.  */

static gphi *
factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
				   tree arg0, tree arg1, gimple *cond_stmt)
{
  gimple *arg0_def_stmt = NULL, *arg1_def_stmt = NULL, *new_stmt;
  tree new_arg0 = NULL_TREE, new_arg1 = NULL_TREE;
  tree temp, result;
  gphi *newphi;
  gimple_stmt_iterator gsi, gsi_for_def;
  location_t locus = gimple_location (phi);
  enum tree_code convert_code;

  /* Handle only PHI statements with two arguments.  TODO: If all
     other arguments to PHI are INTEGER_CST or if their defining
     statement have the same unary operation, we can handle more
     than two arguments too.  */
  if (gimple_phi_num_args (phi) != 2)
    return NULL;

  /* First canonicalize to simplify tests.  */
  if (TREE_CODE (arg0) != SSA_NAME)
    {
      std::swap (arg0, arg1);
      std::swap (e0, e1);
    }

  if (TREE_CODE (arg0) != SSA_NAME
      || (TREE_CODE (arg1) != SSA_NAME
	  && TREE_CODE (arg1) != INTEGER_CST))
    return NULL;

  /* Check if arg0 is an SSA_NAME and the stmt which defines arg0 is
     a conversion.  */
  arg0_def_stmt = SSA_NAME_DEF_STMT (arg0);
  if (!gimple_assign_cast_p (arg0_def_stmt))
    return NULL;

  /* Use the RHS as new_arg0.  */
  convert_code = gimple_assign_rhs_code (arg0_def_stmt);
  new_arg0 = gimple_assign_rhs1 (arg0_def_stmt);
  if (convert_code == VIEW_CONVERT_EXPR)
    {
      new_arg0 = TREE_OPERAND (new_arg0, 0);
      if (!is_gimple_reg_type (TREE_TYPE (new_arg0)))
	return NULL;
    }

  if (TREE_CODE (arg1) == SSA_NAME)
    {
      /* Check if arg1 is an SSA_NAME and the stmt which defines arg1
	 is a conversion.  */
      arg1_def_stmt = SSA_NAME_DEF_STMT (arg1);
      if (!is_gimple_assign (arg1_def_stmt)
	  || gimple_assign_rhs_code (arg1_def_stmt) != convert_code)
	return NULL;

      /* Use the RHS as new_arg1.  */
      new_arg1 = gimple_assign_rhs1 (arg1_def_stmt);
      if (convert_code == VIEW_CONVERT_EXPR)
	new_arg1 = TREE_OPERAND (new_arg1, 0);
    }
  else
    {
      /* If arg1 is an INTEGER_CST, fold it to new type.  */
      if (INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
	  && int_fits_type_p (arg1, TREE_TYPE (new_arg0)))
	{
	  if (gimple_assign_cast_p (arg0_def_stmt))
	    {
	      /* For the INTEGER_CST case, we are just moving the
		 conversion from one place to another, which can often
		 hurt as the conversion moves further away from the
		 statement that computes the value.  So, perform this
		 only if new_arg0 is an operand of COND_STMT, or
		 if arg0_def_stmt is the only non-debug stmt in
		 its basic block, because then it is possible this
		 could enable further optimizations (minmax replacement
		 etc.).  See PR71016.  */
	      if (new_arg0 != gimple_cond_lhs (cond_stmt)
		  && new_arg0 != gimple_cond_rhs (cond_stmt)
		  && gimple_bb (arg0_def_stmt) == e0->src)
		{
		  gsi = gsi_for_stmt (arg0_def_stmt);
		  gsi_prev_nondebug (&gsi);
		  if (!gsi_end_p (gsi))
		    return NULL;
		  gsi = gsi_for_stmt (arg0_def_stmt);
		  gsi_next_nondebug (&gsi);
		  if (!gsi_end_p (gsi))
		    return NULL;
		}
	      new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
	    }
	  else
	    return NULL;
	}
      else
	return NULL;
    }

  /*  If arg0/arg1 have > 1 use, then this transformation actually increases
      the number of expressions evaluated at runtime.  */
  if (!has_single_use (arg0)
      || (arg1_def_stmt && !has_single_use (arg1)))
    return NULL;

  /* If types of new_arg0 and new_arg1 are different bailout.  */
  if (!types_compatible_p (TREE_TYPE (new_arg0), TREE_TYPE (new_arg1)))
    return NULL;

  /* Create a new PHI stmt.  */
  result = PHI_RESULT (phi);
  temp = make_ssa_name (TREE_TYPE (new_arg0), NULL);
  newphi = create_phi_node (temp, gimple_bb (phi));

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, "PHI ");
      print_generic_expr (dump_file, gimple_phi_result (phi));
      fprintf (dump_file,
	       " changed to factor conversion out from COND_EXPR.\n");
      fprintf (dump_file, "New stmt with CAST that defines ");
      print_generic_expr (dump_file, result);
      fprintf (dump_file, ".\n");
    }

  /* Remove the old cast(s) that has single use.  */
  gsi_for_def = gsi_for_stmt (arg0_def_stmt);
  gsi_remove (&gsi_for_def, true);
  release_defs (arg0_def_stmt);

  if (arg1_def_stmt)
    {
      gsi_for_def = gsi_for_stmt (arg1_def_stmt);
      gsi_remove (&gsi_for_def, true);
      release_defs (arg1_def_stmt);
    }

  add_phi_arg (newphi, new_arg0, e0, locus);
  add_phi_arg (newphi, new_arg1, e1, locus);

  /* Create the conversion stmt and insert it.  */
  if (convert_code == VIEW_CONVERT_EXPR)
    {
      temp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), temp);
      new_stmt = gimple_build_assign (result, temp);
    }
  else
    new_stmt = gimple_build_assign (result, convert_code, temp);
  gsi = gsi_after_labels (gimple_bb (phi));
  gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);

  /* Remove the original PHI stmt.  */
  gsi = gsi_for_stmt (phi);
  gsi_remove (&gsi, true);
  return newphi;
}

/* Optimize
   # x_5 in range [cst1, cst2] where cst2 = cst1 + 1
   if (x_5 op cstN) # where op is == or != and N is 1 or 2
     goto bb3;
   else
     goto bb4;
   bb3:
   bb4:
   # r_6 = PHI<cst3(2), cst4(3)> # where cst3 == cst4 + 1 or cst4 == cst3 + 1

   to r_6 = x_5 + (min (cst3, cst4) - cst1) or
   r_6 = (min (cst3, cst4) + cst1) - x_5 depending on op, N and which
   of cst3 and cst4 is smaller.  */

static bool
two_value_replacement (basic_block cond_bb, basic_block middle_bb,
		       edge e1, gphi *phi, tree arg0, tree arg1)
{
  /* Only look for adjacent integer constants.  */
  if (!INTEGRAL_TYPE_P (TREE_TYPE (arg0))
      || !INTEGRAL_TYPE_P (TREE_TYPE (arg1))
      || TREE_CODE (arg0) != INTEGER_CST
      || TREE_CODE (arg1) != INTEGER_CST
      || (tree_int_cst_lt (arg0, arg1)
	  ? wi::to_widest (arg0) + 1 != wi::to_widest (arg1)
	  : wi::to_widest (arg1) + 1 != wi::to_widest (arg1)))
    return false;

  if (!empty_block_p (middle_bb))
    return false;

  gimple *stmt = last_stmt (cond_bb);
  tree lhs = gimple_cond_lhs (stmt);
  tree rhs = gimple_cond_rhs (stmt);

  if (TREE_CODE (lhs) != SSA_NAME
      || !INTEGRAL_TYPE_P (TREE_TYPE (lhs))
      || TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE
      || TREE_CODE (rhs) != INTEGER_CST)
    return false;

  switch (gimple_cond_code (stmt))
    {
    case EQ_EXPR:
    case NE_EXPR:
      break;
    default:
      return false;
    }

  wide_int min, max;
  if (get_range_info (lhs, &min, &max) != VR_RANGE
      || min + 1 != max
      || (wi::to_wide (rhs) != min
	  && wi::to_wide (rhs) != max))
    return false;

  /* We need to know which is the true edge and which is the false
     edge so that we know when to invert the condition below.  */
  edge true_edge, false_edge;
  extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
  if ((gimple_cond_code (stmt) == EQ_EXPR)
      ^ (wi::to_wide (rhs) == max)
      ^ (e1 == false_edge))
    std::swap (arg0, arg1);

  tree type;
  if (TYPE_PRECISION (TREE_TYPE (lhs)) == TYPE_PRECISION (TREE_TYPE (arg0)))
    {
      /* Avoid performing the arithmetics in bool type which has different
	 semantics, otherwise prefer unsigned types from the two with
	 the same precision.  */
      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE
	  || !TYPE_UNSIGNED (TREE_TYPE (arg0)))
	type = TREE_TYPE (lhs);
      else
	type = TREE_TYPE (arg0);
    }
  else if (TYPE_PRECISION (TREE_TYPE (lhs)) > TYPE_PRECISION (TREE_TYPE (arg0)))
    type = TREE_TYPE (lhs);
  else
    type = TREE_TYPE (arg0);

  min = wide_int::from (min, TYPE_PRECISION (type),
			TYPE_SIGN (TREE_TYPE (lhs)));
  wide_int a = wide_int::from (wi::to_wide (arg0), TYPE_PRECISION (type),
			       TYPE_SIGN (TREE_TYPE (arg0)));
  enum tree_code code;
  wi::overflow_type ovf;
  if (tree_int_cst_lt (arg0, arg1))
    {
      code = PLUS_EXPR;
      a -= min;
      if (!TYPE_UNSIGNED (type))
	{
	  /* lhs is known to be in range [min, min+1] and we want to add a
	     to it.  Check if that operation can overflow for those 2 values
	     and if yes, force unsigned type.  */
	  wi::add (min + (wi::neg_p (a) ? 0 : 1), a, SIGNED, &ovf);
	  if (ovf)
	    type = unsigned_type_for (type);
	}
    }
  else
    {
      code = MINUS_EXPR;
      a += min;
      if (!TYPE_UNSIGNED (type))
	{
	  /* lhs is known to be in range [min, min+1] and we want to subtract
	     it from a.  Check if that operation can overflow for those 2
	     values and if yes, force unsigned type.  */
	  wi::sub (a, min + (wi::neg_p (min) ? 0 : 1), SIGNED, &ovf);
	  if (ovf)
	    type = unsigned_type_for (type);
	}
    }

  tree arg = wide_int_to_tree (type, a);
  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
  if (!useless_type_conversion_p (type, TREE_TYPE (lhs)))
    lhs = gimplify_build1 (&gsi, NOP_EXPR, type, lhs);
  tree new_rhs;
  if (code == PLUS_EXPR)
    new_rhs = gimplify_build2 (&gsi, PLUS_EXPR, type, lhs, arg);
  else
    new_rhs = gimplify_build2 (&gsi, MINUS_EXPR, type, arg, lhs);
  if (!useless_type_conversion_p (TREE_TYPE (arg0), type))
    new_rhs = gimplify_build1 (&gsi, NOP_EXPR, TREE_TYPE (arg0), new_rhs);

  replace_phi_edge_with_variable (cond_bb, e1, phi, new_rhs);

  /* Note that we optimized this PHI.  */
  return true;
}

/*  The function conditional_replacement does the main work of doing the
    conditional replacement.  Return true if the replacement is done.
    Otherwise return false.
    BB is the basic block where the replacement is going to be done on.  ARG0
    is argument 0 from PHI.  Likewise for ARG1.  */

static bool
conditional_replacement (basic_block cond_bb, basic_block middle_bb,
			 edge e0, edge e1, gphi *phi,
			 tree arg0, tree arg1)
{
  tree result;
  gimple *stmt;
  gassign *new_stmt;
  tree cond;
  gimple_stmt_iterator gsi;
  edge true_edge, false_edge;
  tree new_var, new_var2;
  bool neg;

  /* FIXME: Gimplification of complex type is too hard for now.  */
  /* We aren't prepared to handle vectors either (and it is a question
     if it would be worthwhile anyway).  */
  if (!(INTEGRAL_TYPE_P (TREE_TYPE (arg0))
	|| POINTER_TYPE_P (TREE_TYPE (arg0)))
      || !(INTEGRAL_TYPE_P (TREE_TYPE (arg1))
	   || POINTER_TYPE_P (TREE_TYPE (arg1))))
    return false;

  /* The PHI arguments have the constants 0 and 1, or 0 and -1, then
     convert it to the conditional.  */
  if ((integer_zerop (arg0) && integer_onep (arg1))
      || (integer_zerop (arg1) && integer_onep (arg0)))
    neg = false;
  else if ((integer_zerop (arg0) && integer_all_onesp (arg1))
	   || (integer_zerop (arg1) && integer_all_onesp (arg0)))
    neg = true;
  else
    return false;

  if (!empty_block_p (middle_bb))
    return false;

  /* At this point we know we have a GIMPLE_COND with two successors.
     One successor is BB, the other successor is an empty block which
     falls through into BB.

     There is a single PHI node at the join point (BB) and its arguments
     are constants (0, 1) or (0, -1).

     So, given the condition COND, and the two PHI arguments, we can
     rewrite this PHI into non-branching code:

       dest = (COND) or dest = COND'

     We use the condition as-is if the argument associated with the
     true edge has the value one or the argument associated with the
     false edge as the value zero.  Note that those conditions are not
     the same since only one of the outgoing edges from the GIMPLE_COND
     will directly reach BB and thus be associated with an argument.  */

  stmt = last_stmt (cond_bb);
  result = PHI_RESULT (phi);

  /* To handle special cases like floating point comparison, it is easier and
     less error-prone to build a tree and gimplify it on the fly though it is
     less efficient.  */
  cond = fold_build2_loc (gimple_location (stmt),
			  gimple_cond_code (stmt), boolean_type_node,
			  gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));

  /* We need to know which is the true edge and which is the false
     edge so that we know when to invert the condition below.  */
  extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
  if ((e0 == true_edge && integer_zerop (arg0))
      || (e0 == false_edge && !integer_zerop (arg0))
      || (e1 == true_edge && integer_zerop (arg1))
      || (e1 == false_edge && !integer_zerop (arg1)))
    cond = fold_build1_loc (gimple_location (stmt),
                            TRUTH_NOT_EXPR, TREE_TYPE (cond), cond);

  if (neg)
    {
      cond = fold_convert_loc (gimple_location (stmt),
                               TREE_TYPE (result), cond);
      cond = fold_build1_loc (gimple_location (stmt),
                              NEGATE_EXPR, TREE_TYPE (cond), cond);
    }

  /* Insert our new statements at the end of conditional block before the
     COND_STMT.  */
  gsi = gsi_for_stmt (stmt);
  new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true,
				      GSI_SAME_STMT);

  if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var)))
    {
      location_t locus_0, locus_1;

      new_var2 = make_ssa_name (TREE_TYPE (result));
      new_stmt = gimple_build_assign (new_var2, CONVERT_EXPR, new_var);
      gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
      new_var = new_var2;

      /* Set the locus to the first argument, unless is doesn't have one.  */
      locus_0 = gimple_phi_arg_location (phi, 0);
      locus_1 = gimple_phi_arg_location (phi, 1);
      if (locus_0 == UNKNOWN_LOCATION)
        locus_0 = locus_1;
      gimple_set_location (new_stmt, locus_0);
    }

  replace_phi_edge_with_variable (cond_bb, e1, phi, new_var);

  /* Note that we optimized this PHI.  */
  return true;
}

/* Update *ARG which is defined in STMT so that it contains the
   computed value if that seems profitable.  Return true if the
   statement is made dead by that rewriting.  */

static bool
jump_function_from_stmt (tree *arg, gimple *stmt)
{
  enum tree_code code = gimple_assign_rhs_code (stmt);
  if (code == ADDR_EXPR)
    {
      /* For arg = &p->i transform it to p, if possible.  */
      tree rhs1 = gimple_assign_rhs1 (stmt);
      poly_int64 offset;
      tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (rhs1, 0),
						&offset);
      if (tem
	  && TREE_CODE (tem) == MEM_REF
	  && known_eq (mem_ref_offset (tem) + offset, 0))
	{
	  *arg = TREE_OPERAND (tem, 0);
	  return true;
	}
    }
  /* TODO: Much like IPA-CP jump-functions we want to handle constant
     additions symbolically here, and we'd need to update the comparison
     code that compares the arg + cst tuples in our caller.  For now the
     code above exactly handles the VEC_BASE pattern from vec.h.  */
  return false;
}

/* RHS is a source argument in a BIT_AND_EXPR which feeds a conditional
   of the form SSA_NAME NE 0.

   If RHS is fed by a simple EQ_EXPR comparison of two values, see if
   the two input values of the EQ_EXPR match arg0 and arg1.

   If so update *code and return TRUE.  Otherwise return FALSE.  */

static bool
rhs_is_fed_for_value_replacement (const_tree arg0, const_tree arg1,
				  enum tree_code *code, const_tree rhs)
{
  /* Obviously if RHS is not an SSA_NAME, we can't look at the defining
     statement.  */
  if (TREE_CODE (rhs) == SSA_NAME)
    {
      gimple *def1 = SSA_NAME_DEF_STMT (rhs);

      /* Verify the defining statement has an EQ_EXPR on the RHS.  */
      if (is_gimple_assign (def1) && gimple_assign_rhs_code (def1) == EQ_EXPR)
	{
	  /* Finally verify the source operands of the EQ_EXPR are equal
	     to arg0 and arg1.  */
	  tree op0 = gimple_assign_rhs1 (def1);
	  tree op1 = gimple_assign_rhs2 (def1);
	  if ((operand_equal_for_phi_arg_p (arg0, op0)
	       && operand_equal_for_phi_arg_p (arg1, op1))
	      || (operand_equal_for_phi_arg_p (arg0, op1)
               && operand_equal_for_phi_arg_p (arg1, op0)))
	    {
	      /* We will perform the optimization.  */
	      *code = gimple_assign_rhs_code (def1);
	      return true;
	    }
	}
    }
  return false;
}

/* Return TRUE if arg0/arg1 are equal to the rhs/lhs or lhs/rhs of COND. 

   Also return TRUE if arg0/arg1 are equal to the source arguments of a
   an EQ comparison feeding a BIT_AND_EXPR which feeds COND. 

   Return FALSE otherwise.  */

static bool
operand_equal_for_value_replacement (const_tree arg0, const_tree arg1,
				     enum tree_code *code, gimple *cond)
{
  gimple *def;
  tree lhs = gimple_cond_lhs (cond);
  tree rhs = gimple_cond_rhs (cond);

  if ((operand_equal_for_phi_arg_p (arg0, lhs)
       && operand_equal_for_phi_arg_p (arg1, rhs))
      || (operand_equal_for_phi_arg_p (arg1, lhs)
	  && operand_equal_for_phi_arg_p (arg0, rhs)))
    return true;

  /* Now handle more complex case where we have an EQ comparison
     which feeds a BIT_AND_EXPR which feeds COND.

     First verify that COND is of the form SSA_NAME NE 0.  */
  if (*code != NE_EXPR || !integer_zerop (rhs)
      || TREE_CODE (lhs) != SSA_NAME)
    return false;

  /* Now ensure that SSA_NAME is set by a BIT_AND_EXPR.  */
  def = SSA_NAME_DEF_STMT (lhs);
  if (!is_gimple_assign (def) || gimple_assign_rhs_code (def) != BIT_AND_EXPR)
    return false;

  /* Now verify arg0/arg1 correspond to the source arguments of an 
     EQ comparison feeding the BIT_AND_EXPR.  */
     
  tree tmp = gimple_assign_rhs1 (def);
  if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp))
    return true;

  tmp = gimple_assign_rhs2 (def);
  if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp))
    return true;

  return false;
}

/* Returns true if ARG is a neutral element for operation CODE
   on the RIGHT side.  */

static bool
neutral_element_p (tree_code code, tree arg, bool right)
{
  switch (code)
    {
    case PLUS_EXPR:
    case BIT_IOR_EXPR:
    case BIT_XOR_EXPR:
      return integer_zerop (arg);

    case LROTATE_EXPR:
    case RROTATE_EXPR:
    case LSHIFT_EXPR:
    case RSHIFT_EXPR:
    case MINUS_EXPR:
    case POINTER_PLUS_EXPR:
      return right && integer_zerop (arg);

    case MULT_EXPR:
      return integer_onep (arg);

    case TRUNC_DIV_EXPR:
    case CEIL_DIV_EXPR:
    case FLOOR_DIV_EXPR:
    case ROUND_DIV_EXPR:
    case EXACT_DIV_EXPR:
      return right && integer_onep (arg);

    case BIT_AND_EXPR:
      return integer_all_onesp (arg);

    default:
      return false;
    }
}

/* Returns true if ARG is an absorbing element for operation CODE.  */

static bool
absorbing_element_p (tree_code code, tree arg, bool right, tree rval)
{
  switch (code)
    {
    case BIT_IOR_EXPR:
      return integer_all_onesp (arg);

    case MULT_EXPR:
    case BIT_AND_EXPR:
      return integer_zerop (arg);

    case LSHIFT_EXPR:
    case RSHIFT_EXPR:
    case LROTATE_EXPR:
    case RROTATE_EXPR:
      return !right && integer_zerop (arg);

    case TRUNC_DIV_EXPR:
    case CEIL_DIV_EXPR:
    case FLOOR_DIV_EXPR:
    case ROUND_DIV_EXPR:
    case EXACT_DIV_EXPR:
    case TRUNC_MOD_EXPR:
    case CEIL_MOD_EXPR:
    case FLOOR_MOD_EXPR:
    case ROUND_MOD_EXPR:
      return (!right
	      && integer_zerop (arg)
	      && tree_single_nonzero_warnv_p (rval, NULL));

    default:
      return false;
    }
}

/*  The function value_replacement does the main work of doing the value
    replacement.  Return non-zero if the replacement is done.  Otherwise return
    0.  If we remove the middle basic block, return 2.
    BB is the basic block where the replacement is going to be done on.  ARG0
    is argument 0 from the PHI.  Likewise for ARG1.  */

static int
value_replacement (basic_block cond_bb, basic_block middle_bb,
		   edge e0, edge e1, gimple *phi,
		   tree arg0, tree arg1)
{
  gimple_stmt_iterator gsi;
  gimple *cond;
  edge true_edge, false_edge;
  enum tree_code code;
  bool emtpy_or_with_defined_p = true;

  /* If the type says honor signed zeros we cannot do this
     optimization.  */
  if (HONOR_SIGNED_ZEROS (arg1))
    return 0;

  /* If there is a statement in MIDDLE_BB that defines one of the PHI
     arguments, then adjust arg0 or arg1.  */
  gsi = gsi_start_nondebug_after_labels_bb (middle_bb);
  while (!gsi_end_p (gsi))
    {
      gimple *stmt = gsi_stmt (gsi);
      tree lhs;
      gsi_next_nondebug (&gsi);
      if (!is_gimple_assign (stmt))
	{
	  if (gimple_code (stmt) != GIMPLE_PREDICT
	      && gimple_code (stmt) != GIMPLE_NOP)
	    emtpy_or_with_defined_p = false;
	  continue;
	}
      /* Now try to adjust arg0 or arg1 according to the computation
	 in the statement.  */
      lhs = gimple_assign_lhs (stmt);
      if (!(lhs == arg0
	     && jump_function_from_stmt (&arg0, stmt))
	    || (lhs == arg1
		&& jump_function_from_stmt (&arg1, stmt)))
	emtpy_or_with_defined_p = false;
    }

  cond = last_stmt (cond_bb);
  code = gimple_cond_code (cond);

  /* This transformation is only valid for equality comparisons.  */
  if (code != NE_EXPR && code != EQ_EXPR)
    return 0;

  /* We need to know which is the true edge and which is the false
      edge so that we know if have abs or negative abs.  */
  extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);

  /* At this point we know we have a COND_EXPR with two successors.
     One successor is BB, the other successor is an empty block which
     falls through into BB.

     The condition for the COND_EXPR is known to be NE_EXPR or EQ_EXPR.

     There is a single PHI node at the join point (BB) with two arguments.

     We now need to verify that the two arguments in the PHI node match
     the two arguments to the equality comparison.  */

  if (operand_equal_for_value_replacement (arg0, arg1, &code, cond))
    {
      edge e;
      tree arg;

      /* For NE_EXPR, we want to build an assignment result = arg where
	 arg is the PHI argument associated with the true edge.  For
	 EQ_EXPR we want the PHI argument associated with the false edge.  */
      e = (code == NE_EXPR ? true_edge : false_edge);

      /* Unfortunately, E may not reach BB (it may instead have gone to
	 OTHER_BLOCK).  If that is the case, then we want the single outgoing
	 edge from OTHER_BLOCK which reaches BB and represents the desired
	 path from COND_BLOCK.  */
      if (e->dest == middle_bb)
	e = single_succ_edge (e->dest);

      /* Now we know the incoming edge to BB that has the argument for the
	 RHS of our new assignment statement.  */
      if (e0 == e)
	arg = arg0;
      else
	arg = arg1;

      /* If the middle basic block was empty or is defining the
	 PHI arguments and this is a single phi where the args are different
	 for the edges e0 and e1 then we can remove the middle basic block. */
      if (emtpy_or_with_defined_p
	  && single_non_singleton_phi_for_edges (phi_nodes (gimple_bb (phi)),
						 e0, e1) == phi)
	{
          replace_phi_edge_with_variable (cond_bb, e1, phi, arg);
	  /* Note that we optimized this PHI.  */
	  return 2;
	}
      else
	{
	  /* Replace the PHI arguments with arg. */
	  SET_PHI_ARG_DEF (phi, e0->dest_idx, arg);
	  SET_PHI_ARG_DEF (phi, e1->dest_idx, arg);
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
	      fprintf (dump_file, "PHI ");
	      print_generic_expr (dump_file, gimple_phi_result (phi));
	      fprintf (dump_file, " reduced for COND_EXPR in block %d to ",
		       cond_bb->index);
	      print_generic_expr (dump_file, arg);
	      fprintf (dump_file, ".\n");
            }
          return 1;
	}

    }

  /* Now optimize (x != 0) ? x + y : y to just x + y.  */
  gsi = gsi_last_nondebug_bb (middle_bb);
  if (gsi_end_p (gsi))
    return 0;

  gimple *assign = gsi_stmt (gsi);
  if (!is_gimple_assign (assign)
      || gimple_assign_rhs_class (assign) != GIMPLE_BINARY_RHS
      || (!INTEGRAL_TYPE_P (TREE_TYPE (arg0))
	  && !POINTER_TYPE_P (TREE_TYPE (arg0))))
    return 0;

  /* Punt if there are (degenerate) PHIs in middle_bb, there should not be.  */
  if (!gimple_seq_empty_p (phi_nodes (middle_bb)))
    return 0;

  /* Allow up to 2 cheap preparation statements that prepare argument
     for assign, e.g.:
      if (y_4 != 0)
	goto <bb 3>;
      else
	goto <bb 4>;
     <bb 3>:
      _1 = (int) y_4;
      iftmp.0_6 = x_5(D) r<< _1;
     <bb 4>:
      # iftmp.0_2 = PHI <iftmp.0_6(3), x_5(D)(2)>
     or:
      if (y_3(D) == 0)
	goto <bb 4>;
      else
	goto <bb 3>;
     <bb 3>:
      y_4 = y_3(D) & 31;
      _1 = (int) y_4;
      _6 = x_5(D) r<< _1;
     <bb 4>:
      # _2 = PHI <x_5(D)(2), _6(3)>  */
  gimple *prep_stmt[2] = { NULL, NULL };
  int prep_cnt;
  for (prep_cnt = 0; ; prep_cnt++)
    {
      gsi_prev_nondebug (&gsi);
      if (gsi_end_p (gsi))
	break;

      gimple *g = gsi_stmt (gsi);
      if (gimple_code (g) == GIMPLE_LABEL)
	break;

      if (prep_cnt == 2 || !is_gimple_assign (g))
	return 0;

      tree lhs = gimple_assign_lhs (g);
      tree rhs1 = gimple_assign_rhs1 (g);
      use_operand_p use_p;
      gimple *use_stmt;
      if (TREE_CODE (lhs) != SSA_NAME
	  || TREE_CODE (rhs1) != SSA_NAME
	  || !INTEGRAL_TYPE_P (TREE_TYPE (lhs))
	  || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
	  || !single_imm_use (lhs, &use_p, &use_stmt)
	  || use_stmt != (prep_cnt ? prep_stmt[prep_cnt - 1] : assign))
	return 0;
      switch (gimple_assign_rhs_code (g))
	{
	CASE_CONVERT:
	  break;
	case PLUS_EXPR:
	case BIT_AND_EXPR:
	case BIT_IOR_EXPR:
	case BIT_XOR_EXPR:
	  if (TREE_CODE (gimple_assign_rhs2 (g)) != INTEGER_CST)
	    return 0;
	  break;
	default:
	  return 0;
	}
      prep_stmt[prep_cnt] = g;
    }

  /* Only transform if it removes the condition.  */
  if (!single_non_singleton_phi_for_edges (phi_nodes (gimple_bb (phi)), e0, e1))
    return 0;

  /* Size-wise, this is always profitable.  */
  if (optimize_bb_for_speed_p (cond_bb)
      /* The special case is useless if it has a low probability.  */
      && profile_status_for_fn (cfun) != PROFILE_ABSENT
      && EDGE_PRED (middle_bb, 0)->probability < profile_probability::even ()
      /* If assign is cheap, there is no point avoiding it.  */
      && estimate_num_insns (bb_seq (middle_bb), &eni_time_weights)
	 >= 3 * estimate_num_insns (cond, &eni_time_weights))
    return 0;

  tree lhs = gimple_assign_lhs (assign);
  tree rhs1 = gimple_assign_rhs1 (assign);
  tree rhs2 = gimple_assign_rhs2 (assign);
  enum tree_code code_def = gimple_assign_rhs_code (assign);
  tree cond_lhs = gimple_cond_lhs (cond);
  tree cond_rhs = gimple_cond_rhs (cond);

  /* Propagate the cond_rhs constant through preparation stmts,
     make sure UB isn't invoked while doing that.  */
  for (int i = prep_cnt - 1; i >= 0; --i)
    {
      gimple *g = prep_stmt[i];
      tree grhs1 = gimple_assign_rhs1 (g);
      if (!operand_equal_for_phi_arg_p (cond_lhs, grhs1))
	return 0;
      cond_lhs = gimple_assign_lhs (g);
      cond_rhs = fold_convert (TREE_TYPE (grhs1), cond_rhs);
      if (TREE_CODE (cond_rhs) != INTEGER_CST
	  || TREE_OVERFLOW (cond_rhs))
	return 0;
      if (gimple_assign_rhs_class (g) == GIMPLE_BINARY_RHS)
	{
	  cond_rhs = int_const_binop (gimple_assign_rhs_code (g), cond_rhs,
				      gimple_assign_rhs2 (g));
	  if (TREE_OVERFLOW (cond_rhs))
	    return 0;
	}
      cond_rhs = fold_convert (TREE_TYPE (cond_lhs), cond_rhs);
      if (TREE_CODE (cond_rhs) != INTEGER_CST
	  || TREE_OVERFLOW (cond_rhs))
	return 0;
    }

  if (((code == NE_EXPR && e1 == false_edge)
	|| (code == EQ_EXPR && e1 == true_edge))
      && arg0 == lhs
      && ((arg1 == rhs1
	   && operand_equal_for_phi_arg_p (rhs2, cond_lhs)
	   && neutral_element_p (code_def, cond_rhs, true))
	  || (arg1 == rhs2
	      && operand_equal_for_phi_arg_p (rhs1, cond_lhs)
	      && neutral_element_p (code_def, cond_rhs, false))
	  || (operand_equal_for_phi_arg_p (arg1, cond_rhs)
	      && ((operand_equal_for_phi_arg_p (rhs2, cond_lhs)
		   && absorbing_element_p (code_def, cond_rhs, true, rhs2))
		  || (operand_equal_for_phi_arg_p (rhs1, cond_lhs)
		      && absorbing_element_p (code_def,
					      cond_rhs, false, rhs2))))))
    {
      gsi = gsi_for_stmt (cond);
      /* Moving ASSIGN might change VR of lhs, e.g. when moving u_6
	 def-stmt in:
	   if (n_5 != 0)
	     goto <bb 3>;
	   else
	     goto <bb 4>;

	   <bb 3>:
	   # RANGE [0, 4294967294]
	   u_6 = n_5 + 4294967295;

	   <bb 4>:
	   # u_3 = PHI <u_6(3), 4294967295(2)>  */
      reset_flow_sensitive_info (lhs);
      if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
	{
	  /* If available, we can use VR of phi result at least.  */
	  tree phires = gimple_phi_result (phi);
	  struct range_info_def *phires_range_info
	    = SSA_NAME_RANGE_INFO (phires);
	  if (phires_range_info)
	    duplicate_ssa_name_range_info (lhs, SSA_NAME_RANGE_TYPE (phires),
					   phires_range_info);
	}
      gimple_stmt_iterator gsi_from;
      for (int i = prep_cnt - 1; i >= 0; --i)
	{
	  tree plhs = gimple_assign_lhs (prep_stmt[i]);
	  reset_flow_sensitive_info (plhs);
	  gsi_from = gsi_for_stmt (prep_stmt[i]);
	  gsi_move_before (&gsi_from, &gsi);
	}
      gsi_from = gsi_for_stmt (assign);
      gsi_move_before (&gsi_from, &gsi);
      replace_phi_edge_with_variable (cond_bb, e1, phi, lhs);
      return 2;
    }

  return 0;
}

/*  The function minmax_replacement does the main work of doing the minmax
    replacement.  Return true if the replacement is done.  Otherwise return
    false.
    BB is the basic block where the replacement is going to be done on.  ARG0
    is argument 0 from the PHI.  Likewise for ARG1.  */

static bool
minmax_replacement (basic_block cond_bb, basic_block middle_bb,
		    edge e0, edge e1, gimple *phi,
		    tree arg0, tree arg1)
{
  tree result, type, rhs;
  gcond *cond;
  gassign *new_stmt;
  edge true_edge, false_edge;
  enum tree_code cmp, minmax, ass_code;
  tree smaller, alt_smaller, larger, alt_larger, arg_true, arg_false;
  gimple_stmt_iterator gsi, gsi_from;

  type = TREE_TYPE (PHI_RESULT (phi));

  /* The optimization may be unsafe due to NaNs.  */
  if (HONOR_NANS (type) || HONOR_SIGNED_ZEROS (type))
    return false;