Update my email address.
[official-gcc.git] / gcc / tree-chkp-opt.c
blob66c99bde38a7b36b35b977086803b8cdd37525f3
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 "alias.h"
25 #include "backend.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "rtl.h"
29 #include "ssa.h"
30 #include "options.h"
31 #include "fold-const.h"
32 #include "target.h"
33 #include "tree-cfg.h"
34 #include "tree-pass.h"
35 #include "cfgloop.h"
36 #include "tree-ssa-address.h"
37 #include "tree-ssa.h"
38 #include "tree-ssa-loop-niter.h"
39 #include "gimple-pretty-print.h"
40 #include "gimple-iterator.h"
41 #include "gimplify.h"
42 #include "gimplify-me.h"
43 #include "flags.h"
44 #include "insn-config.h"
45 #include "expmed.h"
46 #include "dojump.h"
47 #include "explow.h"
48 #include "calls.h"
49 #include "emit-rtl.h"
50 #include "varasm.h"
51 #include "stmt.h"
52 #include "expr.h"
53 #include "tree-chkp.h"
54 #include "ipa-chkp.h"
55 #include "diagnostic.h"
57 enum check_type
59 CHECK_LOWER_BOUND,
60 CHECK_UPPER_BOUND
63 struct pol_item
65 tree cst;
66 tree var;
69 struct address_t
71 vec<struct pol_item> pol;
74 /* Structure to hold check informtation. */
75 struct check_info
77 /* Type of the check. */
78 check_type type;
79 /* Address used for the check. */
80 address_t addr;
81 /* Bounds used for the check. */
82 tree bounds;
83 /* Check statement. Can be NULL for removed checks. */
84 gimple stmt;
87 /* Structure to hold checks information for BB. */
88 struct bb_checks
90 vec<struct check_info, va_heap, vl_ptr> checks;
93 static void chkp_collect_value (tree ssa_name, address_t &res);
95 #define chkp_bndmk_fndecl \
96 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
97 #define chkp_intersect_fndecl \
98 (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
99 #define chkp_checkl_fndecl \
100 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
101 #define chkp_checku_fndecl \
102 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
104 static vec<struct bb_checks, va_heap, vl_ptr> check_infos = vNULL;
106 /* Comparator for pol_item structures I1 and I2 to be used
107 to find items with equal var. Also used for polynomial
108 sorting. */
109 static int
110 chkp_pol_item_compare (const void *i1, const void *i2)
112 const struct pol_item *p1 = (const struct pol_item *)i1;
113 const struct pol_item *p2 = (const struct pol_item *)i2;
115 if (p1->var == p2->var)
116 return 0;
117 else if (p1->var > p2->var)
118 return 1;
119 else
120 return -1;
123 /* Find polynomial item in ADDR with var equal to VAR
124 and return its index. Return -1 if item was not
125 found. */
126 static int
127 chkp_pol_find (address_t &addr, tree var)
129 int left = 0;
130 int right = addr.pol.length () - 1;
131 int n;
133 while (right >= left)
135 n = (left + right) / 2;
137 if (addr.pol[n].var == var
138 || (var && addr.pol[n].var
139 && TREE_CODE (var) == ADDR_EXPR
140 && TREE_CODE (addr.pol[n].var) == ADDR_EXPR
141 && TREE_OPERAND (var, 0) == TREE_OPERAND (addr.pol[n].var, 0)))
142 return n;
143 else if (addr.pol[n].var > var)
144 right = n - 1;
145 else
146 left = n + 1;
149 return -1;
152 /* Return constant CST extended to size type. */
153 static tree
154 chkp_extend_const (tree cst)
156 if (TYPE_PRECISION (TREE_TYPE (cst)) < TYPE_PRECISION (size_type_node))
157 return build_int_cst_type (size_type_node, tree_to_shwi (cst));
159 return cst;
162 /* Add polynomial item CST * VAR to ADDR. */
163 static void
164 chkp_add_addr_item (address_t &addr, tree cst, tree var)
166 int n = chkp_pol_find (addr, var);
168 cst = chkp_extend_const (cst);
170 if (n < 0)
172 struct pol_item item;
173 item.cst = cst;
174 item.var = var;
176 addr.pol.safe_push (item);
177 addr.pol.qsort (&chkp_pol_item_compare);
179 else
181 addr.pol[n].cst = fold_build2 (PLUS_EXPR, TREE_TYPE (addr.pol[n].cst),
182 addr.pol[n].cst, cst);
183 if (TREE_CODE (addr.pol[n].cst) == INTEGER_CST
184 && integer_zerop (addr.pol[n].cst))
185 addr.pol.ordered_remove (n);
189 /* Subtract polynomial item CST * VAR from ADDR. */
190 static void
191 chkp_sub_addr_item (address_t &addr, tree cst, tree var)
193 int n = chkp_pol_find (addr, var);
195 cst = chkp_extend_const (cst);
197 if (n < 0)
199 struct pol_item item;
200 item.cst = fold_build2 (MINUS_EXPR, TREE_TYPE (cst),
201 integer_zero_node, cst);
202 item.var = var;
204 addr.pol.safe_push (item);
205 addr.pol.qsort (&chkp_pol_item_compare);
207 else
209 addr.pol[n].cst = fold_build2 (MINUS_EXPR, TREE_TYPE (addr.pol[n].cst),
210 addr.pol[n].cst, cst);
211 if (TREE_CODE (addr.pol[n].cst) == INTEGER_CST
212 && integer_zerop (addr.pol[n].cst))
213 addr.pol.ordered_remove (n);
217 /* Add address DELTA to ADDR. */
218 static void
219 chkp_add_addr_addr (address_t &addr, address_t &delta)
221 unsigned int i;
222 for (i = 0; i < delta.pol.length (); i++)
223 chkp_add_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
226 /* Subtract address DELTA from ADDR. */
227 static void
228 chkp_sub_addr_addr (address_t &addr, address_t &delta)
230 unsigned int i;
231 for (i = 0; i < delta.pol.length (); i++)
232 chkp_sub_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
235 /* Mutiply address ADDR by integer constant MULT. */
236 static void
237 chkp_mult_addr (address_t &addr, tree mult)
239 unsigned int i;
240 for (i = 0; i < addr.pol.length (); i++)
241 addr.pol[i].cst = fold_build2 (MULT_EXPR, TREE_TYPE (addr.pol[i].cst),
242 addr.pol[i].cst, mult);
245 /* Return 1 if we may prove ADDR has a constant value with
246 determined sign, which is put into *SIGN. Otherwise
247 return 0. */
248 static bool
249 chkp_is_constant_addr (const address_t &addr, int *sign)
251 *sign = 0;
253 if (addr.pol.length () == 0)
254 return true;
255 else if (addr.pol.length () > 1)
256 return false;
257 else if (addr.pol[0].var)
258 return false;
259 else if (integer_zerop (addr.pol[0].cst))
260 *sign = 0;
261 else if (tree_int_cst_sign_bit (addr.pol[0].cst))
262 *sign = -1;
263 else
264 *sign = 1;
266 return true;
269 /* Dump ADDR into dump_file. */
270 static void
271 chkp_print_addr (const address_t &addr)
273 unsigned int n = 0;
274 for (n = 0; n < addr.pol.length (); n++)
276 if (n > 0)
277 fprintf (dump_file, " + ");
279 if (addr.pol[n].var == NULL_TREE)
280 print_generic_expr (dump_file, addr.pol[n].cst, 0);
281 else
283 if (TREE_CODE (addr.pol[n].cst) != INTEGER_CST
284 || !integer_onep (addr.pol[n].cst))
286 print_generic_expr (dump_file, addr.pol[n].cst, 0);
287 fprintf (dump_file, " * ");
289 print_generic_expr (dump_file, addr.pol[n].var, 0);
294 /* Compute value of PTR and put it into address RES.
295 PTR has to be ADDR_EXPR. */
296 static void
297 chkp_collect_addr_value (tree ptr, address_t &res)
299 tree obj = TREE_OPERAND (ptr, 0);
300 address_t addr;
302 switch (TREE_CODE (obj))
304 case INDIRECT_REF:
305 chkp_collect_value (TREE_OPERAND (obj, 0), res);
306 break;
308 case MEM_REF:
309 chkp_collect_value (TREE_OPERAND (obj, 0), res);
310 addr.pol.create (0);
311 chkp_collect_value (TREE_OPERAND (obj, 1), addr);
312 chkp_add_addr_addr (res, addr);
313 addr.pol.release ();
314 break;
316 case ARRAY_REF:
317 chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj, 0)), res);
318 addr.pol.create (0);
319 chkp_collect_value (TREE_OPERAND (obj, 1), addr);
320 chkp_mult_addr (addr, array_ref_element_size (obj));
321 chkp_add_addr_addr (res, addr);
322 addr.pol.release ();
323 break;
325 case COMPONENT_REF:
327 tree str = TREE_OPERAND (obj, 0);
328 tree field = TREE_OPERAND (obj, 1);
329 chkp_collect_value (build_fold_addr_expr (str), res);
330 addr.pol.create (0);
331 chkp_collect_value (component_ref_field_offset (obj), addr);
332 chkp_add_addr_addr (res, addr);
333 addr.pol.release ();
334 if (DECL_FIELD_BIT_OFFSET (field))
336 addr.pol.create (0);
337 chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR, size_type_node,
338 DECL_FIELD_BIT_OFFSET (field),
339 size_int (BITS_PER_UNIT)),
340 addr);
341 chkp_add_addr_addr (res, addr);
342 addr.pol.release ();
345 break;
347 default:
348 chkp_add_addr_item (res, integer_one_node, ptr);
349 break;
353 /* Compute value of PTR and put it into address RES. */
354 static void
355 chkp_collect_value (tree ptr, address_t &res)
357 gimple def_stmt;
358 enum gimple_code code;
359 enum tree_code rhs_code;
360 address_t addr;
361 tree rhs1;
363 if (TREE_CODE (ptr) == INTEGER_CST)
365 chkp_add_addr_item (res, ptr, NULL);
366 return;
368 else if (TREE_CODE (ptr) == ADDR_EXPR)
370 chkp_collect_addr_value (ptr, res);
371 return;
373 else if (TREE_CODE (ptr) != SSA_NAME)
375 chkp_add_addr_item (res, integer_one_node, ptr);
376 return;
379 /* Now we handle the case when polynomial is computed
380 for SSA NAME. */
381 def_stmt = SSA_NAME_DEF_STMT (ptr);
382 code = gimple_code (def_stmt);
384 /* Currently we do not walk through statements other
385 than assignment. */
386 if (code != GIMPLE_ASSIGN)
388 chkp_add_addr_item (res, integer_one_node, ptr);
389 return;
392 rhs_code = gimple_assign_rhs_code (def_stmt);
393 rhs1 = gimple_assign_rhs1 (def_stmt);
395 switch (rhs_code)
397 case SSA_NAME:
398 case INTEGER_CST:
399 case ADDR_EXPR:
400 chkp_collect_value (rhs1, res);
401 break;
403 case PLUS_EXPR:
404 case POINTER_PLUS_EXPR:
405 chkp_collect_value (rhs1, res);
406 addr.pol.create (0);
407 chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
408 chkp_add_addr_addr (res, addr);
409 addr.pol.release ();
410 break;
412 case MINUS_EXPR:
413 chkp_collect_value (rhs1, res);
414 addr.pol.create (0);
415 chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
416 chkp_sub_addr_addr (res, addr);
417 addr.pol.release ();
418 break;
420 case MULT_EXPR:
421 if (TREE_CODE (rhs1) == SSA_NAME
422 && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == INTEGER_CST)
424 chkp_collect_value (rhs1, res);
425 chkp_mult_addr (res, gimple_assign_rhs2 (def_stmt));
427 else if (TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME
428 && TREE_CODE (rhs1) == INTEGER_CST)
430 chkp_collect_value (gimple_assign_rhs2 (def_stmt), res);
431 chkp_mult_addr (res, rhs1);
433 else
434 chkp_add_addr_item (res, integer_one_node, ptr);
435 break;
437 default:
438 chkp_add_addr_item (res, integer_one_node, ptr);
439 break;
443 /* Fill check_info structure *CI with information about
444 check STMT. */
445 static void
446 chkp_fill_check_info (gimple stmt, struct check_info *ci)
448 ci->addr.pol.create (0);
449 ci->bounds = gimple_call_arg (stmt, 1);
450 chkp_collect_value (gimple_call_arg (stmt, 0), ci->addr);
451 ci->type = (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
452 ? CHECK_LOWER_BOUND
453 : CHECK_UPPER_BOUND);
454 ci->stmt = stmt;
457 /* Release structures holding check information
458 for current function. */
459 static void
460 chkp_release_check_info (void)
462 unsigned int n, m;
464 if (check_infos.exists ())
466 for (n = 0; n < check_infos.length (); n++)
468 for (m = 0; m < check_infos[n].checks.length (); m++)
469 if (check_infos[n].checks[m].addr.pol.exists ())
470 check_infos[n].checks[m].addr.pol.release ();
471 check_infos[n].checks.release ();
473 check_infos.release ();
477 /* Create structures to hold check information
478 for current function. */
479 static void
480 chkp_init_check_info (void)
482 struct bb_checks empty_bbc;
483 int n;
485 empty_bbc.checks = vNULL;
487 chkp_release_check_info ();
489 check_infos.create (last_basic_block_for_fn (cfun));
490 for (n = 0; n < last_basic_block_for_fn (cfun); n++)
492 check_infos.safe_push (empty_bbc);
493 check_infos.last ().checks.create (0);
497 /* Find all checks in current function and store info about them
498 in check_infos. */
499 static void
500 chkp_gather_checks_info (void)
502 basic_block bb;
503 gimple_stmt_iterator i;
505 if (dump_file && (dump_flags & TDF_DETAILS))
506 fprintf (dump_file, "Gathering information about checks...\n");
508 chkp_init_check_info ();
510 FOR_EACH_BB_FN (bb, cfun)
512 struct bb_checks *bbc = &check_infos[bb->index];
514 if (dump_file && (dump_flags & TDF_DETAILS))
515 fprintf (dump_file, "Searching checks in BB%d...\n", bb->index);
517 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
519 gimple stmt = gsi_stmt (i);
521 if (gimple_code (stmt) != GIMPLE_CALL)
522 continue;
524 if (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
525 || gimple_call_fndecl (stmt) == chkp_checku_fndecl)
527 struct check_info ci;
529 chkp_fill_check_info (stmt, &ci);
530 bbc->checks.safe_push (ci);
532 if (dump_file && (dump_flags & TDF_DETAILS))
534 fprintf (dump_file, "Adding check information:\n");
535 fprintf (dump_file, " bounds: ");
536 print_generic_expr (dump_file, ci.bounds, 0);
537 fprintf (dump_file, "\n address: ");
538 chkp_print_addr (ci.addr);
539 fprintf (dump_file, "\n check: ");
540 print_gimple_stmt (dump_file, stmt, 0, 0);
547 /* Return 1 if check CI against BOUNDS always pass,
548 -1 if check CI against BOUNDS always fails and
549 0 if we cannot compute check result. */
550 static int
551 chkp_get_check_result (struct check_info *ci, tree bounds)
553 gimple bnd_def;
554 address_t bound_val;
555 int sign, res = 0;
557 if (dump_file && (dump_flags & TDF_DETAILS))
559 fprintf (dump_file, "Trying to compute result of the check\n");
560 fprintf (dump_file, " check: ");
561 print_gimple_stmt (dump_file, ci->stmt, 0, 0);
562 fprintf (dump_file, " address: ");
563 chkp_print_addr (ci->addr);
564 fprintf (dump_file, "\n bounds: ");
565 print_generic_expr (dump_file, bounds, 0);
566 fprintf (dump_file, "\n");
569 if (TREE_CODE (bounds) != SSA_NAME)
571 if (dump_file && (dump_flags & TDF_DETAILS))
572 fprintf (dump_file, " result: bounds tree code is not ssa_name\n");
573 return 0;
576 bnd_def = SSA_NAME_DEF_STMT (bounds);
577 /* Currently we handle cases when bounds are result of bndmk
578 or loaded static bounds var. */
579 if (gimple_code (bnd_def) == GIMPLE_CALL
580 && gimple_call_fndecl (bnd_def) == chkp_bndmk_fndecl)
582 bound_val.pol.create (0);
583 chkp_collect_value (gimple_call_arg (bnd_def, 0), bound_val);
584 if (ci->type == CHECK_UPPER_BOUND)
586 address_t size_val;
587 size_val.pol.create (0);
588 chkp_collect_value (gimple_call_arg (bnd_def, 1), size_val);
589 chkp_add_addr_addr (bound_val, size_val);
590 size_val.pol.release ();
591 chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
594 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
595 && gimple_assign_rhs1 (bnd_def) == chkp_get_zero_bounds_var ())
597 if (dump_file && (dump_flags & TDF_DETAILS))
598 fprintf (dump_file, " result: always pass with zero bounds\n");
599 return 1;
601 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
602 && gimple_assign_rhs1 (bnd_def) == chkp_get_none_bounds_var ())
604 if (dump_file && (dump_flags & TDF_DETAILS))
605 fprintf (dump_file, " result: always fails with none bounds\n");
606 return -1;
608 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
609 && TREE_CODE (gimple_assign_rhs1 (bnd_def)) == VAR_DECL)
611 tree bnd_var = gimple_assign_rhs1 (bnd_def);
612 tree var;
613 tree size;
615 if (!DECL_INITIAL (bnd_var)
616 || DECL_INITIAL (bnd_var) == error_mark_node)
618 if (dump_file && (dump_flags & TDF_DETAILS))
619 fprintf (dump_file, " result: cannot compute bounds\n");
620 return 0;
623 gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var)) == ADDR_EXPR);
624 var = TREE_OPERAND (DECL_INITIAL (bnd_var), 0);
626 bound_val.pol.create (0);
627 chkp_collect_value (DECL_INITIAL (bnd_var), bound_val);
628 if (ci->type == CHECK_UPPER_BOUND)
630 if (TREE_CODE (var) == VAR_DECL)
632 if (DECL_SIZE (var)
633 && !chkp_variable_size_type (TREE_TYPE (var)))
634 size = DECL_SIZE_UNIT (var);
635 else
637 if (dump_file && (dump_flags & TDF_DETAILS))
638 fprintf (dump_file, " result: cannot compute bounds\n");
639 return 0;
642 else
644 gcc_assert (TREE_CODE (var) == STRING_CST);
645 size = build_int_cst (size_type_node,
646 TREE_STRING_LENGTH (var));
649 address_t size_val;
650 size_val.pol.create (0);
651 chkp_collect_value (size, size_val);
652 chkp_add_addr_addr (bound_val, size_val);
653 size_val.pol.release ();
654 chkp_add_addr_item (bound_val, integer_minus_one_node, NULL);
657 else
659 if (dump_file && (dump_flags & TDF_DETAILS))
660 fprintf (dump_file, " result: cannot compute bounds\n");
661 return 0;
664 if (dump_file && (dump_flags & TDF_DETAILS))
666 fprintf (dump_file, " bound value: ");
667 chkp_print_addr (bound_val);
668 fprintf (dump_file, "\n");
671 chkp_sub_addr_addr (bound_val, ci->addr);
673 if (!chkp_is_constant_addr (bound_val, &sign))
675 if (dump_file && (dump_flags & TDF_DETAILS))
676 fprintf (dump_file, " result: cannot compute result\n");
678 res = 0;
680 else if (sign == 0
681 || (ci->type == CHECK_UPPER_BOUND && sign > 0)
682 || (ci->type == CHECK_LOWER_BOUND && sign < 0))
684 if (dump_file && (dump_flags & TDF_DETAILS))
685 fprintf (dump_file, " result: always pass\n");
687 res = 1;
689 else
691 if (dump_file && (dump_flags & TDF_DETAILS))
692 fprintf (dump_file, " result: always fail\n");
694 res = -1;
697 bound_val.pol.release ();
699 return res;
702 /* Try to compare bounds value and address value
703 used in the check CI. If we can prove that check
704 always pass then remove it. */
705 static void
706 chkp_remove_check_if_pass (struct check_info *ci)
708 int result = 0;
710 if (dump_file && (dump_flags & TDF_DETAILS))
712 fprintf (dump_file, "Trying to remove check: ");
713 print_gimple_stmt (dump_file, ci->stmt, 0, 0);
716 result = chkp_get_check_result (ci, ci->bounds);
718 if (result == 1)
720 gimple_stmt_iterator i = gsi_for_stmt (ci->stmt);
722 if (dump_file && (dump_flags & TDF_DETAILS))
723 fprintf (dump_file, " action: delete check (always pass)\n");
725 gsi_remove (&i, true);
726 unlink_stmt_vdef (ci->stmt);
727 release_defs (ci->stmt);
728 ci->stmt = NULL;
730 else if (result == -1)
732 if (dump_file && (dump_flags & TDF_DETAILS))
733 fprintf (dump_file, " action: keep check (always fail)\n");
734 warning_at (gimple_location (ci->stmt), OPT_Wchkp,
735 "memory access check always fail");
737 else if (result == 0)
739 if (dump_file && (dump_flags & TDF_DETAILS))
740 fprintf (dump_file, " action: keep check (cannot compute result)\n");
744 /* For bounds used in CI check if bounds are produced by
745 intersection and we may use outer bounds instead. If
746 transformation is possible then fix check statement and
747 recompute its info. */
748 static void
749 chkp_use_outer_bounds_if_possible (struct check_info *ci)
751 gimple bnd_def;
752 tree bnd1, bnd2, bnd_res = NULL;
753 int check_res1, check_res2;
755 if (TREE_CODE (ci->bounds) != SSA_NAME)
756 return;
758 bnd_def = SSA_NAME_DEF_STMT (ci->bounds);
759 if (gimple_code (bnd_def) != GIMPLE_CALL
760 || gimple_call_fndecl (bnd_def) != chkp_intersect_fndecl)
761 return;
763 if (dump_file && (dump_flags & TDF_DETAILS))
765 fprintf (dump_file, "Check if bounds intersection is redundant: \n");
766 fprintf (dump_file, " check: ");
767 print_gimple_stmt (dump_file, ci->stmt, 0, 0);
768 fprintf (dump_file, " intersection: ");
769 print_gimple_stmt (dump_file, bnd_def, 0, 0);
770 fprintf (dump_file, "\n");
773 bnd1 = gimple_call_arg (bnd_def, 0);
774 bnd2 = gimple_call_arg (bnd_def, 1);
776 check_res1 = chkp_get_check_result (ci, bnd1);
777 check_res2 = chkp_get_check_result (ci, bnd2);
778 if (check_res1 == 1)
779 bnd_res = bnd2;
780 else if (check_res1 == -1)
781 bnd_res = bnd1;
782 else if (check_res2 == 1)
783 bnd_res = bnd1;
784 else if (check_res2 == -1)
785 bnd_res = bnd2;
787 if (bnd_res)
789 if (dump_file && (dump_flags & TDF_DETAILS))
791 fprintf (dump_file, " action: use ");
792 print_generic_expr (dump_file, bnd2, 0);
793 fprintf (dump_file, " instead of ");
794 print_generic_expr (dump_file, ci->bounds, 0);
795 fprintf (dump_file, "\n");
798 ci->bounds = bnd_res;
799 gimple_call_set_arg (ci->stmt, 1, bnd_res);
800 update_stmt (ci->stmt);
801 chkp_fill_check_info (ci->stmt, ci);
805 /* Try to find checks whose bounds were produced by intersection
806 which does not affect check result. In such check outer bounds
807 are used instead. It allows to remove excess intersections
808 and helps to compare checks. */
809 static void
810 chkp_remove_excess_intersections (void)
812 basic_block bb;
814 if (dump_file && (dump_flags & TDF_DETAILS))
815 fprintf (dump_file, "Searching for redundant bounds intersections...\n");
817 FOR_EACH_BB_FN (bb, cfun)
819 struct bb_checks *bbc = &check_infos[bb->index];
820 unsigned int no;
822 /* Iterate through all found checks in BB. */
823 for (no = 0; no < bbc->checks.length (); no++)
824 if (bbc->checks[no].stmt)
825 chkp_use_outer_bounds_if_possible (&bbc->checks[no]);
829 /* Try to remove all checks which are known to alwyas pass. */
830 static void
831 chkp_remove_constant_checks (void)
833 basic_block bb;
835 if (dump_file && (dump_flags & TDF_DETAILS))
836 fprintf (dump_file, "Searching for redundant checks...\n");
838 FOR_EACH_BB_FN (bb, cfun)
840 struct bb_checks *bbc = &check_infos[bb->index];
841 unsigned int no;
843 /* Iterate through all found checks in BB. */
844 for (no = 0; no < bbc->checks.length (); no++)
845 if (bbc->checks[no].stmt)
846 chkp_remove_check_if_pass (&bbc->checks[no]);
850 /* Return fast version of string function FNCODE. */
851 static tree
852 chkp_get_nobnd_fndecl (enum built_in_function fncode)
854 /* Check if we are allowed to use fast string functions. */
855 if (!flag_chkp_use_fast_string_functions)
856 return NULL_TREE;
858 tree fndecl = NULL_TREE;
860 switch (fncode)
862 case BUILT_IN_MEMCPY_CHKP:
863 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND);
864 break;
866 case BUILT_IN_MEMPCPY_CHKP:
867 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND);
868 break;
870 case BUILT_IN_MEMMOVE_CHKP:
871 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND);
872 break;
874 case BUILT_IN_MEMSET_CHKP:
875 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND);
876 break;
878 case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP:
879 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
880 break;
882 case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP:
883 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
884 break;
886 case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP:
887 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
888 break;
890 case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP:
891 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
892 break;
894 default:
895 break;
898 if (fndecl)
899 fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
901 return fndecl;
905 /* Return no-check version of string function FNCODE. */
906 static tree
907 chkp_get_nochk_fndecl (enum built_in_function fncode)
909 /* Check if we are allowed to use fast string functions. */
910 if (!flag_chkp_use_nochk_string_functions)
911 return NULL_TREE;
913 tree fndecl = NULL_TREE;
915 switch (fncode)
917 case BUILT_IN_MEMCPY_CHKP:
918 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK);
919 break;
921 case BUILT_IN_MEMPCPY_CHKP:
922 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK);
923 break;
925 case BUILT_IN_MEMMOVE_CHKP:
926 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK);
927 break;
929 case BUILT_IN_MEMSET_CHKP:
930 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK);
931 break;
933 case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP:
934 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
935 break;
937 case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP:
938 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
939 break;
941 case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP:
942 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
943 break;
945 case BUILT_IN_CHKP_MEMSET_NOBND_CHKP:
946 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
947 break;
949 default:
950 break;
953 if (fndecl)
954 fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
956 return fndecl;
959 /* Find memcpy, mempcpy, memmove and memset calls, perform
960 checks before call and then call no_chk version of
961 functions. We do it on O2 to enable inlining of these
962 functions during expand.
964 Also try to find memcpy, mempcpy, memmove and memset calls
965 which are known to not write pointers to memory and use
966 faster function versions for them. */
967 static void
968 chkp_optimize_string_function_calls (void)
970 basic_block bb;
972 if (dump_file && (dump_flags & TDF_DETAILS))
973 fprintf (dump_file, "Searching for replaceable string function calls...\n");
975 FOR_EACH_BB_FN (bb, cfun)
977 gimple_stmt_iterator i;
979 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
981 gimple stmt = gsi_stmt (i);
982 tree fndecl;
984 if (gimple_code (stmt) != GIMPLE_CALL
985 || !gimple_call_with_bounds_p (stmt))
986 continue;
988 fndecl = gimple_call_fndecl (stmt);
990 if (!fndecl || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
991 continue;
993 if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMCPY_CHKP
994 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHKP
995 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMMOVE_CHKP
996 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP)
998 tree dst = gimple_call_arg (stmt, 0);
999 tree dst_bnd = gimple_call_arg (stmt, 1);
1000 bool is_memset = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMSET_CHKP;
1001 tree size = gimple_call_arg (stmt, is_memset ? 3 : 4);
1002 tree fndecl_nochk;
1003 gimple_stmt_iterator j;
1004 basic_block check_bb;
1005 address_t size_val;
1006 int sign;
1007 bool known;
1009 /* We may replace call with corresponding __chkp_*_nobnd
1010 call in case destination pointer base type is not
1011 void or pointer. */
1012 if (POINTER_TYPE_P (TREE_TYPE (dst))
1013 && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst)))
1014 && !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst))))
1016 tree fndecl_nobnd
1017 = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl));
1019 if (fndecl_nobnd)
1020 fndecl = fndecl_nobnd;
1023 fndecl_nochk = chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl));
1025 if (fndecl_nochk)
1026 fndecl = fndecl_nochk;
1028 if (fndecl != gimple_call_fndecl (stmt))
1030 if (dump_file && (dump_flags & TDF_DETAILS))
1032 fprintf (dump_file, "Replacing call: ");
1033 print_gimple_stmt (dump_file, stmt, 0,
1034 TDF_VOPS|TDF_MEMSYMS);
1037 gimple_call_set_fndecl (stmt, fndecl);
1039 if (dump_file && (dump_flags & TDF_DETAILS))
1041 fprintf (dump_file, "With a new call: ");
1042 print_gimple_stmt (dump_file, stmt, 0,
1043 TDF_VOPS|TDF_MEMSYMS);
1047 /* If there is no nochk version of function then
1048 do nothing. Otherwise insert checks before
1049 the call. */
1050 if (!fndecl_nochk)
1051 continue;
1053 /* If size passed to call is known and > 0
1054 then we may insert checks unconditionally. */
1055 size_val.pol.create (0);
1056 chkp_collect_value (size, size_val);
1057 known = chkp_is_constant_addr (size_val, &sign);
1058 size_val.pol.release ();
1060 /* If we are not sure size is not zero then we have
1061 to perform runtime check for size and perform
1062 checks only when size is not zero. */
1063 if (!known)
1065 gimple check = gimple_build_cond (NE_EXPR,
1066 size,
1067 size_zero_node,
1068 NULL_TREE,
1069 NULL_TREE);
1071 /* Split block before string function call. */
1072 gsi_prev (&i);
1073 check_bb = insert_cond_bb (bb, gsi_stmt (i), check);
1075 /* Set position for checks. */
1076 j = gsi_last_bb (check_bb);
1078 /* The block was splitted and therefore we
1079 need to set iterator to its end. */
1080 i = gsi_last_bb (bb);
1082 /* If size is known to be zero then no checks
1083 should be performed. */
1084 else if (!sign)
1085 continue;
1086 else
1087 j = i;
1089 size = size_binop (MINUS_EXPR, size, size_one_node);
1090 if (!is_memset)
1092 tree src = gimple_call_arg (stmt, 2);
1093 tree src_bnd = gimple_call_arg (stmt, 3);
1095 chkp_check_mem_access (src, fold_build_pointer_plus (src, size),
1096 src_bnd, j, gimple_location (stmt),
1097 integer_zero_node);
1100 chkp_check_mem_access (dst, fold_build_pointer_plus (dst, size),
1101 dst_bnd, j, gimple_location (stmt),
1102 integer_one_node);
1109 /* Intrumentation pass inserts most of bounds creation code
1110 in the header of the function. We want to move bounds
1111 creation closer to bounds usage to reduce bounds lifetime.
1112 We also try to avoid bounds creation code on paths where
1113 bounds are not used. */
1114 static void
1115 chkp_reduce_bounds_lifetime (void)
1117 basic_block bb = FALLTHRU_EDGE (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest;
1118 gimple_stmt_iterator i;
1120 for (i = gsi_start_bb (bb); !gsi_end_p (i); )
1122 gimple dom_use, use_stmt, stmt = gsi_stmt (i);
1123 basic_block dom_bb;
1124 ssa_op_iter iter;
1125 imm_use_iterator use_iter;
1126 use_operand_p use_p;
1127 tree op;
1128 bool want_move = false;
1129 bool deps = false;
1131 if (gimple_code (stmt) == GIMPLE_CALL
1132 && gimple_call_fndecl (stmt) == chkp_bndmk_fndecl)
1133 want_move = true;
1135 if (gimple_code (stmt) == GIMPLE_ASSIGN
1136 && POINTER_BOUNDS_P (gimple_assign_lhs (stmt))
1137 && gimple_assign_rhs_code (stmt) == VAR_DECL)
1138 want_move = true;
1140 if (!want_move)
1142 gsi_next (&i);
1143 continue;
1146 /* Check we do not increase other values lifetime. */
1147 FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
1149 op = USE_FROM_PTR (use_p);
1151 if (TREE_CODE (op) == SSA_NAME
1152 && gimple_code (SSA_NAME_DEF_STMT (op)) != GIMPLE_NOP)
1154 deps = true;
1155 break;
1159 if (deps)
1161 gsi_next (&i);
1162 continue;
1165 /* Check all usages of bounds. */
1166 if (gimple_code (stmt) == GIMPLE_CALL)
1167 op = gimple_call_lhs (stmt);
1168 else
1170 gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
1171 op = gimple_assign_lhs (stmt);
1174 dom_use = NULL;
1175 dom_bb = NULL;
1177 FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, op)
1179 if (is_gimple_debug (use_stmt))
1180 continue;
1182 if (dom_bb &&
1183 dominated_by_p (CDI_DOMINATORS,
1184 dom_bb, gimple_bb (use_stmt)))
1186 dom_use = use_stmt;
1187 dom_bb = NULL;
1189 else if (dom_bb)
1190 dom_bb = nearest_common_dominator (CDI_DOMINATORS, dom_bb,
1191 gimple_bb (use_stmt));
1192 else if (!dom_use)
1193 dom_use = use_stmt;
1194 else if (stmt_dominates_stmt_p (use_stmt, dom_use))
1195 dom_use = use_stmt;
1196 else if (!stmt_dominates_stmt_p (dom_use, use_stmt)
1197 /* If dom_use and use_stmt are PHI nodes in one BB
1198 then it is OK to keep any of them as dom_use.
1199 stmt_dominates_stmt_p returns 0 for such
1200 combination, so check it here manually. */
1201 && (gimple_code (dom_use) != GIMPLE_PHI
1202 || gimple_code (use_stmt) != GIMPLE_PHI
1203 || gimple_bb (use_stmt) != gimple_bb (dom_use))
1206 dom_bb = nearest_common_dominator (CDI_DOMINATORS,
1207 gimple_bb (use_stmt),
1208 gimple_bb (dom_use));
1209 dom_use = NULL;
1213 /* In case there is a single use, just move bounds
1214 creation to the use. */
1215 if (dom_use || dom_bb)
1217 if (dump_file && (dump_flags & TDF_DETAILS))
1219 fprintf (dump_file, "Moving creation of ");
1220 print_generic_expr (dump_file, op, 0);
1221 fprintf (dump_file, " down to its use.\n");
1224 if (dom_use && gimple_code (dom_use) == GIMPLE_PHI)
1226 dom_bb = get_immediate_dominator (CDI_DOMINATORS,
1227 gimple_bb (dom_use));
1228 dom_use = NULL;
1231 if (dom_bb == bb
1232 || (dom_use && gimple_bb (dom_use) == bb))
1234 if (dump_file && (dump_flags & TDF_DETAILS))
1235 fprintf (dump_file, "Cannot move statement bacause there is no "
1236 "suitable dominator block other than entry block.\n");
1238 gsi_next (&i);
1240 else
1242 if (dom_bb)
1244 gimple_stmt_iterator last = gsi_last_bb (dom_bb);
1245 if (!gsi_end_p (last) && stmt_ends_bb_p (gsi_stmt (last)))
1246 gsi_move_before (&i, &last);
1247 else
1248 gsi_move_after (&i, &last);
1250 else
1252 gimple_stmt_iterator gsi = gsi_for_stmt (dom_use);
1253 gsi_move_before (&i, &gsi);
1256 update_stmt (stmt);
1259 else
1260 gsi_next (&i);
1264 /* Initilize checker optimization pass. */
1265 static void
1266 chkp_opt_init (void)
1268 check_infos.create (0);
1270 calculate_dominance_info (CDI_DOMINATORS);
1271 calculate_dominance_info (CDI_POST_DOMINATORS);
1273 /* With LTO constant bounds vars may be not initialized by now.
1274 Get constant bounds vars to handle their assignments during
1275 optimizations. */
1276 chkp_get_zero_bounds_var ();
1277 chkp_get_none_bounds_var ();
1280 /* Finalise checker optimization pass. */
1281 static void
1282 chkp_opt_fini (void)
1284 chkp_fix_cfg ();
1286 free_dominance_info (CDI_POST_DOMINATORS);
1289 /* Checker optimization pass function. */
1290 static unsigned int
1291 chkp_opt_execute (void)
1293 chkp_opt_init();
1295 /* This optimization may introduce new checks
1296 and thus we put it before checks search. */
1297 chkp_optimize_string_function_calls ();
1299 chkp_gather_checks_info ();
1301 chkp_remove_excess_intersections ();
1303 chkp_remove_constant_checks ();
1305 chkp_reduce_bounds_lifetime ();
1307 chkp_release_check_info ();
1309 chkp_opt_fini ();
1311 return 0;
1314 /* Pass gate. */
1315 static bool
1316 chkp_opt_gate (void)
1318 return chkp_function_instrumented_p (cfun->decl)
1319 && (flag_chkp_optimize > 0
1320 || (flag_chkp_optimize == -1 && optimize > 0));
1323 namespace {
1325 const pass_data pass_data_chkp_opt =
1327 GIMPLE_PASS, /* type */
1328 "chkpopt", /* name */
1329 OPTGROUP_NONE, /* optinfo_flags */
1330 TV_NONE, /* tv_id */
1331 PROP_ssa | PROP_cfg, /* properties_required */
1332 0, /* properties_provided */
1333 0, /* properties_destroyed */
1334 0, /* todo_flags_start */
1335 TODO_verify_il
1336 | TODO_update_ssa /* todo_flags_finish */
1339 class pass_chkp_opt : public gimple_opt_pass
1341 public:
1342 pass_chkp_opt (gcc::context *ctxt)
1343 : gimple_opt_pass (pass_data_chkp_opt, ctxt)
1346 /* opt_pass methods: */
1347 virtual opt_pass * clone ()
1349 return new pass_chkp_opt (m_ctxt);
1352 virtual bool gate (function *)
1354 return chkp_opt_gate ();
1357 virtual unsigned int execute (function *)
1359 return chkp_opt_execute ();
1362 }; // class pass_chkp_opt
1364 } // anon namespace
1366 gimple_opt_pass *
1367 make_pass_chkp_opt (gcc::context *ctxt)
1369 return new pass_chkp_opt (ctxt);