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
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
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/>. */
23 #include "coretypes.h"
29 #include "fold-const.h"
32 #include "tree-pass.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"
42 #include "dominance.h"
44 #include "basic-block.h"
45 #include "tree-ssa-loop-niter.h"
46 #include "gimple-expr.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"
54 #include "gimplify-me.h"
56 #include "hard-reg-set.h"
60 #include "insn-config.h"
69 #include "tree-chkp.h"
71 #include "diagnostic.h"
87 vec
<struct pol_item
> pol
;
90 /* Structure to hold check informtation. */
93 /* Type of the check. */
95 /* Address used for the check. */
97 /* Bounds used for the check. */
99 /* Check statement. Can be NULL for removed checks. */
103 /* Structure to hold checks information for BB. */
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
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
)
133 else if (p1
->var
> p2
->var
)
139 /* Find polynomial item in ADDR with var equal to VAR
140 and return its index. Return -1 if item was not
143 chkp_pol_find (address_t
&addr
, tree var
)
146 int right
= addr
.pol
.length () - 1;
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)))
159 else if (addr
.pol
[n
].var
> var
)
168 /* Return constant CST extended to size type. */
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
));
178 /* Add polynomial item CST * VAR to ADDR. */
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
);
188 struct pol_item item
;
192 addr
.pol
.safe_push (item
);
193 addr
.pol
.qsort (&chkp_pol_item_compare
);
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. */
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
);
215 struct pol_item item
;
216 item
.cst
= fold_build2 (MINUS_EXPR
, TREE_TYPE (cst
),
217 integer_zero_node
, cst
);
220 addr
.pol
.safe_push (item
);
221 addr
.pol
.qsort (&chkp_pol_item_compare
);
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. */
235 chkp_add_addr_addr (address_t
&addr
, address_t
&delta
)
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. */
244 chkp_sub_addr_addr (address_t
&addr
, address_t
&delta
)
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. */
253 chkp_mult_addr (address_t
&addr
, tree mult
)
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
265 chkp_is_constant_addr (const address_t
&addr
, int *sign
)
269 if (addr
.pol
.length () == 0)
271 else if (addr
.pol
.length () > 1)
273 else if (addr
.pol
[0].var
)
275 else if (integer_zerop (addr
.pol
[0].cst
))
277 else if (tree_int_cst_sign_bit (addr
.pol
[0].cst
))
285 /* Dump ADDR into dump_file. */
287 chkp_print_addr (const address_t
&addr
)
290 for (n
= 0; n
< addr
.pol
.length (); n
++)
293 fprintf (dump_file
, " + ");
295 if (addr
.pol
[n
].var
== NULL_TREE
)
296 print_generic_expr (dump_file
, addr
.pol
[n
].cst
, 0);
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. */
313 chkp_collect_addr_value (tree ptr
, address_t
&res
)
315 tree obj
= TREE_OPERAND (ptr
, 0);
318 switch (TREE_CODE (obj
))
321 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
325 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
327 chkp_collect_value (TREE_OPERAND (obj
, 1), addr
);
328 chkp_add_addr_addr (res
, addr
);
333 chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj
, 0)), res
);
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
);
343 tree str
= TREE_OPERAND (obj
, 0);
344 tree field
= TREE_OPERAND (obj
, 1);
345 chkp_collect_value (build_fold_addr_expr (str
), res
);
347 chkp_collect_value (component_ref_field_offset (obj
), addr
);
348 chkp_add_addr_addr (res
, addr
);
350 if (DECL_FIELD_BIT_OFFSET (field
))
353 chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR
, size_type_node
,
354 DECL_FIELD_BIT_OFFSET (field
),
355 size_int (BITS_PER_UNIT
)),
357 chkp_add_addr_addr (res
, addr
);
364 chkp_add_addr_item (res
, integer_one_node
, ptr
);
369 /* Compute value of PTR and put it into address RES. */
371 chkp_collect_value (tree ptr
, address_t
&res
)
374 enum gimple_code code
;
375 enum tree_code rhs_code
;
379 if (TREE_CODE (ptr
) == INTEGER_CST
)
381 chkp_add_addr_item (res
, ptr
, NULL
);
384 else if (TREE_CODE (ptr
) == ADDR_EXPR
)
386 chkp_collect_addr_value (ptr
, res
);
389 else if (TREE_CODE (ptr
) != SSA_NAME
)
391 chkp_add_addr_item (res
, integer_one_node
, ptr
);
395 /* Now we handle the case when polynomial is computed
397 def_stmt
= SSA_NAME_DEF_STMT (ptr
);
398 code
= gimple_code (def_stmt
);
400 /* Currently we do not walk through statements other
402 if (code
!= GIMPLE_ASSIGN
)
404 chkp_add_addr_item (res
, integer_one_node
, ptr
);
408 rhs_code
= gimple_assign_rhs_code (def_stmt
);
409 rhs1
= gimple_assign_rhs1 (def_stmt
);
416 chkp_collect_value (rhs1
, res
);
420 case POINTER_PLUS_EXPR
:
421 chkp_collect_value (rhs1
, res
);
423 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
424 chkp_add_addr_addr (res
, addr
);
429 chkp_collect_value (rhs1
, res
);
431 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
432 chkp_sub_addr_addr (res
, addr
);
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
);
450 chkp_add_addr_item (res
, integer_one_node
, ptr
);
454 chkp_add_addr_item (res
, integer_one_node
, ptr
);
459 /* Fill check_info structure *CI with information about
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
469 : CHECK_UPPER_BOUND
);
473 /* Release structures holding check information
474 for current function. */
476 chkp_release_check_info (void)
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. */
496 chkp_init_check_info (void)
498 struct bb_checks empty_bbc
;
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
516 chkp_gather_checks_info (void)
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
)
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. */
567 chkp_get_check_result (struct check_info
*ci
, tree bounds
)
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");
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
)
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");
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");
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
);
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");
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
)
649 && !chkp_variable_size_type (TREE_TYPE (var
)))
650 size
= DECL_SIZE_UNIT (var
);
653 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
654 fprintf (dump_file
, " result: cannot compute bounds\n");
660 gcc_assert (TREE_CODE (var
) == STRING_CST
);
661 size
= build_int_cst (size_type_node
,
662 TREE_STRING_LENGTH (var
));
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
);
675 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
676 fprintf (dump_file
, " result: cannot compute bounds\n");
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");
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");
707 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
708 fprintf (dump_file
, " result: always fail\n");
713 bound_val
.pol
.release ();
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. */
722 chkp_remove_check_if_pass (struct check_info
*ci
)
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
);
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
);
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. */
765 chkp_use_outer_bounds_if_possible (struct check_info
*ci
)
768 tree bnd1
, bnd2
, bnd_res
= NULL
;
769 int check_res1
, check_res2
;
771 if (TREE_CODE (ci
->bounds
) != SSA_NAME
)
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
)
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
);
796 else if (check_res1
== -1)
798 else if (check_res2
== 1)
800 else if (check_res2
== -1)
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. */
826 chkp_remove_excess_intersections (void)
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
];
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. */
847 chkp_remove_constant_checks (void)
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
];
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. */
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
)
874 tree fndecl
= NULL_TREE
;
878 case BUILT_IN_MEMCPY_CHKP
:
879 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND
);
882 case BUILT_IN_MEMPCPY_CHKP
:
883 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND
);
886 case BUILT_IN_MEMMOVE_CHKP
:
887 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND
);
890 case BUILT_IN_MEMSET_CHKP
:
891 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND
);
894 case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP
:
895 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
898 case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP
:
899 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
902 case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP
:
903 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
906 case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP
:
907 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
915 fndecl
= chkp_maybe_clone_builtin_fndecl (fndecl
);
921 /* Return no-check version of string function FNCODE. */
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
)
929 tree fndecl
= NULL_TREE
;
933 case BUILT_IN_MEMCPY_CHKP
:
934 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK
);
937 case BUILT_IN_MEMPCPY_CHKP
:
938 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK
);
941 case BUILT_IN_MEMMOVE_CHKP
:
942 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK
);
945 case BUILT_IN_MEMSET_CHKP
:
946 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK
);
949 case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP
:
950 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
953 case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP
:
954 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
957 case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP
:
958 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
961 case BUILT_IN_CHKP_MEMSET_NOBND_CHKP
:
962 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
970 fndecl
= chkp_maybe_clone_builtin_fndecl (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. */
984 chkp_optimize_string_function_calls (void)
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
);
1000 if (gimple_code (stmt
) != GIMPLE_CALL
1001 || !gimple_call_with_bounds_p (stmt
))
1004 fndecl
= gimple_call_fndecl (stmt
);
1006 if (!fndecl
|| DECL_BUILT_IN_CLASS (fndecl
) != BUILT_IN_NORMAL
)
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);
1019 gimple_stmt_iterator j
;
1020 basic_block check_bb
;
1025 /* We may replace call with corresponding __chkp_*_nobnd
1026 call in case destination pointer base type is not
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
))))
1033 = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl
));
1036 fndecl
= fndecl_nobnd
;
1039 fndecl_nochk
= chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl
));
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
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. */
1081 gimple check
= gimple_build_cond (NE_EXPR
,
1087 /* Split block before string function call. */
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. */
1105 size
= size_binop (MINUS_EXPR
, size
, size_one_node
);
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
),
1116 chkp_check_mem_access (dst
, fold_build_pointer_plus (dst
, size
),
1117 dst_bnd
, j
, gimple_location (stmt
),
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. */
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
);
1141 imm_use_iterator use_iter
;
1142 use_operand_p use_p
;
1144 bool want_move
= false;
1147 if (gimple_code (stmt
) == GIMPLE_CALL
1148 && gimple_call_fndecl (stmt
) == chkp_bndmk_fndecl
)
1151 if (gimple_code (stmt
) == GIMPLE_ASSIGN
1152 && POINTER_BOUNDS_P (gimple_assign_lhs (stmt
))
1153 && gimple_assign_rhs_code (stmt
) == VAR_DECL
)
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
)
1181 /* Check all usages of bounds. */
1182 if (gimple_code (stmt
) == GIMPLE_CALL
)
1183 op
= gimple_call_lhs (stmt
);
1186 gcc_assert (gimple_code (stmt
) == GIMPLE_ASSIGN
);
1187 op
= gimple_assign_lhs (stmt
);
1193 FOR_EACH_IMM_USE_STMT (use_stmt
, use_iter
, op
)
1195 if (is_gimple_debug (use_stmt
))
1199 dominated_by_p (CDI_DOMINATORS
,
1200 dom_bb
, gimple_bb (use_stmt
)))
1206 dom_bb
= nearest_common_dominator (CDI_DOMINATORS
, dom_bb
,
1207 gimple_bb (use_stmt
));
1210 else if (stmt_dominates_stmt_p (use_stmt
, dom_use
))
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
));
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
));
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");
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
);
1264 gsi_move_after (&i
, &last
);
1268 gimple_stmt_iterator gsi
= gsi_for_stmt (dom_use
);
1269 gsi_move_before (&i
, &gsi
);
1280 /* Initilize checker optimization pass. */
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
1292 chkp_get_zero_bounds_var ();
1293 chkp_get_none_bounds_var ();
1296 /* Finalise checker optimization pass. */
1298 chkp_opt_fini (void)
1303 /* Checker optimization pass function. */
1305 chkp_opt_execute (void)
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 ();
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));
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 */
1350 | TODO_update_ssa
/* todo_flags_finish */
1353 class pass_chkp_opt
: public gimple_opt_pass
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
1381 make_pass_chkp_opt (gcc::context
*ctxt
)
1383 return new pass_chkp_opt (ctxt
);