gcc80: Handle TZ specific "%+" format in strftime.
[dragonfly.git] / contrib / gcc-8.0 / gcc / tree-chkp-opt.c
1 /* Pointer Bounds Checker optimization pass.
2    Copyright (C) 2014-2018 Free Software Foundation, Inc.
3    Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "gimple.h"
29 #include "tree-pass.h"
30 #include "ssa.h"
31 #include "gimple-pretty-print.h"
32 #include "diagnostic.h"
33 #include "fold-const.h"
34 #include "tree-cfg.h"
35 #include "tree-ssa-loop-niter.h"
36 #include "gimple-iterator.h"
37 #include "tree-chkp.h"
38 #include "ipa-chkp.h"
39
40 enum check_type
41 {
42   CHECK_LOWER_BOUND,
43   CHECK_UPPER_BOUND
44 };
45
46 struct pol_item
47 {
48   tree cst;
49   tree var;
50 };
51
52 struct address_t
53 {
54   vec<struct pol_item> pol;
55 };
56
57 /* Structure to hold check informtation.  */
58 struct check_info
59 {
60   /* Type of the check.  */
61   check_type type;
62   /* Address used for the check.  */
63   address_t addr;
64   /* Bounds used for the check.  */
65   tree bounds;
66   /* Check statement.  Can be NULL for removed checks.  */
67   gimple *stmt;
68 };
69
70 /* Structure to hold checks information for BB.  */
71 struct bb_checks
72 {
73   vec<struct check_info, va_heap, vl_ptr> checks;
74 };
75
76 static void chkp_collect_value (tree ssa_name, address_t &res);
77
78 #define chkp_bndmk_fndecl \
79   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
80 #define chkp_intersect_fndecl \
81   (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
82 #define chkp_checkl_fndecl \
83   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
84 #define chkp_checku_fndecl \
85   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
86
87 static vec<struct bb_checks, va_heap, vl_ptr> check_infos;
88
89 /* Comparator for pol_item structures I1 and I2 to be used
90    to find items with equal var.  Also used for polynomial
91    sorting.  */
92 static int
93 chkp_pol_item_compare (const void *i1, const void *i2)
94 {
95   const struct pol_item *p1 = (const struct pol_item *)i1;
96   const struct pol_item *p2 = (const struct pol_item *)i2;
97
98   if (p1->var == p2->var)
99     return 0;
100   else if (p1->var > p2->var)
101     return 1;
102   else
103     return -1;
104 }
105
106 /* Find polynomial item in ADDR with var equal to VAR
107    and return its index.  Return -1 if item was not
108    found.  */
109 static int
110 chkp_pol_find (address_t &addr, tree var)
111 {
112   int left = 0;
113   int right = addr.pol.length () - 1;
114   int n;
115
116   while (right >= left)
117     {
118       n = (left + right) / 2;
119
120       if (addr.pol[n].var == var
121           || (var && addr.pol[n].var
122               && TREE_CODE (var) == ADDR_EXPR
123               && TREE_CODE (addr.pol[n].var) == ADDR_EXPR
124               && TREE_OPERAND (var, 0) == TREE_OPERAND (addr.pol[n].var, 0)))
125         return n;
126       else if (addr.pol[n].var > var)
127         right = n - 1;
128       else
129         left = n + 1;
130     }
131
132   return -1;
133 }
134
135 /* Return constant CST extended to size type.  */
136 static tree
137 chkp_extend_const (tree cst)
138 {
139   if (TYPE_PRECISION (TREE_TYPE (cst)) < TYPE_PRECISION (size_type_node))
140     return build_int_cst_type (size_type_node, tree_to_shwi (cst));
141
142   return cst;
143 }
144
145 /* Add polynomial item CST * VAR to ADDR.  */
146 static void
147 chkp_add_addr_item (address_t &addr, tree cst, tree var)
148 {
149   int n = chkp_pol_find (addr, var);
150
151   cst = chkp_extend_const (cst);
152
153   if (n < 0)
154     {
155       struct pol_item item;
156       item.cst = cst;
157       item.var = var;
158
159       addr.pol.safe_push (item);
160       addr.pol.qsort (&chkp_pol_item_compare);
161     }
162   else
163     {
164       addr.pol[n].cst = fold_build2 (PLUS_EXPR, TREE_TYPE (addr.pol[n].cst),
165                                      addr.pol[n].cst, cst);
166       if (TREE_CODE (addr.pol[n].cst) == INTEGER_CST
167           && integer_zerop (addr.pol[n].cst))
168         addr.pol.ordered_remove (n);
169     }
170 }
171
172 /* Subtract polynomial item CST * VAR from ADDR.  */
173 static void
174 chkp_sub_addr_item (address_t &addr, tree cst, tree var)
175 {
176   int n = chkp_pol_find (addr, var);
177
178   cst = chkp_extend_const (cst);
179
180   if (n < 0)
181     {
182       struct pol_item item;
183       item.cst = fold_build2 (MINUS_EXPR, TREE_TYPE (cst),
184                               integer_zero_node, cst);
185       item.var = var;
186
187       addr.pol.safe_push (item);
188       addr.pol.qsort (&chkp_pol_item_compare);
189     }
190   else
191     {
192       addr.pol[n].cst = fold_build2 (MINUS_EXPR, TREE_TYPE (addr.pol[n].cst),
193                                      addr.pol[n].cst, cst);
194       if (TREE_CODE (addr.pol[n].cst) == INTEGER_CST
195           && integer_zerop (addr.pol[n].cst))
196         addr.pol.ordered_remove (n);
197     }
198 }
199
200 /* Add address DELTA to ADDR.  */
201 static void
202 chkp_add_addr_addr (address_t &addr, address_t &delta)
203 {
204   unsigned int i;
205   for (i = 0; i < delta.pol.length (); i++)
206     chkp_add_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
207 }
208
209 /* Subtract address DELTA from ADDR.  */
210 static void
211 chkp_sub_addr_addr (address_t &addr, address_t &delta)
212 {
213   unsigned int i;
214   for (i = 0; i < delta.pol.length (); i++)
215     chkp_sub_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
216 }
217
218 /* Mutiply address ADDR by integer constant MULT.  */
219 static void
220 chkp_mult_addr (address_t &addr, tree mult)
221 {
222   unsigned int i;
223   for (i = 0; i < addr.pol.length (); i++)
224     addr.pol[i].cst = fold_build2 (MULT_EXPR, TREE_TYPE (addr.pol[i].cst),
225                                    addr.pol[i].cst, mult);
226 }
227
228 /* Return 1 if we may prove ADDR has a constant value with
229    determined sign, which is put into *SIGN.  Otherwise
230    return 0.  */
231 static bool
232 chkp_is_constant_addr (const address_t &addr, int *sign)
233 {
234   *sign = 0;
235
236   if (addr.pol.length () == 0)
237     return true;
238   else if (addr.pol.length () > 1)
239     return false;
240   else if (addr.pol[0].var)
241     return false;
242   else if (TREE_CODE (addr.pol[0].cst) != INTEGER_CST)
243     return false;
244   else if (integer_zerop (addr.pol[0].cst))
245     *sign = 0;
246   else if (tree_int_cst_sign_bit (addr.pol[0].cst))
247     *sign = -1;
248   else
249     *sign = 1;
250
251   return true;
252 }
253
254 /* Dump ADDR into dump_file.  */
255 static void
256 chkp_print_addr (const address_t &addr)
257 {
258   unsigned int n = 0;
259   for (n = 0; n < addr.pol.length (); n++)
260     {
261       if (n > 0)
262         fprintf (dump_file, " + ");
263
264       if (addr.pol[n].var == NULL_TREE)
265         print_generic_expr (dump_file, addr.pol[n].cst);
266       else
267         {
268           if (TREE_CODE (addr.pol[n].cst) != INTEGER_CST
269               || !integer_onep (addr.pol[n].cst))
270             {
271               print_generic_expr (dump_file, addr.pol[n].cst);
272               fprintf (dump_file, " * ");
273             }
274           print_generic_expr (dump_file, addr.pol[n].var);
275         }
276     }
277 }
278
279 /* Compute value of PTR and put it into address RES.
280    PTR has to be ADDR_EXPR.  */
281 static void
282 chkp_collect_addr_value (tree ptr, address_t &res)
283 {
284   tree obj = TREE_OPERAND (ptr, 0);
285   address_t addr;
286
287   switch (TREE_CODE (obj))
288     {
289     case INDIRECT_REF:
290       chkp_collect_value (TREE_OPERAND (obj, 0), res);
291       break;
292
293     case MEM_REF:
294       chkp_collect_value (TREE_OPERAND (obj, 0), res);
295       addr.pol.create (0);
296       chkp_collect_value (TREE_OPERAND (obj, 1), addr);
297       chkp_add_addr_addr (res, addr);
298       addr.pol.release ();
299       break;
300
301     case ARRAY_REF:
302       chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj, 0)), res);
303       addr.pol.create (0);
304       chkp_collect_value (TREE_OPERAND (obj, 1), addr);
305       chkp_mult_addr (addr, array_ref_element_size (obj));
306       chkp_add_addr_addr (res, addr);
307       addr.pol.release ();
308       break;
309
310     case COMPONENT_REF:
311       {
312         tree str = TREE_OPERAND (obj, 0);
313         tree field = TREE_OPERAND (obj, 1);
314         chkp_collect_value (build_fold_addr_expr (str), res);
315         addr.pol.create (0);
316         chkp_collect_value (component_ref_field_offset (obj), addr);
317         chkp_add_addr_addr (res, addr);
318         addr.pol.release ();
319         if (DECL_FIELD_BIT_OFFSET (field))
320           {
321             addr.pol.create (0);
322             chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR, size_type_node,
323                                              DECL_FIELD_BIT_OFFSET (field),
324                                              size_int (BITS_PER_UNIT)),
325                            addr);
326             chkp_add_addr_addr (res, addr);
327             addr.pol.release ();
328           }
329       }
330       break;
331
332     default:
333       chkp_add_addr_item (res, integer_one_node, ptr);
334       break;
335     }
336 }
337
338 /* Compute value of PTR and put it into address RES.  */
339 static void
340 chkp_collect_value (tree ptr, address_t &res)
341 {
342   gimple *def_stmt;
343   enum gimple_code code;
344   enum tree_code rhs_code;
345   address_t addr;
346   tree rhs1;
347
348   if (TREE_CODE (ptr) == INTEGER_CST)
349     {
350       chkp_add_addr_item (res, ptr, NULL);
351       return;
352     }
353   else if (TREE_CODE (ptr) == ADDR_EXPR)
354     {
355       chkp_collect_addr_value (ptr, res);
356       return;
357     }
358   else if (TREE_CODE (ptr) != SSA_NAME)
359     {
360       chkp_add_addr_item (res, integer_one_node, ptr);
361       return;
362     }
363
364   /* Now we handle the case when polynomial is computed
365      for SSA NAME.  */
366   def_stmt = SSA_NAME_DEF_STMT (ptr);
367   code = gimple_code (def_stmt);
368
369   /* Currently we do not walk through statements other
370      than assignment.  */
371   if (code != GIMPLE_ASSIGN)
372     {
373       chkp_add_addr_item (res, integer_one_node, ptr);
374       return;
375     }
376
377   rhs_code = gimple_assign_rhs_code (def_stmt);
378   rhs1 = gimple_assign_rhs1 (def_stmt);
379
380   switch (rhs_code)
381     {
382     case SSA_NAME:
383     case INTEGER_CST:
384     case ADDR_EXPR:
385       chkp_collect_value (rhs1, res);
386       break;
387
388     case PLUS_EXPR:
389     case POINTER_PLUS_EXPR:
390       chkp_collect_value (rhs1, res);
391       addr.pol.create (0);
392       chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
393       chkp_add_addr_addr (res, addr);
394       addr.pol.release ();
395       break;
396
397     case MINUS_EXPR:
398       chkp_collect_value (rhs1, res);
399       addr.pol.create (0);
400       chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
401       chkp_sub_addr_addr (res, addr);
402       addr.pol.release ();
403       break;
404
405     case MULT_EXPR:
406       if (TREE_CODE (rhs1) == SSA_NAME
407           && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == INTEGER_CST)
408         {
409           chkp_collect_value (rhs1, res);
410           chkp_mult_addr (res, gimple_assign_rhs2 (def_stmt));
411         }
412       else if (TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME
413                && TREE_CODE (rhs1) == INTEGER_CST)
414         {
415           chkp_collect_value (gimple_assign_rhs2 (def_stmt), res);
416           chkp_mult_addr (res, rhs1);
417         }
418       else
419         chkp_add_addr_item (res, integer_one_node, ptr);
420       break;
421
422     default:
423       chkp_add_addr_item (res, integer_one_node, ptr);
424       break;
425     }
426 }
427
428 /* Fill check_info structure *CI with information about
429    check STMT.  */
430 static void
431 chkp_fill_check_info (gimple *stmt, struct check_info *ci)
432 {
433   ci->addr.pol.create (0);
434   ci->bounds = gimple_call_arg (stmt, 1);
435   chkp_collect_value (gimple_call_arg (stmt, 0), ci->addr);
436   ci->type = (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
437              ? CHECK_LOWER_BOUND
438              : CHECK_UPPER_BOUND);
439   ci->stmt = stmt;
440 }
441
442 /* Release structures holding check information
443    for current function.  */
444 static void
445 chkp_release_check_info (void)
446 {
447   unsigned int n, m;
448
449   if (check_infos.exists ())
450     {
451       for (n = 0; n < check_infos.length (); n++)
452         {
453           for (m = 0; m < check_infos[n].checks.length (); m++)
454             if (check_infos[n].checks[m].addr.pol.exists ())
455               check_infos[n].checks[m].addr.pol.release ();
456           check_infos[n].checks.release ();
457         }
458       check_infos.release ();
459     }
460 }
461
462 /* Create structures to hold check information
463    for current function.  */
464 static void
465 chkp_init_check_info (void)
466 {
467   struct bb_checks empty_bbc;
468   int n;
469
470   empty_bbc.checks = vNULL;
471
472   chkp_release_check_info ();
473
474   check_infos.create (last_basic_block_for_fn (cfun));
475   for (n = 0; n < last_basic_block_for_fn (cfun); n++)
476     {
477       check_infos.safe_push (empty_bbc);
478       check_infos.last ().checks.create (0);
479     }
480 }
481
482 /* Find all checks in current function and store info about them
483    in check_infos.  */
484 static void
485 chkp_gather_checks_info (void)
486 {
487   basic_block bb;
488   gimple_stmt_iterator i;
489
490   if (dump_file && (dump_flags & TDF_DETAILS))
491     fprintf (dump_file, "Gathering information about checks...\n");
492
493   chkp_init_check_info ();
494
495   FOR_EACH_BB_FN (bb, cfun)
496     {
497       struct bb_checks *bbc = &check_infos[bb->index];
498
499       if (dump_file && (dump_flags & TDF_DETAILS))
500         fprintf (dump_file, "Searching checks in BB%d...\n", bb->index);
501
502       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
503         {
504           gimple *stmt = gsi_stmt (i);
505
506           if (gimple_code (stmt) != GIMPLE_CALL)
507             continue;
508
509           if (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
510               || gimple_call_fndecl (stmt) == chkp_checku_fndecl)
511             {
512               struct check_info ci;
513
514               chkp_fill_check_info (stmt, &ci);
515               bbc->checks.safe_push (ci);
516
517               if (dump_file && (dump_flags & TDF_DETAILS))
518                 {
519                   fprintf (dump_file, "Adding check information:\n");
520                   fprintf (dump_file, "  bounds: ");
521                   print_generic_expr (dump_file, ci.bounds);
522                   fprintf (dump_file, "\n  address: ");
523                   chkp_print_addr (ci.addr);
524                   fprintf (dump_file, "\n  check: ");
525                   print_gimple_stmt (dump_file, stmt, 0);
526                 }
527             }
528         }
529     }
530 }
531
532 /* Return 1 if check CI against BOUNDS always pass,
533    -1 if check CI against BOUNDS always fails and
534    0 if we cannot compute check result.  */
535 static int
536 chkp_get_check_result (struct check_info *ci, tree bounds)
537 {
538   gimple *bnd_def;
539   address_t bound_val;
540   int sign, res = 0;
541
542   if (dump_file && (dump_flags & TDF_DETAILS))
543     {
544       fprintf (dump_file, "Trying to compute result of the check\n");
545       fprintf (dump_file, "  check: ");
546       print_gimple_stmt (dump_file, ci->stmt, 0);
547       fprintf (dump_file, "  address: ");
548       chkp_print_addr (ci->addr);
549       fprintf (dump_file, "\n  bounds: ");
550       print_generic_expr (dump_file, bounds);
551       fprintf (dump_file, "\n");
552     }
553
554   if (TREE_CODE (bounds) != SSA_NAME)
555     {
556       if (dump_file && (dump_flags & TDF_DETAILS))
557         fprintf (dump_file, "  result: bounds tree code is not ssa_name\n");
558       return 0;
559     }
560
561   bnd_def = SSA_NAME_DEF_STMT (bounds);
562   /* Currently we handle cases when bounds are result of bndmk
563      or loaded static bounds var.  */
564   if (gimple_code (bnd_def) == GIMPLE_CALL
565       && gimple_call_fndecl (bnd_def) == chkp_bndmk_fndecl)
566     {
567       bound_val.pol.create (0);
568       chkp_collect_value (gimple_call_arg (bnd_def, 0), bound_val);
569       if (ci->type == CHECK_UPPER_BOUND)
570         {
571           address_t size_val;
572           size_val.pol.create (0);
573           chkp_collect_value (gimple_call_arg (bnd_def, 1), size_val);
574           chkp_add_addr_addr (bound_val, size_val);
575           size_val.pol.release ();
576           chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
577         }
578     }
579   else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
580            && gimple_assign_rhs1 (bnd_def) == chkp_get_zero_bounds_var ())
581     {
582       if (dump_file && (dump_flags & TDF_DETAILS))
583         fprintf (dump_file, "  result: always pass with zero bounds\n");
584       return 1;
585     }
586   else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
587            && gimple_assign_rhs1 (bnd_def) == chkp_get_none_bounds_var ())
588     {
589       if (dump_file && (dump_flags & TDF_DETAILS))
590         fprintf (dump_file, "  result: always fails with none bounds\n");
591       return -1;
592     }
593   else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
594            && TREE_CODE (gimple_assign_rhs1 (bnd_def)) == VAR_DECL)
595     {
596       tree bnd_var = gimple_assign_rhs1 (bnd_def);
597       tree var;
598       tree size;
599
600       if (!DECL_INITIAL (bnd_var)
601           || DECL_INITIAL (bnd_var) == error_mark_node)
602         {
603           if (dump_file && (dump_flags & TDF_DETAILS))
604             fprintf (dump_file, "  result: cannot compute bounds\n");
605           return 0;
606         }
607
608       gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var)) == ADDR_EXPR);
609       var = TREE_OPERAND (DECL_INITIAL (bnd_var), 0);
610
611       bound_val.pol.create (0);
612       chkp_collect_value (DECL_INITIAL (bnd_var), bound_val);
613       if (ci->type == CHECK_UPPER_BOUND)
614         {
615           if (VAR_P (var))
616             {
617               if (DECL_SIZE (var)
618                   && !chkp_variable_size_type (TREE_TYPE (var)))
619                 size = DECL_SIZE_UNIT (var);
620               else
621                 {
622                   if (dump_file && (dump_flags & TDF_DETAILS))
623                     fprintf (dump_file, "  result: cannot compute bounds\n");
624                   return 0;
625                 }
626             }
627           else
628             {
629               gcc_assert (TREE_CODE (var) == STRING_CST);
630               size = build_int_cst (size_type_node,
631                                     TREE_STRING_LENGTH (var));
632             }
633
634           address_t size_val;
635           size_val.pol.create (0);
636           chkp_collect_value (size, size_val);
637           chkp_add_addr_addr (bound_val, size_val);
638           size_val.pol.release ();
639           chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
640         }
641     }
642   else
643     {
644       if (dump_file && (dump_flags & TDF_DETAILS))
645         fprintf (dump_file, "  result: cannot compute bounds\n");
646       return 0;
647     }
648
649   if (dump_file && (dump_flags & TDF_DETAILS))
650     {
651       fprintf (dump_file, "  bound value: ");
652       chkp_print_addr (bound_val);
653       fprintf (dump_file, "\n");
654     }
655
656   chkp_sub_addr_addr (bound_val, ci->addr);
657
658   if (!chkp_is_constant_addr (bound_val, &sign))
659     {
660       if (dump_file && (dump_flags & TDF_DETAILS))
661         fprintf (dump_file, "  result: cannot compute result\n");
662
663       res = 0;
664     }
665   else if (sign == 0
666            || (ci->type == CHECK_UPPER_BOUND && sign > 0)
667            || (ci->type == CHECK_LOWER_BOUND && sign < 0))
668     {
669       if (dump_file && (dump_flags & TDF_DETAILS))
670         fprintf (dump_file, "  result: always pass\n");
671
672       res = 1;
673     }
674   else
675     {
676       if (dump_file && (dump_flags & TDF_DETAILS))
677         fprintf (dump_file, "  result: always fail\n");
678
679       res = -1;
680     }
681
682   bound_val.pol.release ();
683
684   return res;
685 }
686
687 /* Try to compare bounds value and address value
688    used in the check CI.  If we can prove that check
689    always pass then remove it.  */
690 static void
691 chkp_remove_check_if_pass (struct check_info *ci)
692 {
693   int result = 0;
694
695   if (dump_file && (dump_flags & TDF_DETAILS))
696     {
697       fprintf (dump_file, "Trying to remove check: ");
698       print_gimple_stmt (dump_file, ci->stmt, 0);
699     }
700
701   result = chkp_get_check_result (ci, ci->bounds);
702
703   if (result == 1)
704     {
705       gimple_stmt_iterator i = gsi_for_stmt (ci->stmt);
706
707       if (dump_file && (dump_flags & TDF_DETAILS))
708         fprintf (dump_file, "  action: delete check (always pass)\n");
709
710       gsi_remove (&i, true);
711       unlink_stmt_vdef (ci->stmt);
712       release_defs (ci->stmt);
713       ci->stmt = NULL;
714     }
715   else if (result == -1)
716     {
717       if (dump_file && (dump_flags & TDF_DETAILS))
718         fprintf (dump_file, "  action: keep check (always fail)\n");
719       warning_at (gimple_location (ci->stmt), OPT_Wchkp,
720                   "memory access check always fail");
721     }
722   else if (result == 0)
723     {
724       if (dump_file && (dump_flags & TDF_DETAILS))
725         fprintf (dump_file, "  action: keep check (cannot compute result)\n");
726     }
727 }
728
729 /* For bounds used in CI check if bounds are produced by
730    intersection and we may use outer bounds instead.  If
731    transformation is possible then fix check statement and
732    recompute its info.  */
733 static void
734 chkp_use_outer_bounds_if_possible (struct check_info *ci)
735 {
736   gimple *bnd_def;
737   tree bnd1, bnd2, bnd_res = NULL;
738   int check_res1, check_res2;
739
740   if (TREE_CODE (ci->bounds) != SSA_NAME)
741     return;
742
743   bnd_def = SSA_NAME_DEF_STMT (ci->bounds);
744   if (gimple_code (bnd_def) != GIMPLE_CALL
745       || gimple_call_fndecl (bnd_def) != chkp_intersect_fndecl)
746     return;
747
748   if (dump_file && (dump_flags & TDF_DETAILS))
749     {
750       fprintf (dump_file, "Check if bounds intersection is redundant: \n");
751       fprintf (dump_file, "  check: ");
752       print_gimple_stmt (dump_file, ci->stmt, 0);
753       fprintf (dump_file, "  intersection: ");
754       print_gimple_stmt (dump_file, bnd_def, 0);
755       fprintf (dump_file, "\n");
756     }
757
758   bnd1 = gimple_call_arg (bnd_def, 0);
759   bnd2 = gimple_call_arg (bnd_def, 1);
760
761   check_res1 = chkp_get_check_result (ci, bnd1);
762   check_res2 = chkp_get_check_result (ci, bnd2);
763   if (check_res1 == 1)
764     bnd_res = bnd2;
765   else if (check_res1 == -1)
766     bnd_res = bnd1;
767   else if (check_res2 == 1)
768     bnd_res = bnd1;
769   else if (check_res2 == -1)
770     bnd_res = bnd2;
771
772   if (bnd_res)
773     {
774       if (dump_file && (dump_flags & TDF_DETAILS))
775         {
776           fprintf (dump_file, "  action: use ");
777           print_generic_expr (dump_file, bnd2);
778           fprintf (dump_file, " instead of ");
779           print_generic_expr (dump_file, ci->bounds);
780           fprintf (dump_file, "\n");
781         }
782
783       ci->bounds = bnd_res;
784       gimple_call_set_arg (ci->stmt, 1, bnd_res);
785       update_stmt (ci->stmt);
786       chkp_fill_check_info (ci->stmt, ci);
787     }
788 }
789
790 /*  Try to find checks whose bounds were produced by intersection
791     which does not affect check result.  In such check outer bounds
792     are used instead.  It allows to remove excess intersections
793     and helps to compare checks.  */
794 static void
795 chkp_remove_excess_intersections (void)
796 {
797   basic_block bb;
798
799   if (dump_file && (dump_flags & TDF_DETAILS))
800     fprintf (dump_file, "Searching for redundant bounds intersections...\n");
801
802   FOR_EACH_BB_FN (bb, cfun)
803     {
804       struct bb_checks *bbc = &check_infos[bb->index];
805       unsigned int no;
806
807       /* Iterate through all found checks in BB.  */
808       for (no = 0; no < bbc->checks.length (); no++)
809         if (bbc->checks[no].stmt)
810           chkp_use_outer_bounds_if_possible (&bbc->checks[no]);
811     }
812 }
813
814 /*  Try to remove all checks which are known to alwyas pass.  */
815 static void
816 chkp_remove_constant_checks (void)
817 {
818   basic_block bb;
819
820   if (dump_file && (dump_flags & TDF_DETAILS))
821     fprintf (dump_file, "Searching for redundant checks...\n");
822
823   FOR_EACH_BB_FN (bb, cfun)
824     {
825       struct bb_checks *bbc = &check_infos[bb->index];
826       unsigned int no;
827
828       /* Iterate through all found checks in BB.  */
829       for (no = 0; no < bbc->checks.length (); no++)
830         if (bbc->checks[no].stmt)
831           chkp_remove_check_if_pass (&bbc->checks[no]);
832     }
833 }
834
835 /* Return fast version of string function FNCODE.  */
836 static tree
837 chkp_get_nobnd_fndecl (enum built_in_function fncode)
838 {
839   /* Check if we are allowed to use fast string functions.  */
840   if (!flag_chkp_use_fast_string_functions)
841     return NULL_TREE;
842
843   tree fndecl = NULL_TREE;
844
845   switch (fncode)
846     {
847     case BUILT_IN_MEMCPY_CHKP:
848       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND);
849       break;
850
851     case BUILT_IN_MEMPCPY_CHKP:
852       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND);
853       break;
854
855     case BUILT_IN_MEMMOVE_CHKP:
856       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND);
857       break;
858
859     case BUILT_IN_MEMSET_CHKP:
860       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND);
861       break;
862
863     case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP:
864       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
865       break;
866
867     case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP:
868       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
869       break;
870
871     case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP:
872       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
873       break;
874
875     case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP:
876       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
877       break;
878
879     default:
880       break;
881     }
882
883   if (fndecl)
884     fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
885
886   return fndecl;
887 }
888
889
890 /* Return no-check version of string function FNCODE.  */
891 static tree
892 chkp_get_nochk_fndecl (enum built_in_function fncode)
893 {
894   /* Check if we are allowed to use fast string functions.  */
895   if (!flag_chkp_use_nochk_string_functions)
896     return NULL_TREE;
897
898   tree fndecl = NULL_TREE;
899
900   switch (fncode)
901     {
902     case BUILT_IN_MEMCPY_CHKP:
903       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK);
904       break;
905
906     case BUILT_IN_MEMPCPY_CHKP:
907       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK);
908       break;
909
910     case BUILT_IN_MEMMOVE_CHKP:
911       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK);
912       break;
913
914     case BUILT_IN_MEMSET_CHKP:
915       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK);
916       break;
917
918     case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP:
919       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
920       break;
921
922     case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP:
923       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
924       break;
925
926     case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP:
927       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
928       break;
929
930     case BUILT_IN_CHKP_MEMSET_NOBND_CHKP:
931       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
932       break;
933
934     default:
935       break;
936     }
937
938   if (fndecl)
939     fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
940
941   return fndecl;
942 }
943
944 /* Find memcpy, mempcpy, memmove and memset calls, perform
945    checks before call and then call no_chk version of
946    functions.  We do it on O2 to enable inlining of these
947    functions during expand.
948
949    Also try to find memcpy, mempcpy, memmove and memset calls
950    which are known to not write pointers to memory and use
951    faster function versions for them.  */
952 static void
953 chkp_optimize_string_function_calls (void)
954 {
955   basic_block bb;
956
957   if (dump_file && (dump_flags & TDF_DETAILS))
958     fprintf (dump_file, "Searching for replaceable string function calls...\n");
959
960   FOR_EACH_BB_FN (bb, cfun)
961     {
962       gimple_stmt_iterator i;
963
964       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
965         {
966           gimple *stmt = gsi_stmt (i);
967           tree fndecl;
968
969           if (!is_gimple_call (stmt)
970               || !gimple_call_with_bounds_p (stmt)
971               || !gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
972             continue;
973
974           fndecl = gimple_call_fndecl (stmt);
975           if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMCPY_CHKP
976               || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHKP
977               || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMMOVE_CHKP
978               || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP)
979             {
980               tree dst = gimple_call_arg (stmt, 0);
981               tree dst_bnd = gimple_call_arg (stmt, 1);
982               bool is_memset = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP;
983               tree size = gimple_call_arg (stmt, is_memset ? 3 : 4);
984               tree fndecl_nochk;
985               gimple_stmt_iterator j;
986               basic_block check_bb;
987               address_t size_val;
988               int sign;
989               bool known;
990
991               /* We may replace call with corresponding __chkp_*_nobnd
992                  call in case destination pointer base type is not
993                  void or pointer.  */
994               if (POINTER_TYPE_P (TREE_TYPE (dst))
995                   && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst)))
996                   && !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst))))
997                 {
998                   tree fndecl_nobnd
999                     = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl));
1000
1001                   if (fndecl_nobnd)
1002                     fndecl = fndecl_nobnd;
1003                 }
1004
1005               fndecl_nochk = chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl));
1006
1007               if (fndecl_nochk)
1008                 fndecl = fndecl_nochk;
1009
1010               if (fndecl != gimple_call_fndecl (stmt))
1011                 {
1012                   if (dump_file && (dump_flags & TDF_DETAILS))
1013                     {
1014                       fprintf (dump_file, "Replacing call: ");
1015                       print_gimple_stmt (dump_file, stmt, 0,
1016                                          TDF_VOPS|TDF_MEMSYMS);
1017                     }
1018
1019                   gimple_call_set_fndecl (stmt, fndecl);
1020
1021                   if (dump_file && (dump_flags & TDF_DETAILS))
1022                     {
1023                       fprintf (dump_file, "With a new call: ");
1024                       print_gimple_stmt (dump_file, stmt, 0,
1025                                          TDF_VOPS|TDF_MEMSYMS);
1026                     }
1027                 }
1028
1029               /* If there is no nochk version of function then
1030                  do nothing.  Otherwise insert checks before
1031                  the call.  */
1032               if (!fndecl_nochk)
1033                 continue;
1034
1035               /* If size passed to call is known and > 0
1036                  then we may insert checks unconditionally.  */
1037               size_val.pol.create (0);
1038               chkp_collect_value (size, size_val);
1039               known = chkp_is_constant_addr (size_val, &sign);
1040               size_val.pol.release ();
1041
1042               /* If we are not sure size is not zero then we have
1043                  to perform runtime check for size and perform
1044                  checks only when size is not zero.  */
1045               if (!known)
1046                 {
1047                   gimple *check = gimple_build_cond (NE_EXPR,
1048                                                      size,
1049                                                      size_zero_node,
1050                                                      NULL_TREE,
1051                                                      NULL_TREE);
1052
1053                   /* Split block before string function call.  */
1054                   gsi_prev (&i);
1055                   check_bb = insert_cond_bb (bb, gsi_stmt (i), check,
1056                                              profile_probability::likely ());
1057
1058                   /* Set position for checks.  */
1059                   j = gsi_last_bb (check_bb);
1060
1061                   /* The block was splitted and therefore we
1062                      need to set iterator to its end.  */
1063                   i = gsi_last_bb (bb);
1064                 }
1065               /* If size is known to be zero then no checks
1066                  should be performed.  */
1067               else if (!sign)
1068                 continue;
1069               else
1070                 j = i;
1071
1072               size = size_binop (MINUS_EXPR, size, size_one_node);
1073               if (!is_memset)
1074                 {
1075                   tree src = gimple_call_arg (stmt, 2);
1076                   tree src_bnd = gimple_call_arg (stmt, 3);
1077
1078                   chkp_check_mem_access (src, fold_build_pointer_plus (src, size),
1079                                          src_bnd, j, gimple_location (stmt),
1080                                          integer_zero_node);
1081                 }
1082
1083               chkp_check_mem_access (dst, fold_build_pointer_plus (dst, size),
1084                                      dst_bnd, j, gimple_location (stmt),
1085                                      integer_one_node);
1086
1087             }
1088         }
1089     }
1090 }
1091
1092 /* Intrumentation pass inserts most of bounds creation code
1093    in the header of the function.  We want to move bounds
1094    creation closer to bounds usage to reduce bounds lifetime.
1095    We also try to avoid bounds creation code on paths where
1096    bounds are not used.  */
1097 static void
1098 chkp_reduce_bounds_lifetime (void)
1099 {
1100   basic_block bb = FALLTHRU_EDGE (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest;
1101   gimple_stmt_iterator i;
1102
1103   for (i = gsi_start_bb (bb); !gsi_end_p (i); )
1104     {
1105       gimple *dom_use, *use_stmt, *stmt = gsi_stmt (i);
1106       basic_block dom_bb;
1107       ssa_op_iter iter;
1108       imm_use_iterator use_iter;
1109       use_operand_p use_p;
1110       tree op;
1111       bool want_move = false;
1112       bool deps = false;
1113
1114       if (gimple_code (stmt) == GIMPLE_CALL
1115           && gimple_call_fndecl (stmt) == chkp_bndmk_fndecl)
1116         want_move = true;
1117
1118       if (gimple_code (stmt) == GIMPLE_ASSIGN
1119           && POINTER_BOUNDS_P (gimple_assign_lhs (stmt))
1120           && gimple_assign_rhs_code (stmt) == VAR_DECL)
1121         want_move = true;
1122
1123       if (!want_move)
1124         {
1125           gsi_next (&i);
1126           continue;
1127         }
1128
1129       /* Check we do not increase other values lifetime.  */
1130       FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
1131         {
1132           op = USE_FROM_PTR (use_p);
1133
1134           if (TREE_CODE (op) == SSA_NAME
1135               && gimple_code (SSA_NAME_DEF_STMT (op)) != GIMPLE_NOP)
1136             {
1137               deps = true;
1138               break;
1139             }
1140         }
1141
1142       if (deps)
1143         {
1144           gsi_next (&i);
1145           continue;
1146         }
1147
1148       /* Check all usages of bounds.  */
1149       if (gimple_code (stmt) == GIMPLE_CALL)
1150         op = gimple_call_lhs (stmt);
1151       else
1152         {
1153           gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
1154           op = gimple_assign_lhs (stmt);
1155         }
1156
1157       dom_use = NULL;
1158       dom_bb = NULL;
1159
1160       FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, op)
1161         {
1162           if (is_gimple_debug (use_stmt))
1163             continue;
1164
1165           if (dom_bb &&
1166               dominated_by_p (CDI_DOMINATORS,
1167                               dom_bb, gimple_bb (use_stmt)))
1168             {
1169               dom_use = use_stmt;
1170               dom_bb = NULL;
1171             }
1172           else if (dom_bb)
1173             dom_bb = nearest_common_dominator (CDI_DOMINATORS, dom_bb,
1174                                                gimple_bb (use_stmt));
1175           else if (!dom_use)
1176             dom_use = use_stmt;
1177           else if (stmt_dominates_stmt_p (use_stmt, dom_use))
1178             dom_use = use_stmt;
1179           else if (!stmt_dominates_stmt_p (dom_use, use_stmt)
1180                    /* If dom_use and use_stmt are PHI nodes in one BB
1181                       then it is OK to keep any of them as dom_use.
1182                       stmt_dominates_stmt_p returns 0 for such
1183                       combination, so check it here manually.  */
1184                    && (gimple_code (dom_use) != GIMPLE_PHI
1185                        || gimple_code (use_stmt) != GIMPLE_PHI
1186                        || gimple_bb (use_stmt) != gimple_bb (dom_use))
1187                    )
1188             {
1189               dom_bb = nearest_common_dominator (CDI_DOMINATORS,
1190                                                  gimple_bb (use_stmt),
1191                                                  gimple_bb (dom_use));
1192               dom_use = NULL;
1193             }
1194         }
1195
1196       /* In case there is a single use, just move bounds
1197          creation to the use.  */
1198       if (dom_use || dom_bb)
1199         {
1200           if (dump_file && (dump_flags & TDF_DETAILS))
1201             {
1202               fprintf (dump_file, "Moving creation of ");
1203               print_generic_expr (dump_file, op);
1204               fprintf (dump_file, " down to its use.\n");
1205             }
1206
1207           if (dom_use && gimple_code (dom_use) == GIMPLE_PHI)
1208             {
1209               dom_bb = get_immediate_dominator (CDI_DOMINATORS,
1210                                                 gimple_bb (dom_use));
1211               dom_use = NULL;
1212             }
1213
1214           if (dom_bb == bb
1215               || (dom_use && gimple_bb (dom_use) == bb))
1216             {
1217                   if (dump_file && (dump_flags & TDF_DETAILS))
1218                     fprintf (dump_file, "Cannot move statement bacause there is no "
1219                              "suitable dominator block other than entry block.\n");
1220
1221                   gsi_next (&i);
1222             }
1223           else
1224             {
1225               if (dom_bb)
1226                 {
1227                   gimple_stmt_iterator last = gsi_last_bb (dom_bb);
1228                   if (!gsi_end_p (last) && stmt_ends_bb_p (gsi_stmt (last)))
1229                     gsi_move_before (&i, &last);
1230                   else
1231                     gsi_move_after (&i, &last);
1232                 }
1233               else
1234                 {
1235                   gimple_stmt_iterator gsi = gsi_for_stmt (dom_use);
1236                   gsi_move_before (&i, &gsi);
1237                 }
1238
1239               gimple_set_vdef (stmt, NULL_TREE);
1240               gimple_set_vuse (stmt, NULL_TREE);
1241               update_stmt (stmt);
1242             }
1243         }
1244       else
1245         gsi_next (&i);
1246     }
1247 }
1248
1249 /* Initilize checker optimization pass.  */
1250 static void
1251 chkp_opt_init (void)
1252 {
1253   check_infos.create (0);
1254
1255   calculate_dominance_info (CDI_DOMINATORS);
1256   calculate_dominance_info (CDI_POST_DOMINATORS);
1257
1258   /* With LTO constant bounds vars may be not initialized by now.
1259      Get constant bounds vars to handle their assignments during
1260      optimizations.  */
1261   chkp_get_zero_bounds_var ();
1262   chkp_get_none_bounds_var ();
1263 }
1264
1265 /* Finalise checker optimization  pass.  */
1266 static void
1267 chkp_opt_fini (void)
1268 {
1269   chkp_fix_cfg ();
1270
1271   free_dominance_info (CDI_POST_DOMINATORS);
1272 }
1273
1274 /* Checker optimization pass function.  */
1275 static unsigned int
1276 chkp_opt_execute (void)
1277 {
1278   chkp_opt_init();
1279
1280   /* This optimization may introduce new checks
1281      and thus we put it before checks search.  */
1282   chkp_optimize_string_function_calls ();
1283
1284   chkp_gather_checks_info ();
1285
1286   chkp_remove_excess_intersections ();
1287
1288   chkp_remove_constant_checks ();
1289
1290   chkp_reduce_bounds_lifetime ();
1291
1292   chkp_release_check_info ();
1293
1294   chkp_opt_fini ();
1295
1296   return 0;
1297 }
1298
1299 /* Pass gate.  */
1300 static bool
1301 chkp_opt_gate (void)
1302 {
1303   return chkp_function_instrumented_p (cfun->decl)
1304     && (flag_chkp_optimize > 0
1305         || (flag_chkp_optimize == -1 && optimize > 0));
1306 }
1307
1308 namespace {
1309
1310 const pass_data pass_data_chkp_opt =
1311 {
1312   GIMPLE_PASS, /* type */
1313   "chkpopt", /* name */
1314   OPTGROUP_NONE, /* optinfo_flags */
1315   TV_NONE, /* tv_id */
1316   PROP_ssa | PROP_cfg, /* properties_required */
1317   0, /* properties_provided */
1318   0, /* properties_destroyed */
1319   0, /* todo_flags_start */
1320   TODO_verify_il
1321   | TODO_update_ssa /* todo_flags_finish */
1322 };
1323
1324 class pass_chkp_opt : public gimple_opt_pass
1325 {
1326 public:
1327   pass_chkp_opt (gcc::context *ctxt)
1328     : gimple_opt_pass (pass_data_chkp_opt, ctxt)
1329   {}
1330
1331   /* opt_pass methods: */
1332   virtual opt_pass * clone ()
1333     {
1334       return new pass_chkp_opt (m_ctxt);
1335     }
1336
1337   virtual bool gate (function *)
1338     {
1339       return chkp_opt_gate ();
1340     }
1341
1342   virtual unsigned int execute (function *)
1343     {
1344       return chkp_opt_execute ();
1345     }
1346
1347 }; // class pass_chkp_opt
1348
1349 } // anon namespace
1350
1351 gimple_opt_pass *
1352 make_pass_chkp_opt (gcc::context *ctxt)
1353 {
1354   return new pass_chkp_opt (ctxt);
1355 }