* ipa-prop.c (ipa_modify_expr): Set REF_REVERSE_STORAGE_ORDER on the
[official-gcc.git] / gcc / tree-chkp-opt.c
blob59a0b405bf17c2ffef87360c2c90933ca15318ad
1 /* Pointer Bounds Checker optimization pass.
2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "input.h"
25 #include "alias.h"
26 #include "symtab.h"
27 #include "options.h"
28 #include "tree.h"
29 #include "fold-const.h"
30 #include "target.h"
31 #include "tree-cfg.h"
32 #include "tree-pass.h"
33 #include "is-a.h"
34 #include "cfgloop.h"
35 #include "stringpool.h"
36 #include "tree-ssa-alias.h"
37 #include "tree-ssanames.h"
38 #include "tree-ssa-operands.h"
39 #include "tree-ssa-address.h"
40 #include "tree-ssa.h"
41 #include "predict.h"
42 #include "dominance.h"
43 #include "cfg.h"
44 #include "basic-block.h"
45 #include "tree-ssa-loop-niter.h"
46 #include "gimple-expr.h"
47 #include "gimple.h"
48 #include "tree-phinodes.h"
49 #include "gimple-ssa.h"
50 #include "ssa-iterators.h"
51 #include "gimple-pretty-print.h"
52 #include "gimple-iterator.h"
53 #include "gimplify.h"
54 #include "gimplify-me.h"
55 #include "tm.h"
56 #include "hard-reg-set.h"
57 #include "function.h"
58 #include "rtl.h"
59 #include "flags.h"
60 #include "insn-config.h"
61 #include "expmed.h"
62 #include "dojump.h"
63 #include "explow.h"
64 #include "calls.h"
65 #include "emit-rtl.h"
66 #include "varasm.h"
67 #include "stmt.h"
68 #include "expr.h"
69 #include "tree-chkp.h"
70 #include "ipa-chkp.h"
71 #include "diagnostic.h"
73 enum check_type
75 CHECK_LOWER_BOUND,
76 CHECK_UPPER_BOUND
79 struct pol_item
81 tree cst;
82 tree var;
85 struct address_t
87 vec<struct pol_item> pol;
90 /* Structure to hold check informtation. */
91 struct check_info
93 /* Type of the check. */
94 check_type type;
95 /* Address used for the check. */
96 address_t addr;
97 /* Bounds used for the check. */
98 tree bounds;
99 /* Check statement. Can be NULL for removed checks. */
100 gimple stmt;
103 /* Structure to hold checks information for BB. */
104 struct bb_checks
106 vec<struct check_info, va_heap, vl_ptr> checks;
109 static void chkp_collect_value (tree ssa_name, address_t &res);
111 #define chkp_bndmk_fndecl \
112 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
113 #define chkp_intersect_fndecl \
114 (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
115 #define chkp_checkl_fndecl \
116 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
117 #define chkp_checku_fndecl \
118 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
120 static vec<struct bb_checks, va_heap, vl_ptr> check_infos = vNULL;
122 /* Comparator for pol_item structures I1 and I2 to be used
123 to find items with equal var. Also used for polynomial
124 sorting. */
125 static int
126 chkp_pol_item_compare (const void *i1, const void *i2)
128 const struct pol_item *p1 = (const struct pol_item *)i1;
129 const struct pol_item *p2 = (const struct pol_item *)i2;
131 if (p1->var == p2->var)
132 return 0;
133 else if (p1->var > p2->var)
134 return 1;
135 else
136 return -1;
139 /* Find polynomial item in ADDR with var equal to VAR
140 and return its index. Return -1 if item was not
141 found. */
142 static int
143 chkp_pol_find (address_t &addr, tree var)
145 int left = 0;
146 int right = addr.pol.length () - 1;
147 int n;
149 while (right >= left)
151 n = (left + right) / 2;
153 if (addr.pol[n].var == var
154 || (var && addr.pol[n].var
155 && TREE_CODE (var) == ADDR_EXPR
156 && TREE_CODE (addr.pol[n].var) == ADDR_EXPR
157 && TREE_OPERAND (var, 0) == TREE_OPERAND (addr.pol[n].var, 0)))
158 return n;
159 else if (addr.pol[n].var > var)
160 right = n - 1;
161 else
162 left = n + 1;
165 return -1;
168 /* Return constant CST extended to size type. */
169 static tree
170 chkp_extend_const (tree cst)
172 if (TYPE_PRECISION (TREE_TYPE (cst)) < TYPE_PRECISION (size_type_node))
173 return build_int_cst_type (size_type_node, tree_to_shwi (cst));
175 return cst;
178 /* Add polynomial item CST * VAR to ADDR. */
179 static void
180 chkp_add_addr_item (address_t &addr, tree cst, tree var)
182 int n = chkp_pol_find (addr, var);
184 cst = chkp_extend_const (cst);
186 if (n < 0)
188 struct pol_item item;
189 item.cst = cst;
190 item.var = var;
192 addr.pol.safe_push (item);
193 addr.pol.qsort (&chkp_pol_item_compare);
195 else
197 addr.pol[n].cst = fold_build2 (PLUS_EXPR, TREE_TYPE (addr.pol[n].cst),
198 addr.pol[n].cst, cst);
199 if (TREE_CODE (addr.pol[n].cst) == INTEGER_CST
200 && integer_zerop (addr.pol[n].cst))
201 addr.pol.ordered_remove (n);
205 /* Subtract polynomial item CST * VAR from ADDR. */
206 static void
207 chkp_sub_addr_item (address_t &addr, tree cst, tree var)
209 int n = chkp_pol_find (addr, var);
211 cst = chkp_extend_const (cst);
213 if (n < 0)
215 struct pol_item item;
216 item.cst = fold_build2 (MINUS_EXPR, TREE_TYPE (cst),
217 integer_zero_node, cst);
218 item.var = var;
220 addr.pol.safe_push (item);
221 addr.pol.qsort (&chkp_pol_item_compare);
223 else
225 addr.pol[n].cst = fold_build2 (MINUS_EXPR, TREE_TYPE (addr.pol[n].cst),
226 addr.pol[n].cst, cst);
227 if (TREE_CODE (addr.pol[n].cst) == INTEGER_CST
228 && integer_zerop (addr.pol[n].cst))
229 addr.pol.ordered_remove (n);
233 /* Add address DELTA to ADDR. */
234 static void
235 chkp_add_addr_addr (address_t &addr, address_t &delta)
237 unsigned int i;
238 for (i = 0; i < delta.pol.length (); i++)
239 chkp_add_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
242 /* Subtract address DELTA from ADDR. */
243 static void
244 chkp_sub_addr_addr (address_t &addr, address_t &delta)
246 unsigned int i;
247 for (i = 0; i < delta.pol.length (); i++)
248 chkp_sub_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
251 /* Mutiply address ADDR by integer constant MULT. */
252 static void
253 chkp_mult_addr (address_t &addr, tree mult)
255 unsigned int i;
256 for (i = 0; i < addr.pol.length (); i++)
257 addr.pol[i].cst = fold_build2 (MULT_EXPR, TREE_TYPE (addr.pol[i].cst),
258 addr.pol[i].cst, mult);
261 /* Return 1 if we may prove ADDR has a constant value with
262 determined sign, which is put into *SIGN. Otherwise
263 return 0. */
264 static bool
265 chkp_is_constant_addr (const address_t &addr, int *sign)
267 *sign = 0;
269 if (addr.pol.length () == 0)
270 return true;
271 else if (addr.pol.length () > 1)
272 return false;
273 else if (addr.pol[0].var)
274 return false;
275 else if (integer_zerop (addr.pol[0].cst))
276 *sign = 0;
277 else if (tree_int_cst_sign_bit (addr.pol[0].cst))
278 *sign = -1;
279 else
280 *sign = 1;
282 return true;
285 /* Dump ADDR into dump_file. */
286 static void
287 chkp_print_addr (const address_t &addr)
289 unsigned int n = 0;
290 for (n = 0; n < addr.pol.length (); n++)
292 if (n > 0)
293 fprintf (dump_file, " + ");
295 if (addr.pol[n].var == NULL_TREE)
296 print_generic_expr (dump_file, addr.pol[n].cst, 0);
297 else
299 if (TREE_CODE (addr.pol[n].cst) != INTEGER_CST
300 || !integer_onep (addr.pol[n].cst))
302 print_generic_expr (dump_file, addr.pol[n].cst, 0);
303 fprintf (dump_file, " * ");
305 print_generic_expr (dump_file, addr.pol[n].var, 0);
310 /* Compute value of PTR and put it into address RES.
311 PTR has to be ADDR_EXPR. */
312 static void
313 chkp_collect_addr_value (tree ptr, address_t &res)
315 tree obj = TREE_OPERAND (ptr, 0);
316 address_t addr;
318 switch (TREE_CODE (obj))
320 case INDIRECT_REF:
321 chkp_collect_value (TREE_OPERAND (obj, 0), res);
322 break;
324 case MEM_REF:
325 chkp_collect_value (TREE_OPERAND (obj, 0), res);
326 addr.pol.create (0);
327 chkp_collect_value (TREE_OPERAND (obj, 1), addr);
328 chkp_add_addr_addr (res, addr);
329 addr.pol.release ();
330 break;
332 case ARRAY_REF:
333 chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj, 0)), res);
334 addr.pol.create (0);
335 chkp_collect_value (TREE_OPERAND (obj, 1), addr);
336 chkp_mult_addr (addr, array_ref_element_size (obj));
337 chkp_add_addr_addr (res, addr);
338 addr.pol.release ();
339 break;
341 case COMPONENT_REF:
343 tree str = TREE_OPERAND (obj, 0);
344 tree field = TREE_OPERAND (obj, 1);
345 chkp_collect_value (build_fold_addr_expr (str), res);
346 addr.pol.create (0);
347 chkp_collect_value (component_ref_field_offset (obj), addr);
348 chkp_add_addr_addr (res, addr);
349 addr.pol.release ();
350 if (DECL_FIELD_BIT_OFFSET (field))
352 addr.pol.create (0);
353 chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR, size_type_node,
354 DECL_FIELD_BIT_OFFSET (field),
355 size_int (BITS_PER_UNIT)),
356 addr);
357 chkp_add_addr_addr (res, addr);
358 addr.pol.release ();
361 break;
363 default:
364 chkp_add_addr_item (res, integer_one_node, ptr);
365 break;
369 /* Compute value of PTR and put it into address RES. */
370 static void
371 chkp_collect_value (tree ptr, address_t &res)
373 gimple def_stmt;
374 enum gimple_code code;
375 enum tree_code rhs_code;
376 address_t addr;
377 tree rhs1;
379 if (TREE_CODE (ptr) == INTEGER_CST)
381 chkp_add_addr_item (res, ptr, NULL);
382 return;
384 else if (TREE_CODE (ptr) == ADDR_EXPR)
386 chkp_collect_addr_value (ptr, res);
387 return;
389 else if (TREE_CODE (ptr) != SSA_NAME)
391 chkp_add_addr_item (res, integer_one_node, ptr);
392 return;
395 /* Now we handle the case when polynomial is computed
396 for SSA NAME. */
397 def_stmt = SSA_NAME_DEF_STMT (ptr);
398 code = gimple_code (def_stmt);
400 /* Currently we do not walk through statements other
401 than assignment. */
402 if (code != GIMPLE_ASSIGN)
404 chkp_add_addr_item (res, integer_one_node, ptr);
405 return;
408 rhs_code = gimple_assign_rhs_code (def_stmt);
409 rhs1 = gimple_assign_rhs1 (def_stmt);
411 switch (rhs_code)
413 case SSA_NAME:
414 case INTEGER_CST:
415 case ADDR_EXPR:
416 chkp_collect_value (rhs1, res);
417 break;
419 case PLUS_EXPR:
420 case POINTER_PLUS_EXPR:
421 chkp_collect_value (rhs1, res);
422 addr.pol.create (0);
423 chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
424 chkp_add_addr_addr (res, addr);
425 addr.pol.release ();
426 break;
428 case MINUS_EXPR:
429 chkp_collect_value (rhs1, res);
430 addr.pol.create (0);
431 chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
432 chkp_sub_addr_addr (res, addr);
433 addr.pol.release ();
434 break;
436 case MULT_EXPR:
437 if (TREE_CODE (rhs1) == SSA_NAME
438 && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == INTEGER_CST)
440 chkp_collect_value (rhs1, res);
441 chkp_mult_addr (res, gimple_assign_rhs2 (def_stmt));
443 else if (TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME
444 && TREE_CODE (rhs1) == INTEGER_CST)
446 chkp_collect_value (gimple_assign_rhs2 (def_stmt), res);
447 chkp_mult_addr (res, rhs1);
449 else
450 chkp_add_addr_item (res, integer_one_node, ptr);
451 break;
453 default:
454 chkp_add_addr_item (res, integer_one_node, ptr);
455 break;
459 /* Fill check_info structure *CI with information about
460 check STMT. */
461 static void
462 chkp_fill_check_info (gimple stmt, struct check_info *ci)
464 ci->addr.pol.create (0);
465 ci->bounds = gimple_call_arg (stmt, 1);
466 chkp_collect_value (gimple_call_arg (stmt, 0), ci->addr);
467 ci->type = (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
468 ? CHECK_LOWER_BOUND
469 : CHECK_UPPER_BOUND);
470 ci->stmt = stmt;
473 /* Release structures holding check information
474 for current function. */
475 static void
476 chkp_release_check_info (void)
478 unsigned int n, m;
480 if (check_infos.exists ())
482 for (n = 0; n < check_infos.length (); n++)
484 for (m = 0; m < check_infos[n].checks.length (); m++)
485 if (check_infos[n].checks[m].addr.pol.exists ())
486 check_infos[n].checks[m].addr.pol.release ();
487 check_infos[n].checks.release ();
489 check_infos.release ();
493 /* Create structures to hold check information
494 for current function. */
495 static void
496 chkp_init_check_info (void)
498 struct bb_checks empty_bbc;
499 int n;
501 empty_bbc.checks = vNULL;
503 chkp_release_check_info ();
505 check_infos.create (last_basic_block_for_fn (cfun));
506 for (n = 0; n < last_basic_block_for_fn (cfun); n++)
508 check_infos.safe_push (empty_bbc);
509 check_infos.last ().checks.create (0);
513 /* Find all checks in current function and store info about them
514 in check_infos. */
515 static void
516 chkp_gather_checks_info (void)
518 basic_block bb;
519 gimple_stmt_iterator i;
521 if (dump_file && (dump_flags & TDF_DETAILS))
522 fprintf (dump_file, "Gathering information about checks...\n");
524 chkp_init_check_info ();
526 FOR_EACH_BB_FN (bb, cfun)
528 struct bb_checks *bbc = &check_infos[bb->index];
530 if (dump_file && (dump_flags & TDF_DETAILS))
531 fprintf (dump_file, "Searching checks in BB%d...\n", bb->index);
533 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
535 gimple stmt = gsi_stmt (i);
537 if (gimple_code (stmt) != GIMPLE_CALL)
538 continue;
540 if (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
541 || gimple_call_fndecl (stmt) == chkp_checku_fndecl)
543 struct check_info ci;
545 chkp_fill_check_info (stmt, &ci);
546 bbc->checks.safe_push (ci);
548 if (dump_file && (dump_flags & TDF_DETAILS))
550 fprintf (dump_file, "Adding check information:\n");
551 fprintf (dump_file, " bounds: ");
552 print_generic_expr (dump_file, ci.bounds, 0);
553 fprintf (dump_file, "\n address: ");
554 chkp_print_addr (ci.addr);
555 fprintf (dump_file, "\n check: ");
556 print_gimple_stmt (dump_file, stmt, 0, 0);
563 /* Return 1 if check CI against BOUNDS always pass,
564 -1 if check CI against BOUNDS always fails and
565 0 if we cannot compute check result. */
566 static int
567 chkp_get_check_result (struct check_info *ci, tree bounds)
569 gimple bnd_def;
570 address_t bound_val;
571 int sign, res = 0;
573 if (dump_file && (dump_flags & TDF_DETAILS))
575 fprintf (dump_file, "Trying to compute result of the check\n");
576 fprintf (dump_file, " check: ");
577 print_gimple_stmt (dump_file, ci->stmt, 0, 0);
578 fprintf (dump_file, " address: ");
579 chkp_print_addr (ci->addr);
580 fprintf (dump_file, "\n bounds: ");
581 print_generic_expr (dump_file, bounds, 0);
582 fprintf (dump_file, "\n");
585 if (TREE_CODE (bounds) != SSA_NAME)
587 if (dump_file && (dump_flags & TDF_DETAILS))
588 fprintf (dump_file, " result: bounds tree code is not ssa_name\n");
589 return 0;
592 bnd_def = SSA_NAME_DEF_STMT (bounds);
593 /* Currently we handle cases when bounds are result of bndmk
594 or loaded static bounds var. */
595 if (gimple_code (bnd_def) == GIMPLE_CALL
596 && gimple_call_fndecl (bnd_def) == chkp_bndmk_fndecl)
598 bound_val.pol.create (0);
599 chkp_collect_value (gimple_call_arg (bnd_def, 0), bound_val);
600 if (ci->type == CHECK_UPPER_BOUND)
602 address_t size_val;
603 size_val.pol.create (0);
604 chkp_collect_value (gimple_call_arg (bnd_def, 1), size_val);
605 chkp_add_addr_addr (bound_val, size_val);
606 size_val.pol.release ();
607 chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
610 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
611 && gimple_assign_rhs1 (bnd_def) == chkp_get_zero_bounds_var ())
613 if (dump_file && (dump_flags & TDF_DETAILS))
614 fprintf (dump_file, " result: always pass with zero bounds\n");
615 return 1;
617 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
618 && gimple_assign_rhs1 (bnd_def) == chkp_get_none_bounds_var ())
620 if (dump_file && (dump_flags & TDF_DETAILS))
621 fprintf (dump_file, " result: always fails with none bounds\n");
622 return -1;
624 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
625 && TREE_CODE (gimple_assign_rhs1 (bnd_def)) == VAR_DECL)
627 tree bnd_var = gimple_assign_rhs1 (bnd_def);
628 tree var;
629 tree size;
631 if (!DECL_INITIAL (bnd_var)
632 || DECL_INITIAL (bnd_var) == error_mark_node)
634 if (dump_file && (dump_flags & TDF_DETAILS))
635 fprintf (dump_file, " result: cannot compute bounds\n");
636 return 0;
639 gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var)) == ADDR_EXPR);
640 var = TREE_OPERAND (DECL_INITIAL (bnd_var), 0);
642 bound_val.pol.create (0);
643 chkp_collect_value (DECL_INITIAL (bnd_var), bound_val);
644 if (ci->type == CHECK_UPPER_BOUND)
646 if (TREE_CODE (var) == VAR_DECL)
648 if (DECL_SIZE (var)
649 && !chkp_variable_size_type (TREE_TYPE (var)))
650 size = DECL_SIZE_UNIT (var);
651 else
653 if (dump_file && (dump_flags & TDF_DETAILS))
654 fprintf (dump_file, " result: cannot compute bounds\n");
655 return 0;
658 else
660 gcc_assert (TREE_CODE (var) == STRING_CST);
661 size = build_int_cst (size_type_node,
662 TREE_STRING_LENGTH (var));
665 address_t size_val;
666 size_val.pol.create (0);
667 chkp_collect_value (size, size_val);
668 chkp_add_addr_addr (bound_val, size_val);
669 size_val.pol.release ();
670 chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
673 else
675 if (dump_file && (dump_flags & TDF_DETAILS))
676 fprintf (dump_file, " result: cannot compute bounds\n");
677 return 0;
680 if (dump_file && (dump_flags & TDF_DETAILS))
682 fprintf (dump_file, " bound value: ");
683 chkp_print_addr (bound_val);
684 fprintf (dump_file, "\n");
687 chkp_sub_addr_addr (bound_val, ci->addr);
689 if (!chkp_is_constant_addr (bound_val, &sign))
691 if (dump_file && (dump_flags & TDF_DETAILS))
692 fprintf (dump_file, " result: cannot compute result\n");
694 res = 0;
696 else if (sign == 0
697 || (ci->type == CHECK_UPPER_BOUND && sign > 0)
698 || (ci->type == CHECK_LOWER_BOUND && sign < 0))
700 if (dump_file && (dump_flags & TDF_DETAILS))
701 fprintf (dump_file, " result: always pass\n");
703 res = 1;
705 else
707 if (dump_file && (dump_flags & TDF_DETAILS))
708 fprintf (dump_file, " result: always fail\n");
710 res = -1;
713 bound_val.pol.release ();
715 return res;
718 /* Try to compare bounds value and address value
719 used in the check CI. If we can prove that check
720 always pass then remove it. */
721 static void
722 chkp_remove_check_if_pass (struct check_info *ci)
724 int result = 0;
726 if (dump_file && (dump_flags & TDF_DETAILS))
728 fprintf (dump_file, "Trying to remove check: ");
729 print_gimple_stmt (dump_file, ci->stmt, 0, 0);
732 result = chkp_get_check_result (ci, ci->bounds);
734 if (result == 1)
736 gimple_stmt_iterator i = gsi_for_stmt (ci->stmt);
738 if (dump_file && (dump_flags & TDF_DETAILS))
739 fprintf (dump_file, " action: delete check (always pass)\n");
741 gsi_remove (&i, true);
742 unlink_stmt_vdef (ci->stmt);
743 release_defs (ci->stmt);
744 ci->stmt = NULL;
746 else if (result == -1)
748 if (dump_file && (dump_flags & TDF_DETAILS))
749 fprintf (dump_file, " action: keep check (always fail)\n");
750 warning_at (gimple_location (ci->stmt), OPT_Wchkp,
751 "memory access check always fail");
753 else if (result == 0)
755 if (dump_file && (dump_flags & TDF_DETAILS))
756 fprintf (dump_file, " action: keep check (cannot compute result)\n");
760 /* For bounds used in CI check if bounds are produced by
761 intersection and we may use outer bounds instead. If
762 transformation is possible then fix check statement and
763 recompute its info. */
764 static void
765 chkp_use_outer_bounds_if_possible (struct check_info *ci)
767 gimple bnd_def;
768 tree bnd1, bnd2, bnd_res = NULL;
769 int check_res1, check_res2;
771 if (TREE_CODE (ci->bounds) != SSA_NAME)
772 return;
774 bnd_def = SSA_NAME_DEF_STMT (ci->bounds);
775 if (gimple_code (bnd_def) != GIMPLE_CALL
776 || gimple_call_fndecl (bnd_def) != chkp_intersect_fndecl)
777 return;
779 if (dump_file && (dump_flags & TDF_DETAILS))
781 fprintf (dump_file, "Check if bounds intersection is redundant: \n");
782 fprintf (dump_file, " check: ");
783 print_gimple_stmt (dump_file, ci->stmt, 0, 0);
784 fprintf (dump_file, " intersection: ");
785 print_gimple_stmt (dump_file, bnd_def, 0, 0);
786 fprintf (dump_file, "\n");
789 bnd1 = gimple_call_arg (bnd_def, 0);
790 bnd2 = gimple_call_arg (bnd_def, 1);
792 check_res1 = chkp_get_check_result (ci, bnd1);
793 check_res2 = chkp_get_check_result (ci, bnd2);
794 if (check_res1 == 1)
795 bnd_res = bnd2;
796 else if (check_res1 == -1)
797 bnd_res = bnd1;
798 else if (check_res2 == 1)
799 bnd_res = bnd1;
800 else if (check_res2 == -1)
801 bnd_res = bnd2;
803 if (bnd_res)
805 if (dump_file && (dump_flags & TDF_DETAILS))
807 fprintf (dump_file, " action: use ");
808 print_generic_expr (dump_file, bnd2, 0);
809 fprintf (dump_file, " instead of ");
810 print_generic_expr (dump_file, ci->bounds, 0);
811 fprintf (dump_file, "\n");
814 ci->bounds = bnd_res;
815 gimple_call_set_arg (ci->stmt, 1, bnd_res);
816 update_stmt (ci->stmt);
817 chkp_fill_check_info (ci->stmt, ci);
821 /* Try to find checks whose bounds were produced by intersection
822 which does not affect check result. In such check outer bounds
823 are used instead. It allows to remove excess intersections
824 and helps to compare checks. */
825 static void
826 chkp_remove_excess_intersections (void)
828 basic_block bb;
830 if (dump_file && (dump_flags & TDF_DETAILS))
831 fprintf (dump_file, "Searching for redundant bounds intersections...\n");
833 FOR_EACH_BB_FN (bb, cfun)
835 struct bb_checks *bbc = &check_infos[bb->index];
836 unsigned int no;
838 /* Iterate through all found checks in BB. */
839 for (no = 0; no < bbc->checks.length (); no++)
840 if (bbc->checks[no].stmt)
841 chkp_use_outer_bounds_if_possible (&bbc->checks[no]);
845 /* Try to remove all checks which are known to alwyas pass. */
846 static void
847 chkp_remove_constant_checks (void)
849 basic_block bb;
851 if (dump_file && (dump_flags & TDF_DETAILS))
852 fprintf (dump_file, "Searching for redundant checks...\n");
854 FOR_EACH_BB_FN (bb, cfun)
856 struct bb_checks *bbc = &check_infos[bb->index];
857 unsigned int no;
859 /* Iterate through all found checks in BB. */
860 for (no = 0; no < bbc->checks.length (); no++)
861 if (bbc->checks[no].stmt)
862 chkp_remove_check_if_pass (&bbc->checks[no]);
866 /* Return fast version of string function FNCODE. */
867 static tree
868 chkp_get_nobnd_fndecl (enum built_in_function fncode)
870 /* Check if we are allowed to use fast string functions. */
871 if (!flag_chkp_use_fast_string_functions)
872 return NULL_TREE;
874 tree fndecl = NULL_TREE;
876 switch (fncode)
878 case BUILT_IN_MEMCPY_CHKP:
879 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND);
880 break;
882 case BUILT_IN_MEMPCPY_CHKP:
883 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND);
884 break;
886 case BUILT_IN_MEMMOVE_CHKP:
887 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND);
888 break;
890 case BUILT_IN_MEMSET_CHKP:
891 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND);
892 break;
894 case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP:
895 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
896 break;
898 case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP:
899 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
900 break;
902 case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP:
903 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
904 break;
906 case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP:
907 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
908 break;
910 default:
911 break;
914 if (fndecl)
915 fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
917 return fndecl;
921 /* Return no-check version of string function FNCODE. */
922 static tree
923 chkp_get_nochk_fndecl (enum built_in_function fncode)
925 /* Check if we are allowed to use fast string functions. */
926 if (!flag_chkp_use_nochk_string_functions)
927 return NULL_TREE;
929 tree fndecl = NULL_TREE;
931 switch (fncode)
933 case BUILT_IN_MEMCPY_CHKP:
934 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK);
935 break;
937 case BUILT_IN_MEMPCPY_CHKP:
938 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK);
939 break;
941 case BUILT_IN_MEMMOVE_CHKP:
942 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK);
943 break;
945 case BUILT_IN_MEMSET_CHKP:
946 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK);
947 break;
949 case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP:
950 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
951 break;
953 case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP:
954 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
955 break;
957 case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP:
958 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
959 break;
961 case BUILT_IN_CHKP_MEMSET_NOBND_CHKP:
962 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
963 break;
965 default:
966 break;
969 if (fndecl)
970 fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
972 return fndecl;
975 /* Find memcpy, mempcpy, memmove and memset calls, perform
976 checks before call and then call no_chk version of
977 functions. We do it on O2 to enable inlining of these
978 functions during expand.
980 Also try to find memcpy, mempcpy, memmove and memset calls
981 which are known to not write pointers to memory and use
982 faster function versions for them. */
983 static void
984 chkp_optimize_string_function_calls (void)
986 basic_block bb;
988 if (dump_file && (dump_flags & TDF_DETAILS))
989 fprintf (dump_file, "Searching for replaceable string function calls...\n");
991 FOR_EACH_BB_FN (bb, cfun)
993 gimple_stmt_iterator i;
995 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
997 gimple stmt = gsi_stmt (i);
998 tree fndecl;
1000 if (gimple_code (stmt) != GIMPLE_CALL
1001 || !gimple_call_with_bounds_p (stmt))
1002 continue;
1004 fndecl = gimple_call_fndecl (stmt);
1006 if (!fndecl || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
1007 continue;
1009 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMCPY_CHKP
1010 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHKP
1011 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMMOVE_CHKP
1012 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP)
1014 tree dst = gimple_call_arg (stmt, 0);
1015 tree dst_bnd = gimple_call_arg (stmt, 1);
1016 bool is_memset = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP;
1017 tree size = gimple_call_arg (stmt, is_memset ? 3 : 4);
1018 tree fndecl_nochk;
1019 gimple_stmt_iterator j;
1020 basic_block check_bb;
1021 address_t size_val;
1022 int sign;
1023 bool known;
1025 /* We may replace call with corresponding __chkp_*_nobnd
1026 call in case destination pointer base type is not
1027 void or pointer. */
1028 if (POINTER_TYPE_P (TREE_TYPE (dst))
1029 && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst)))
1030 && !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst))))
1032 tree fndecl_nobnd
1033 = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl));
1035 if (fndecl_nobnd)
1036 fndecl = fndecl_nobnd;
1039 fndecl_nochk = chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl));
1041 if (fndecl_nochk)
1042 fndecl = fndecl_nochk;
1044 if (fndecl != gimple_call_fndecl (stmt))
1046 if (dump_file && (dump_flags & TDF_DETAILS))
1048 fprintf (dump_file, "Replacing call: ");
1049 print_gimple_stmt (dump_file, stmt, 0,
1050 TDF_VOPS|TDF_MEMSYMS);
1053 gimple_call_set_fndecl (stmt, fndecl);
1055 if (dump_file && (dump_flags & TDF_DETAILS))
1057 fprintf (dump_file, "With a new call: ");
1058 print_gimple_stmt (dump_file, stmt, 0,
1059 TDF_VOPS|TDF_MEMSYMS);
1063 /* If there is no nochk version of function then
1064 do nothing. Otherwise insert checks before
1065 the call. */
1066 if (!fndecl_nochk)
1067 continue;
1069 /* If size passed to call is known and > 0
1070 then we may insert checks unconditionally. */
1071 size_val.pol.create (0);
1072 chkp_collect_value (size, size_val);
1073 known = chkp_is_constant_addr (size_val, &sign);
1074 size_val.pol.release ();
1076 /* If we are not sure size is not zero then we have
1077 to perform runtime check for size and perform
1078 checks only when size is not zero. */
1079 if (!known)
1081 gimple check = gimple_build_cond (NE_EXPR,
1082 size,
1083 size_zero_node,
1084 NULL_TREE,
1085 NULL_TREE);
1087 /* Split block before string function call. */
1088 gsi_prev (&i);
1089 check_bb = insert_cond_bb (bb, gsi_stmt (i), check);
1091 /* Set position for checks. */
1092 j = gsi_last_bb (check_bb);
1094 /* The block was splitted and therefore we
1095 need to set iterator to its end. */
1096 i = gsi_last_bb (bb);
1098 /* If size is known to be zero then no checks
1099 should be performed. */
1100 else if (!sign)
1101 continue;
1102 else
1103 j = i;
1105 size = size_binop (MINUS_EXPR, size, size_one_node);
1106 if (!is_memset)
1108 tree src = gimple_call_arg (stmt, 2);
1109 tree src_bnd = gimple_call_arg (stmt, 3);
1111 chkp_check_mem_access (src, fold_build_pointer_plus (src, size),
1112 src_bnd, j, gimple_location (stmt),
1113 integer_zero_node);
1116 chkp_check_mem_access (dst, fold_build_pointer_plus (dst, size),
1117 dst_bnd, j, gimple_location (stmt),
1118 integer_one_node);
1125 /* Intrumentation pass inserts most of bounds creation code
1126 in the header of the function. We want to move bounds
1127 creation closer to bounds usage to reduce bounds lifetime.
1128 We also try to avoid bounds creation code on paths where
1129 bounds are not used. */
1130 static void
1131 chkp_reduce_bounds_lifetime (void)
1133 basic_block bb = FALLTHRU_EDGE (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest;
1134 gimple_stmt_iterator i;
1136 for (i = gsi_start_bb (bb); !gsi_end_p (i); )
1138 gimple dom_use, use_stmt, stmt = gsi_stmt (i);
1139 basic_block dom_bb;
1140 ssa_op_iter iter;
1141 imm_use_iterator use_iter;
1142 use_operand_p use_p;
1143 tree op;
1144 bool want_move = false;
1145 bool deps = false;
1147 if (gimple_code (stmt) == GIMPLE_CALL
1148 && gimple_call_fndecl (stmt) == chkp_bndmk_fndecl)
1149 want_move = true;
1151 if (gimple_code (stmt) == GIMPLE_ASSIGN
1152 && POINTER_BOUNDS_P (gimple_assign_lhs (stmt))
1153 && gimple_assign_rhs_code (stmt) == VAR_DECL)
1154 want_move = true;
1156 if (!want_move)
1158 gsi_next (&i);
1159 continue;
1162 /* Check we do not increase other values lifetime. */
1163 FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
1165 op = USE_FROM_PTR (use_p);
1167 if (TREE_CODE (op) == SSA_NAME
1168 && gimple_code (SSA_NAME_DEF_STMT (op)) != GIMPLE_NOP)
1170 deps = true;
1171 break;
1175 if (deps)
1177 gsi_next (&i);
1178 continue;
1181 /* Check all usages of bounds. */
1182 if (gimple_code (stmt) == GIMPLE_CALL)
1183 op = gimple_call_lhs (stmt);
1184 else
1186 gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
1187 op = gimple_assign_lhs (stmt);
1190 dom_use = NULL;
1191 dom_bb = NULL;
1193 FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, op)
1195 if (is_gimple_debug (use_stmt))
1196 continue;
1198 if (dom_bb &&
1199 dominated_by_p (CDI_DOMINATORS,
1200 dom_bb, gimple_bb (use_stmt)))
1202 dom_use = use_stmt;
1203 dom_bb = NULL;
1205 else if (dom_bb)
1206 dom_bb = nearest_common_dominator (CDI_DOMINATORS, dom_bb,
1207 gimple_bb (use_stmt));
1208 else if (!dom_use)
1209 dom_use = use_stmt;
1210 else if (stmt_dominates_stmt_p (use_stmt, dom_use))
1211 dom_use = use_stmt;
1212 else if (!stmt_dominates_stmt_p (dom_use, use_stmt)
1213 /* If dom_use and use_stmt are PHI nodes in one BB
1214 then it is OK to keep any of them as dom_use.
1215 stmt_dominates_stmt_p returns 0 for such
1216 combination, so check it here manually. */
1217 && (gimple_code (dom_use) != GIMPLE_PHI
1218 || gimple_code (use_stmt) != GIMPLE_PHI
1219 || gimple_bb (use_stmt) != gimple_bb (dom_use))
1222 dom_bb = nearest_common_dominator (CDI_DOMINATORS,
1223 gimple_bb (use_stmt),
1224 gimple_bb (dom_use));
1225 dom_use = NULL;
1229 /* In case there is a single use, just move bounds
1230 creation to the use. */
1231 if (dom_use || dom_bb)
1233 if (dump_file && (dump_flags & TDF_DETAILS))
1235 fprintf (dump_file, "Moving creation of ");
1236 print_generic_expr (dump_file, op, 0);
1237 fprintf (dump_file, " down to its use.\n");
1240 if (dom_use && gimple_code (dom_use) == GIMPLE_PHI)
1242 dom_bb = get_immediate_dominator (CDI_DOMINATORS,
1243 gimple_bb (dom_use));
1244 dom_use = NULL;
1247 if (dom_bb == bb
1248 || (dom_use && gimple_bb (dom_use) == bb))
1250 if (dump_file && (dump_flags & TDF_DETAILS))
1251 fprintf (dump_file, "Cannot move statement bacause there is no "
1252 "suitable dominator block other than entry block.\n");
1254 gsi_next (&i);
1256 else
1258 if (dom_bb)
1260 gimple_stmt_iterator last = gsi_last_bb (dom_bb);
1261 if (!gsi_end_p (last) && stmt_ends_bb_p (gsi_stmt (last)))
1262 gsi_move_before (&i, &last);
1263 else
1264 gsi_move_after (&i, &last);
1266 else
1268 gimple_stmt_iterator gsi = gsi_for_stmt (dom_use);
1269 gsi_move_before (&i, &gsi);
1272 update_stmt (stmt);
1275 else
1276 gsi_next (&i);
1280 /* Initilize checker optimization pass. */
1281 static void
1282 chkp_opt_init (void)
1284 check_infos.create (0);
1286 calculate_dominance_info (CDI_DOMINATORS);
1287 calculate_dominance_info (CDI_POST_DOMINATORS);
1289 /* With LTO constant bounds vars may be not initialized by now.
1290 Get constant bounds vars to handle their assignments during
1291 optimizations. */
1292 chkp_get_zero_bounds_var ();
1293 chkp_get_none_bounds_var ();
1296 /* Finalise checker optimization pass. */
1297 static void
1298 chkp_opt_fini (void)
1300 chkp_fix_cfg ();
1303 /* Checker optimization pass function. */
1304 static unsigned int
1305 chkp_opt_execute (void)
1307 chkp_opt_init();
1309 /* This optimization may introduce new checks
1310 and thus we put it before checks search. */
1311 chkp_optimize_string_function_calls ();
1313 chkp_gather_checks_info ();
1315 chkp_remove_excess_intersections ();
1317 chkp_remove_constant_checks ();
1319 chkp_reduce_bounds_lifetime ();
1321 chkp_release_check_info ();
1323 chkp_opt_fini ();
1325 return 0;
1328 /* Pass gate. */
1329 static bool
1330 chkp_opt_gate (void)
1332 return chkp_function_instrumented_p (cfun->decl)
1333 && (flag_chkp_optimize > 0
1334 || (flag_chkp_optimize == -1 && optimize > 0));
1337 namespace {
1339 const pass_data pass_data_chkp_opt =
1341 GIMPLE_PASS, /* type */
1342 "chkpopt", /* name */
1343 OPTGROUP_NONE, /* optinfo_flags */
1344 TV_NONE, /* tv_id */
1345 PROP_ssa | PROP_cfg, /* properties_required */
1346 0, /* properties_provided */
1347 0, /* properties_destroyed */
1348 0, /* todo_flags_start */
1349 TODO_verify_il
1350 | TODO_update_ssa /* todo_flags_finish */
1353 class pass_chkp_opt : public gimple_opt_pass
1355 public:
1356 pass_chkp_opt (gcc::context *ctxt)
1357 : gimple_opt_pass (pass_data_chkp_opt, ctxt)
1360 /* opt_pass methods: */
1361 virtual opt_pass * clone ()
1363 return new pass_chkp_opt (m_ctxt);
1366 virtual bool gate (function *)
1368 return chkp_opt_gate ();
1371 virtual unsigned int execute (function *)
1373 return chkp_opt_execute ();
1376 }; // class pass_chkp_opt
1378 } // anon namespace
1380 gimple_opt_pass *
1381 make_pass_chkp_opt (gcc::context *ctxt)
1383 return new pass_chkp_opt (ctxt);