Backport from GCC mainline.
[platform/upstream/linaro-gcc.git] / gcc / tree-chkp-opt.c
1 /* Pointer Bounds Checker optimization pass.
2    Copyright (C) 2014-2016 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 = vNULL;
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 (integer_zerop (addr.pol[0].cst))
243     *sign = 0;
244   else if  (tree_int_cst_sign_bit (addr.pol[0].cst))
245     *sign = -1;
246   else
247     *sign = 1;
248
249   return true;
250 }
251
252 /* Dump ADDR into dump_file.  */
253 static void
254 chkp_print_addr (const address_t &addr)
255 {
256   unsigned int n = 0;
257   for (n = 0; n < addr.pol.length (); n++)
258     {
259       if (n > 0)
260         fprintf (dump_file, " + ");
261
262       if (addr.pol[n].var == NULL_TREE)
263         print_generic_expr (dump_file, addr.pol[n].cst, 0);
264       else
265         {
266           if (TREE_CODE (addr.pol[n].cst) != INTEGER_CST
267               || !integer_onep (addr.pol[n].cst))
268             {
269               print_generic_expr (dump_file, addr.pol[n].cst, 0);
270               fprintf (dump_file, " * ");
271             }
272           print_generic_expr (dump_file, addr.pol[n].var, 0);
273         }
274     }
275 }
276
277 /* Compute value of PTR and put it into address RES.
278    PTR has to be ADDR_EXPR.  */
279 static void
280 chkp_collect_addr_value (tree ptr, address_t &res)
281 {
282   tree obj = TREE_OPERAND (ptr, 0);
283   address_t addr;
284
285   switch (TREE_CODE (obj))
286     {
287     case INDIRECT_REF:
288       chkp_collect_value (TREE_OPERAND (obj, 0), res);
289       break;
290
291     case MEM_REF:
292       chkp_collect_value (TREE_OPERAND (obj, 0), res);
293       addr.pol.create (0);
294       chkp_collect_value (TREE_OPERAND (obj, 1), addr);
295       chkp_add_addr_addr (res, addr);
296       addr.pol.release ();
297       break;
298
299     case ARRAY_REF:
300       chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj, 0)), res);
301       addr.pol.create (0);
302       chkp_collect_value (TREE_OPERAND (obj, 1), addr);
303       chkp_mult_addr (addr, array_ref_element_size (obj));
304       chkp_add_addr_addr (res, addr);
305       addr.pol.release ();
306       break;
307
308     case COMPONENT_REF:
309       {
310         tree str = TREE_OPERAND (obj, 0);
311         tree field = TREE_OPERAND (obj, 1);
312         chkp_collect_value (build_fold_addr_expr (str), res);
313         addr.pol.create (0);
314         chkp_collect_value (component_ref_field_offset (obj), addr);
315         chkp_add_addr_addr (res, addr);
316         addr.pol.release ();
317         if (DECL_FIELD_BIT_OFFSET (field))
318           {
319             addr.pol.create (0);
320             chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR, size_type_node,
321                                              DECL_FIELD_BIT_OFFSET (field),
322                                              size_int (BITS_PER_UNIT)),
323                            addr);
324             chkp_add_addr_addr (res, addr);
325             addr.pol.release ();
326           }
327       }
328       break;
329
330     default:
331       chkp_add_addr_item (res, integer_one_node, ptr);
332       break;
333     }
334 }
335
336 /* Compute value of PTR and put it into address RES.  */
337 static void
338 chkp_collect_value (tree ptr, address_t &res)
339 {
340   gimple *def_stmt;
341   enum gimple_code code;
342   enum tree_code rhs_code;
343   address_t addr;
344   tree rhs1;
345
346   if (TREE_CODE (ptr) == INTEGER_CST)
347     {
348       chkp_add_addr_item (res, ptr, NULL);
349       return;
350     }
351   else if (TREE_CODE (ptr) == ADDR_EXPR)
352     {
353       chkp_collect_addr_value (ptr, res);
354       return;
355     }
356   else if (TREE_CODE (ptr) != SSA_NAME)
357     {
358       chkp_add_addr_item (res, integer_one_node, ptr);
359       return;
360     }
361
362   /* Now we handle the case when polynomial is computed
363      for SSA NAME.  */
364   def_stmt = SSA_NAME_DEF_STMT (ptr);
365   code = gimple_code (def_stmt);
366
367   /* Currently we do not walk through statements other
368      than assignment.  */
369   if (code != GIMPLE_ASSIGN)
370     {
371       chkp_add_addr_item (res, integer_one_node, ptr);
372       return;
373     }
374
375   rhs_code = gimple_assign_rhs_code (def_stmt);
376   rhs1 = gimple_assign_rhs1 (def_stmt);
377
378   switch (rhs_code)
379     {
380     case SSA_NAME:
381     case INTEGER_CST:
382     case ADDR_EXPR:
383       chkp_collect_value (rhs1, res);
384       break;
385
386     case PLUS_EXPR:
387     case POINTER_PLUS_EXPR:
388       chkp_collect_value (rhs1, res);
389       addr.pol.create (0);
390       chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
391       chkp_add_addr_addr (res, addr);
392       addr.pol.release ();
393       break;
394
395     case MINUS_EXPR:
396       chkp_collect_value (rhs1, res);
397       addr.pol.create (0);
398       chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
399       chkp_sub_addr_addr (res, addr);
400       addr.pol.release ();
401       break;
402
403     case MULT_EXPR:
404       if (TREE_CODE (rhs1) == SSA_NAME
405           && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == INTEGER_CST)
406         {
407           chkp_collect_value (rhs1, res);
408           chkp_mult_addr (res, gimple_assign_rhs2 (def_stmt));
409         }
410       else if (TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME
411                && TREE_CODE (rhs1) == INTEGER_CST)
412         {
413           chkp_collect_value (gimple_assign_rhs2 (def_stmt), res);
414           chkp_mult_addr (res, rhs1);
415         }
416       else
417         chkp_add_addr_item (res, integer_one_node, ptr);
418       break;
419
420     default:
421       chkp_add_addr_item (res, integer_one_node, ptr);
422       break;
423     }
424 }
425
426 /* Fill check_info structure *CI with information about
427    check STMT.  */
428 static void
429 chkp_fill_check_info (gimple *stmt, struct check_info *ci)
430 {
431   ci->addr.pol.create (0);
432   ci->bounds = gimple_call_arg (stmt, 1);
433   chkp_collect_value (gimple_call_arg (stmt, 0), ci->addr);
434   ci->type = (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
435              ? CHECK_LOWER_BOUND
436              : CHECK_UPPER_BOUND);
437   ci->stmt = stmt;
438 }
439
440 /* Release structures holding check information
441    for current function.  */
442 static void
443 chkp_release_check_info (void)
444 {
445   unsigned int n, m;
446
447   if (check_infos.exists ())
448     {
449       for (n = 0; n < check_infos.length (); n++)
450         {
451           for (m = 0; m < check_infos[n].checks.length (); m++)
452             if (check_infos[n].checks[m].addr.pol.exists ())
453               check_infos[n].checks[m].addr.pol.release ();
454           check_infos[n].checks.release ();
455         }
456       check_infos.release ();
457     }
458 }
459
460 /* Create structures to hold check information
461    for current function.  */
462 static void
463 chkp_init_check_info (void)
464 {
465   struct bb_checks empty_bbc;
466   int n;
467
468   empty_bbc.checks = vNULL;
469
470   chkp_release_check_info ();
471
472   check_infos.create (last_basic_block_for_fn (cfun));
473   for (n = 0; n < last_basic_block_for_fn (cfun); n++)
474     {
475       check_infos.safe_push (empty_bbc);
476       check_infos.last ().checks.create (0);
477     }
478 }
479
480 /* Find all checks in current function and store info about them
481    in check_infos.  */
482 static void
483 chkp_gather_checks_info (void)
484 {
485   basic_block bb;
486   gimple_stmt_iterator i;
487
488   if (dump_file && (dump_flags & TDF_DETAILS))
489     fprintf (dump_file, "Gathering information about checks...\n");
490
491   chkp_init_check_info ();
492
493   FOR_EACH_BB_FN (bb, cfun)
494     {
495       struct bb_checks *bbc = &check_infos[bb->index];
496
497       if (dump_file && (dump_flags & TDF_DETAILS))
498         fprintf (dump_file, "Searching checks in BB%d...\n", bb->index);
499
500       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
501         {
502           gimple *stmt = gsi_stmt (i);
503
504           if (gimple_code (stmt) != GIMPLE_CALL)
505             continue;
506
507           if (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
508               || gimple_call_fndecl (stmt) == chkp_checku_fndecl)
509             {
510               struct check_info ci;
511
512               chkp_fill_check_info (stmt, &ci);
513               bbc->checks.safe_push (ci);
514
515               if (dump_file && (dump_flags & TDF_DETAILS))
516                 {
517                   fprintf (dump_file, "Adding check information:\n");
518                   fprintf (dump_file, "  bounds: ");
519                   print_generic_expr (dump_file, ci.bounds, 0);
520                   fprintf (dump_file, "\n  address: ");
521                   chkp_print_addr (ci.addr);
522                   fprintf (dump_file, "\n  check: ");
523                   print_gimple_stmt (dump_file, stmt, 0, 0);
524                 }
525             }
526         }
527     }
528 }
529
530 /* Return 1 if check CI against BOUNDS always pass,
531    -1 if check CI against BOUNDS always fails and
532    0 if we cannot compute check result.  */
533 static int
534 chkp_get_check_result (struct check_info *ci, tree bounds)
535 {
536   gimple *bnd_def;
537   address_t bound_val;
538   int sign, res = 0;
539
540   if (dump_file && (dump_flags & TDF_DETAILS))
541     {
542       fprintf (dump_file, "Trying to compute result of the check\n");
543       fprintf (dump_file, "  check: ");
544       print_gimple_stmt (dump_file, ci->stmt, 0, 0);
545       fprintf (dump_file, "  address: ");
546       chkp_print_addr (ci->addr);
547       fprintf (dump_file, "\n  bounds: ");
548       print_generic_expr (dump_file, bounds, 0);
549       fprintf (dump_file, "\n");
550     }
551
552   if (TREE_CODE (bounds) != SSA_NAME)
553     {
554       if (dump_file && (dump_flags & TDF_DETAILS))
555         fprintf (dump_file, "  result: bounds tree code is not ssa_name\n");
556       return 0;
557     }
558
559   bnd_def = SSA_NAME_DEF_STMT (bounds);
560   /* Currently we handle cases when bounds are result of bndmk
561      or loaded static bounds var.  */
562   if (gimple_code (bnd_def) == GIMPLE_CALL
563       && gimple_call_fndecl (bnd_def) == chkp_bndmk_fndecl)
564     {
565       bound_val.pol.create (0);
566       chkp_collect_value (gimple_call_arg (bnd_def, 0), bound_val);
567       if (ci->type == CHECK_UPPER_BOUND)
568         {
569           address_t size_val;
570           size_val.pol.create (0);
571           chkp_collect_value (gimple_call_arg (bnd_def, 1), size_val);
572           chkp_add_addr_addr (bound_val, size_val);
573           size_val.pol.release ();
574           chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
575         }
576     }
577   else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
578            && gimple_assign_rhs1 (bnd_def) == chkp_get_zero_bounds_var ())
579     {
580       if (dump_file && (dump_flags & TDF_DETAILS))
581         fprintf (dump_file, "  result: always pass with zero bounds\n");
582       return 1;
583     }
584   else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
585            && gimple_assign_rhs1 (bnd_def) == chkp_get_none_bounds_var ())
586     {
587       if (dump_file && (dump_flags & TDF_DETAILS))
588         fprintf (dump_file, "  result: always fails with none bounds\n");
589       return -1;
590     }
591   else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
592            && TREE_CODE (gimple_assign_rhs1 (bnd_def)) == VAR_DECL)
593     {
594       tree bnd_var = gimple_assign_rhs1 (bnd_def);
595       tree var;
596       tree size;
597
598       if (!DECL_INITIAL (bnd_var)
599           || DECL_INITIAL (bnd_var) == error_mark_node)
600         {
601           if (dump_file && (dump_flags & TDF_DETAILS))
602             fprintf (dump_file, "  result: cannot compute bounds\n");
603           return 0;
604         }
605
606       gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var)) == ADDR_EXPR);
607       var = TREE_OPERAND (DECL_INITIAL (bnd_var), 0);
608
609       bound_val.pol.create (0);
610       chkp_collect_value (DECL_INITIAL (bnd_var), bound_val);
611       if (ci->type == CHECK_UPPER_BOUND)
612         {
613           if (TREE_CODE (var) == VAR_DECL)
614             {
615               if (DECL_SIZE (var)
616                   && !chkp_variable_size_type (TREE_TYPE (var)))
617                 size = DECL_SIZE_UNIT (var);
618               else
619                 {
620                   if (dump_file && (dump_flags & TDF_DETAILS))
621                     fprintf (dump_file, "  result: cannot compute bounds\n");
622                   return 0;
623                 }
624             }
625           else
626             {
627               gcc_assert (TREE_CODE (var) == STRING_CST);
628               size = build_int_cst (size_type_node,
629                                     TREE_STRING_LENGTH (var));
630             }
631
632           address_t size_val;
633           size_val.pol.create (0);
634           chkp_collect_value (size, size_val);
635           chkp_add_addr_addr (bound_val, size_val);
636           size_val.pol.release ();
637           chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
638         }
639     }
640   else
641     {
642       if (dump_file && (dump_flags & TDF_DETAILS))
643         fprintf (dump_file, "  result: cannot compute bounds\n");
644       return 0;
645     }
646
647   if (dump_file && (dump_flags & TDF_DETAILS))
648     {
649       fprintf (dump_file, "  bound value: ");
650       chkp_print_addr (bound_val);
651       fprintf (dump_file, "\n");
652     }
653
654   chkp_sub_addr_addr (bound_val, ci->addr);
655
656   if (!chkp_is_constant_addr (bound_val, &sign))
657     {
658       if (dump_file && (dump_flags & TDF_DETAILS))
659         fprintf (dump_file, "  result: cannot compute result\n");
660
661       res = 0;
662     }
663   else if (sign == 0
664            || (ci->type == CHECK_UPPER_BOUND && sign > 0)
665            || (ci->type == CHECK_LOWER_BOUND && sign < 0))
666     {
667       if (dump_file && (dump_flags & TDF_DETAILS))
668         fprintf (dump_file, "  result: always pass\n");
669
670       res = 1;
671     }
672   else
673     {
674       if (dump_file && (dump_flags & TDF_DETAILS))
675         fprintf (dump_file, "  result: always fail\n");
676
677       res = -1;
678     }
679
680   bound_val.pol.release ();
681
682   return res;
683 }
684
685 /* Try to compare bounds value and address value
686    used in the check CI.  If we can prove that check
687    always pass then remove it.  */
688 static void
689 chkp_remove_check_if_pass (struct check_info *ci)
690 {
691   int result = 0;
692
693   if (dump_file && (dump_flags & TDF_DETAILS))
694     {
695       fprintf (dump_file, "Trying to remove check: ");
696       print_gimple_stmt (dump_file, ci->stmt, 0, 0);
697     }
698
699   result = chkp_get_check_result (ci, ci->bounds);
700
701   if (result == 1)
702     {
703       gimple_stmt_iterator i = gsi_for_stmt (ci->stmt);
704
705       if (dump_file && (dump_flags & TDF_DETAILS))
706         fprintf (dump_file, "  action: delete check (always pass)\n");
707
708       gsi_remove (&i, true);
709       unlink_stmt_vdef (ci->stmt);
710       release_defs (ci->stmt);
711       ci->stmt = NULL;
712     }
713   else if (result == -1)
714     {
715       if (dump_file && (dump_flags & TDF_DETAILS))
716         fprintf (dump_file, "  action: keep check (always fail)\n");
717       warning_at (gimple_location (ci->stmt), OPT_Wchkp,
718                   "memory access check always fail");
719     }
720   else if (result == 0)
721     {
722       if (dump_file && (dump_flags & TDF_DETAILS))
723         fprintf (dump_file, "  action: keep check (cannot compute result)\n");
724     }
725 }
726
727 /* For bounds used in CI check if bounds are produced by
728    intersection and we may use outer bounds instead.  If
729    transformation is possible then fix check statement and
730    recompute its info.  */
731 static void
732 chkp_use_outer_bounds_if_possible (struct check_info *ci)
733 {
734   gimple *bnd_def;
735   tree bnd1, bnd2, bnd_res = NULL;
736   int check_res1, check_res2;
737
738   if (TREE_CODE (ci->bounds) != SSA_NAME)
739     return;
740
741   bnd_def = SSA_NAME_DEF_STMT (ci->bounds);
742   if (gimple_code (bnd_def) != GIMPLE_CALL
743       || gimple_call_fndecl (bnd_def) != chkp_intersect_fndecl)
744     return;
745
746   if (dump_file && (dump_flags & TDF_DETAILS))
747     {
748       fprintf (dump_file, "Check if bounds intersection is redundant: \n");
749       fprintf (dump_file, "  check: ");
750       print_gimple_stmt (dump_file, ci->stmt, 0, 0);
751       fprintf (dump_file, "  intersection: ");
752       print_gimple_stmt (dump_file, bnd_def, 0, 0);
753       fprintf (dump_file, "\n");
754     }
755
756   bnd1 = gimple_call_arg (bnd_def, 0);
757   bnd2 = gimple_call_arg (bnd_def, 1);
758
759   check_res1 = chkp_get_check_result (ci, bnd1);
760   check_res2 = chkp_get_check_result (ci, bnd2);
761   if (check_res1 == 1)
762     bnd_res = bnd2;
763   else if (check_res1 == -1)
764     bnd_res = bnd1;
765   else if (check_res2 == 1)
766     bnd_res = bnd1;
767   else if (check_res2 == -1)
768     bnd_res = bnd2;
769
770   if (bnd_res)
771     {
772       if (dump_file && (dump_flags & TDF_DETAILS))
773         {
774           fprintf (dump_file, "  action: use ");
775           print_generic_expr (dump_file, bnd2, 0);
776           fprintf (dump_file, " instead of ");
777           print_generic_expr (dump_file, ci->bounds, 0);
778           fprintf (dump_file, "\n");
779         }
780
781       ci->bounds = bnd_res;
782       gimple_call_set_arg (ci->stmt, 1, bnd_res);
783       update_stmt (ci->stmt);
784       chkp_fill_check_info (ci->stmt, ci);
785     }
786 }
787
788 /*  Try to find checks whose bounds were produced by intersection
789     which does not affect check result.  In such check outer bounds
790     are used instead.  It allows to remove excess intersections
791     and helps to compare checks.  */
792 static void
793 chkp_remove_excess_intersections (void)
794 {
795   basic_block bb;
796
797   if (dump_file && (dump_flags & TDF_DETAILS))
798     fprintf (dump_file, "Searching for redundant bounds intersections...\n");
799
800   FOR_EACH_BB_FN (bb, cfun)
801     {
802       struct bb_checks *bbc = &check_infos[bb->index];
803       unsigned int no;
804
805       /* Iterate through all found checks in BB.  */
806       for (no = 0; no < bbc->checks.length (); no++)
807         if (bbc->checks[no].stmt)
808           chkp_use_outer_bounds_if_possible (&bbc->checks[no]);
809     }
810 }
811
812 /*  Try to remove all checks which are known to alwyas pass.  */
813 static void
814 chkp_remove_constant_checks (void)
815 {
816   basic_block bb;
817
818   if (dump_file && (dump_flags & TDF_DETAILS))
819     fprintf (dump_file, "Searching for redundant checks...\n");
820
821   FOR_EACH_BB_FN (bb, cfun)
822     {
823       struct bb_checks *bbc = &check_infos[bb->index];
824       unsigned int no;
825
826       /* Iterate through all found checks in BB.  */
827       for (no = 0; no < bbc->checks.length (); no++)
828         if (bbc->checks[no].stmt)
829           chkp_remove_check_if_pass (&bbc->checks[no]);
830     }
831 }
832
833 /* Return fast version of string function FNCODE.  */
834 static tree
835 chkp_get_nobnd_fndecl (enum built_in_function fncode)
836 {
837   /* Check if we are allowed to use fast string functions.  */
838   if (!flag_chkp_use_fast_string_functions)
839     return NULL_TREE;
840
841   tree fndecl = NULL_TREE;
842
843   switch (fncode)
844     {
845     case BUILT_IN_MEMCPY_CHKP:
846       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND);
847       break;
848
849     case BUILT_IN_MEMPCPY_CHKP:
850       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND);
851       break;
852
853     case BUILT_IN_MEMMOVE_CHKP:
854       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND);
855       break;
856
857     case BUILT_IN_MEMSET_CHKP:
858       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND);
859       break;
860
861     case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP:
862       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
863       break;
864
865     case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP:
866       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
867       break;
868
869     case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP:
870       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
871       break;
872
873     case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP:
874       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
875       break;
876
877     default:
878       break;
879     }
880
881   if (fndecl)
882     fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
883
884   return fndecl;
885 }
886
887
888 /* Return no-check version of string function FNCODE.  */
889 static tree
890 chkp_get_nochk_fndecl (enum built_in_function fncode)
891 {
892   /* Check if we are allowed to use fast string functions.  */
893   if (!flag_chkp_use_nochk_string_functions)
894     return NULL_TREE;
895
896   tree fndecl = NULL_TREE;
897
898   switch (fncode)
899     {
900     case BUILT_IN_MEMCPY_CHKP:
901       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK);
902       break;
903
904     case BUILT_IN_MEMPCPY_CHKP:
905       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK);
906       break;
907
908     case BUILT_IN_MEMMOVE_CHKP:
909       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK);
910       break;
911
912     case BUILT_IN_MEMSET_CHKP:
913       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK);
914       break;
915
916     case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP:
917       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
918       break;
919
920     case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP:
921       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
922       break;
923
924     case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP:
925       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
926       break;
927
928     case BUILT_IN_CHKP_MEMSET_NOBND_CHKP:
929       fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
930       break;
931
932     default:
933       break;
934     }
935
936   if (fndecl)
937     fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
938
939   return fndecl;
940 }
941
942 /* Find memcpy, mempcpy, memmove and memset calls, perform
943    checks before call and then call no_chk version of
944    functions.  We do it on O2 to enable inlining of these
945    functions during expand.
946
947    Also try to find memcpy, mempcpy, memmove and memset calls
948    which are known to not write pointers to memory and use
949    faster function versions for them.  */
950 static void
951 chkp_optimize_string_function_calls (void)
952 {
953   basic_block bb;
954
955   if (dump_file && (dump_flags & TDF_DETAILS))
956     fprintf (dump_file, "Searching for replaceable string function calls...\n");
957
958   FOR_EACH_BB_FN (bb, cfun)
959     {
960       gimple_stmt_iterator i;
961
962       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
963         {
964           gimple *stmt = gsi_stmt (i);
965           tree fndecl;
966
967           if (gimple_code (stmt) != GIMPLE_CALL
968               || !gimple_call_with_bounds_p (stmt))
969             continue;
970
971           fndecl = gimple_call_fndecl (stmt);
972
973           if (!fndecl || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
974             continue;
975
976           if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMCPY_CHKP
977               || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHKP
978               || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMMOVE_CHKP
979               || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP)
980             {
981               tree dst = gimple_call_arg (stmt, 0);
982               tree dst_bnd = gimple_call_arg (stmt, 1);
983               bool is_memset = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP;
984               tree size = gimple_call_arg (stmt, is_memset ? 3 : 4);
985               tree fndecl_nochk;
986               gimple_stmt_iterator j;
987               basic_block check_bb;
988               address_t size_val;
989               int sign;
990               bool known;
991
992               /* We may replace call with corresponding __chkp_*_nobnd
993                  call in case destination pointer base type is not
994                  void or pointer.  */
995               if (POINTER_TYPE_P (TREE_TYPE (dst))
996                   && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst)))
997                   && !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst))))
998                 {
999                   tree fndecl_nobnd
1000                     = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl));
1001
1002                   if (fndecl_nobnd)
1003                     fndecl = fndecl_nobnd;
1004                 }
1005
1006               fndecl_nochk = chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl));
1007
1008               if (fndecl_nochk)
1009                 fndecl = fndecl_nochk;
1010
1011               if (fndecl != gimple_call_fndecl (stmt))
1012                 {
1013                   if (dump_file && (dump_flags & TDF_DETAILS))
1014                     {
1015                       fprintf (dump_file, "Replacing call: ");
1016                       print_gimple_stmt (dump_file, stmt, 0,
1017                                          TDF_VOPS|TDF_MEMSYMS);
1018                     }
1019
1020                   gimple_call_set_fndecl (stmt, fndecl);
1021
1022                   if (dump_file && (dump_flags & TDF_DETAILS))
1023                     {
1024                       fprintf (dump_file, "With a new call: ");
1025                       print_gimple_stmt (dump_file, stmt, 0,
1026                                          TDF_VOPS|TDF_MEMSYMS);
1027                     }
1028                 }
1029
1030               /* If there is no nochk version of function then
1031                  do nothing.  Otherwise insert checks before
1032                  the call.  */
1033               if (!fndecl_nochk)
1034                 continue;
1035
1036               /* If size passed to call is known and > 0
1037                  then we may insert checks unconditionally.  */
1038               size_val.pol.create (0);
1039               chkp_collect_value (size, size_val);
1040               known = chkp_is_constant_addr (size_val, &sign);
1041               size_val.pol.release ();
1042
1043               /* If we are not sure size is not zero then we have
1044                  to perform runtime check for size and perform
1045                  checks only when size is not zero.  */
1046               if (!known)
1047                 {
1048                   gimple *check = gimple_build_cond (NE_EXPR,
1049                                                      size,
1050                                                      size_zero_node,
1051                                                      NULL_TREE,
1052                                                      NULL_TREE);
1053
1054                   /* Split block before string function call.  */
1055                   gsi_prev (&i);
1056                   check_bb = insert_cond_bb (bb, gsi_stmt (i), check);
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, 0);
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               update_stmt (stmt);
1240             }
1241         }
1242       else
1243         gsi_next (&i);
1244     }
1245 }
1246
1247 /* Initilize checker optimization pass.  */
1248 static void
1249 chkp_opt_init (void)
1250 {
1251   check_infos.create (0);
1252
1253   calculate_dominance_info (CDI_DOMINATORS);
1254   calculate_dominance_info (CDI_POST_DOMINATORS);
1255
1256   /* With LTO constant bounds vars may be not initialized by now.
1257      Get constant bounds vars to handle their assignments during
1258      optimizations.  */
1259   chkp_get_zero_bounds_var ();
1260   chkp_get_none_bounds_var ();
1261 }
1262
1263 /* Finalise checker optimization  pass.  */
1264 static void
1265 chkp_opt_fini (void)
1266 {
1267   chkp_fix_cfg ();
1268
1269   free_dominance_info (CDI_POST_DOMINATORS);
1270 }
1271
1272 /* Checker optimization pass function.  */
1273 static unsigned int
1274 chkp_opt_execute (void)
1275 {
1276   chkp_opt_init();
1277
1278   /* This optimization may introduce new checks
1279      and thus we put it before checks search.  */
1280   chkp_optimize_string_function_calls ();
1281
1282   chkp_gather_checks_info ();
1283
1284   chkp_remove_excess_intersections ();
1285
1286   chkp_remove_constant_checks ();
1287
1288   chkp_reduce_bounds_lifetime ();
1289
1290   chkp_release_check_info ();
1291
1292   chkp_opt_fini ();
1293
1294   return 0;
1295 }
1296
1297 /* Pass gate.  */
1298 static bool
1299 chkp_opt_gate (void)
1300 {
1301   return chkp_function_instrumented_p (cfun->decl)
1302     && (flag_chkp_optimize > 0
1303         || (flag_chkp_optimize == -1 && optimize > 0));
1304 }
1305
1306 namespace {
1307
1308 const pass_data pass_data_chkp_opt =
1309 {
1310   GIMPLE_PASS, /* type */
1311   "chkpopt", /* name */
1312   OPTGROUP_NONE, /* optinfo_flags */
1313   TV_NONE, /* tv_id */
1314   PROP_ssa | PROP_cfg, /* properties_required */
1315   0, /* properties_provided */
1316   0, /* properties_destroyed */
1317   0, /* todo_flags_start */
1318   TODO_verify_il
1319   | TODO_update_ssa /* todo_flags_finish */
1320 };
1321
1322 class pass_chkp_opt : public gimple_opt_pass
1323 {
1324 public:
1325   pass_chkp_opt (gcc::context *ctxt)
1326     : gimple_opt_pass (pass_data_chkp_opt, ctxt)
1327   {}
1328
1329   /* opt_pass methods: */
1330   virtual opt_pass * clone ()
1331     {
1332       return new pass_chkp_opt (m_ctxt);
1333     }
1334
1335   virtual bool gate (function *)
1336     {
1337       return chkp_opt_gate ();
1338     }
1339
1340   virtual unsigned int execute (function *)
1341     {
1342       return chkp_opt_execute ();
1343     }
1344
1345 }; // class pass_chkp_opt
1346
1347 } // anon namespace
1348
1349 gimple_opt_pass *
1350 make_pass_chkp_opt (gcc::context *ctxt)
1351 {
1352   return new pass_chkp_opt (ctxt);
1353 }