1 /* Pointer Bounds Checker optimization pass.
2 Copyright (C) 2014 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"
24 #include "tree-core.h"
28 #include "tree-pass.h"
31 #include "stringpool.h"
32 #include "tree-ssa-alias.h"
33 #include "tree-ssanames.h"
34 #include "tree-ssa-operands.h"
35 #include "tree-ssa-address.h"
38 #include "dominance.h"
40 #include "basic-block.h"
41 #include "tree-ssa-loop-niter.h"
42 #include "gimple-expr.h"
44 #include "tree-phinodes.h"
45 #include "gimple-ssa.h"
46 #include "ssa-iterators.h"
47 #include "gimple-pretty-print.h"
48 #include "gimple-iterator.h"
50 #include "gimplify-me.h"
52 #include "tree-chkp.h"
54 #include "diagnostic.h"
70 vec
<struct pol_item
> pol
;
73 /* Structure to hold check informtation. */
76 /* Type of the check. */
78 /* Address used for the check. */
80 /* Bounds used for the check. */
82 /* Check statement. Can be NULL for removed checks. */
86 /* Structure to hold checks information for BB. */
89 vec
<struct check_info
, va_heap
, vl_ptr
> checks
;
92 static void chkp_collect_value (tree ssa_name
, address_t
&res
);
94 #define chkp_bndmk_fndecl \
95 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
96 #define chkp_intersect_fndecl \
97 (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
98 #define chkp_checkl_fndecl \
99 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
100 #define chkp_checku_fndecl \
101 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
103 static vec
<struct bb_checks
, va_heap
, vl_ptr
> check_infos
= vNULL
;
105 /* Comparator for pol_item structures I1 and I2 to be used
106 to find items with equal var. Also used for polynomial
109 chkp_pol_item_compare (const void *i1
, const void *i2
)
111 const struct pol_item
*p1
= (const struct pol_item
*)i1
;
112 const struct pol_item
*p2
= (const struct pol_item
*)i2
;
114 if (p1
->var
== p2
->var
)
116 else if (p1
->var
> p2
->var
)
122 /* Find polynomial item in ADDR with var equal to VAR
123 and return its index. Return -1 if item was not
126 chkp_pol_find (address_t
&addr
, tree var
)
129 int right
= addr
.pol
.length () - 1;
132 while (right
>= left
)
134 n
= (left
+ right
) / 2;
136 if (addr
.pol
[n
].var
== var
137 || (var
&& addr
.pol
[n
].var
138 && TREE_CODE (var
) == ADDR_EXPR
139 && TREE_CODE (addr
.pol
[n
].var
) == ADDR_EXPR
140 && TREE_OPERAND (var
, 0) == TREE_OPERAND (addr
.pol
[n
].var
, 0)))
142 else if (addr
.pol
[n
].var
> var
)
151 /* Return constant CST extended to size type. */
153 chkp_extend_const (tree cst
)
155 if (TYPE_PRECISION (TREE_TYPE (cst
)) < TYPE_PRECISION (size_type_node
))
156 return build_int_cst_type (size_type_node
, tree_to_shwi (cst
));
161 /* Add polynomial item CST * VAR to ADDR. */
163 chkp_add_addr_item (address_t
&addr
, tree cst
, tree var
)
165 int n
= chkp_pol_find (addr
, var
);
167 cst
= chkp_extend_const (cst
);
171 struct pol_item item
;
175 addr
.pol
.safe_push (item
);
176 addr
.pol
.qsort (&chkp_pol_item_compare
);
180 addr
.pol
[n
].cst
= fold_build2 (PLUS_EXPR
, TREE_TYPE (addr
.pol
[n
].cst
),
181 addr
.pol
[n
].cst
, cst
);
182 if (TREE_CODE (addr
.pol
[n
].cst
) == INTEGER_CST
183 && integer_zerop (addr
.pol
[n
].cst
))
184 addr
.pol
.ordered_remove (n
);
188 /* Subtract polynomial item CST * VAR from ADDR. */
190 chkp_sub_addr_item (address_t
&addr
, tree cst
, tree var
)
192 int n
= chkp_pol_find (addr
, var
);
194 cst
= chkp_extend_const (cst
);
198 struct pol_item item
;
199 item
.cst
= fold_build2 (MINUS_EXPR
, TREE_TYPE (cst
),
200 integer_zero_node
, cst
);
203 addr
.pol
.safe_push (item
);
204 addr
.pol
.qsort (&chkp_pol_item_compare
);
208 addr
.pol
[n
].cst
= fold_build2 (MINUS_EXPR
, TREE_TYPE (addr
.pol
[n
].cst
),
209 addr
.pol
[n
].cst
, cst
);
210 if (TREE_CODE (addr
.pol
[n
].cst
) == INTEGER_CST
211 && integer_zerop (addr
.pol
[n
].cst
))
212 addr
.pol
.ordered_remove (n
);
216 /* Add address DELTA to ADDR. */
218 chkp_add_addr_addr (address_t
&addr
, address_t
&delta
)
221 for (i
= 0; i
< delta
.pol
.length (); i
++)
222 chkp_add_addr_item (addr
, delta
.pol
[i
].cst
, delta
.pol
[i
].var
);
225 /* Subtract address DELTA from ADDR. */
227 chkp_sub_addr_addr (address_t
&addr
, address_t
&delta
)
230 for (i
= 0; i
< delta
.pol
.length (); i
++)
231 chkp_sub_addr_item (addr
, delta
.pol
[i
].cst
, delta
.pol
[i
].var
);
234 /* Mutiply address ADDR by integer constant MULT. */
236 chkp_mult_addr (address_t
&addr
, tree mult
)
239 for (i
= 0; i
< addr
.pol
.length (); i
++)
240 addr
.pol
[i
].cst
= fold_build2 (MULT_EXPR
, TREE_TYPE (addr
.pol
[i
].cst
),
241 addr
.pol
[i
].cst
, mult
);
244 /* Return 1 if we may prove ADDR has a constant value with
245 determined sign, which is put into *SIGN. Otherwise
248 chkp_is_constant_addr (const address_t
&addr
, int *sign
)
252 if (addr
.pol
.length () == 0)
254 else if (addr
.pol
.length () > 1)
256 else if (addr
.pol
[0].var
)
258 else if (integer_zerop (addr
.pol
[0].cst
))
260 else if (tree_int_cst_sign_bit (addr
.pol
[0].cst
))
268 /* Dump ADDR into dump_file. */
270 chkp_print_addr (const address_t
&addr
)
273 for (n
= 0; n
< addr
.pol
.length (); n
++)
276 fprintf (dump_file
, " + ");
278 if (addr
.pol
[n
].var
== NULL_TREE
)
279 print_generic_expr (dump_file
, addr
.pol
[n
].cst
, 0);
282 if (TREE_CODE (addr
.pol
[n
].cst
) != INTEGER_CST
283 || !integer_onep (addr
.pol
[n
].cst
))
285 print_generic_expr (dump_file
, addr
.pol
[n
].cst
, 0);
286 fprintf (dump_file
, " * ");
288 print_generic_expr (dump_file
, addr
.pol
[n
].var
, 0);
293 /* Compute value of PTR and put it into address RES.
294 PTR has to be ADDR_EXPR. */
296 chkp_collect_addr_value (tree ptr
, address_t
&res
)
298 tree obj
= TREE_OPERAND (ptr
, 0);
301 switch (TREE_CODE (obj
))
304 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
308 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
310 chkp_collect_value (TREE_OPERAND (obj
, 1), addr
);
311 chkp_add_addr_addr (res
, addr
);
316 chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj
, 0)), res
);
318 chkp_collect_value (TREE_OPERAND (obj
, 1), addr
);
319 chkp_mult_addr (addr
, array_ref_element_size (obj
));
320 chkp_add_addr_addr (res
, addr
);
326 tree str
= TREE_OPERAND (obj
, 0);
327 tree field
= TREE_OPERAND (obj
, 1);
328 chkp_collect_value (build_fold_addr_expr (str
), res
);
330 chkp_collect_value (component_ref_field_offset (obj
), addr
);
331 chkp_add_addr_addr (res
, addr
);
333 if (DECL_FIELD_BIT_OFFSET (field
))
336 chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR
, size_type_node
,
337 DECL_FIELD_BIT_OFFSET (field
),
338 size_int (BITS_PER_UNIT
)),
340 chkp_add_addr_addr (res
, addr
);
347 chkp_add_addr_item (res
, integer_one_node
, ptr
);
352 /* Compute value of PTR and put it into address RES. */
354 chkp_collect_value (tree ptr
, address_t
&res
)
357 enum gimple_code code
;
358 enum tree_code rhs_code
;
362 if (TREE_CODE (ptr
) == INTEGER_CST
)
364 chkp_add_addr_item (res
, ptr
, NULL
);
367 else if (TREE_CODE (ptr
) == ADDR_EXPR
)
369 chkp_collect_addr_value (ptr
, res
);
372 else if (TREE_CODE (ptr
) != SSA_NAME
)
374 chkp_add_addr_item (res
, integer_one_node
, ptr
);
378 /* Now we handle the case when polynomial is computed
380 def_stmt
= SSA_NAME_DEF_STMT (ptr
);
381 code
= gimple_code (def_stmt
);
383 /* Currently we do not walk through statements other
385 if (code
!= GIMPLE_ASSIGN
)
387 chkp_add_addr_item (res
, integer_one_node
, ptr
);
391 rhs_code
= gimple_assign_rhs_code (def_stmt
);
392 rhs1
= gimple_assign_rhs1 (def_stmt
);
399 chkp_collect_value (rhs1
, res
);
403 case POINTER_PLUS_EXPR
:
404 chkp_collect_value (rhs1
, res
);
406 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
407 chkp_add_addr_addr (res
, addr
);
412 chkp_collect_value (rhs1
, res
);
414 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
415 chkp_sub_addr_addr (res
, addr
);
420 if (TREE_CODE (rhs1
) == SSA_NAME
421 && TREE_CODE (gimple_assign_rhs2 (def_stmt
)) == INTEGER_CST
)
423 chkp_collect_value (rhs1
, res
);
424 chkp_mult_addr (res
, gimple_assign_rhs2 (def_stmt
));
426 else if (TREE_CODE (gimple_assign_rhs2 (def_stmt
)) == SSA_NAME
427 && TREE_CODE (rhs1
) == INTEGER_CST
)
429 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), res
);
430 chkp_mult_addr (res
, rhs1
);
433 chkp_add_addr_item (res
, integer_one_node
, ptr
);
437 chkp_add_addr_item (res
, integer_one_node
, ptr
);
442 /* Fill check_info structure *CI with information about
445 chkp_fill_check_info (gimple stmt
, struct check_info
*ci
)
447 ci
->addr
.pol
.create (0);
448 ci
->bounds
= gimple_call_arg (stmt
, 1);
449 chkp_collect_value (gimple_call_arg (stmt
, 0), ci
->addr
);
450 ci
->type
= (gimple_call_fndecl (stmt
) == chkp_checkl_fndecl
452 : CHECK_UPPER_BOUND
);
456 /* Release structures holding check information
457 for current function. */
459 chkp_release_check_info (void)
463 if (check_infos
.exists ())
465 for (n
= 0; n
< check_infos
.length (); n
++)
467 for (m
= 0; m
< check_infos
[n
].checks
.length (); m
++)
468 if (check_infos
[n
].checks
[m
].addr
.pol
.exists ())
469 check_infos
[n
].checks
[m
].addr
.pol
.release ();
470 check_infos
[n
].checks
.release ();
472 check_infos
.release ();
476 /* Create structures to hold check information
477 for current function. */
479 chkp_init_check_info (void)
481 struct bb_checks empty_bbc
;
484 empty_bbc
.checks
= vNULL
;
486 chkp_release_check_info ();
488 check_infos
.create (last_basic_block_for_fn (cfun
));
489 for (n
= 0; n
< last_basic_block_for_fn (cfun
); n
++)
491 check_infos
.safe_push (empty_bbc
);
492 check_infos
.last ().checks
.create (0);
496 /* Find all checks in current function and store info about them
499 chkp_gather_checks_info (void)
502 gimple_stmt_iterator i
;
504 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
505 fprintf (dump_file
, "Gathering information about checks...\n");
507 chkp_init_check_info ();
509 FOR_EACH_BB_FN (bb
, cfun
)
511 struct bb_checks
*bbc
= &check_infos
[bb
->index
];
513 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
514 fprintf (dump_file
, "Searching checks in BB%d...\n", bb
->index
);
516 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
518 gimple stmt
= gsi_stmt (i
);
520 if (gimple_code (stmt
) != GIMPLE_CALL
)
523 if (gimple_call_fndecl (stmt
) == chkp_checkl_fndecl
524 || gimple_call_fndecl (stmt
) == chkp_checku_fndecl
)
526 struct check_info ci
;
528 chkp_fill_check_info (stmt
, &ci
);
529 bbc
->checks
.safe_push (ci
);
531 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
533 fprintf (dump_file
, "Adding check information:\n");
534 fprintf (dump_file
, " bounds: ");
535 print_generic_expr (dump_file
, ci
.bounds
, 0);
536 fprintf (dump_file
, "\n address: ");
537 chkp_print_addr (ci
.addr
);
538 fprintf (dump_file
, "\n check: ");
539 print_gimple_stmt (dump_file
, stmt
, 0, 0);
546 /* Return 1 if check CI against BOUNDS always pass,
547 -1 if check CI against BOUNDS always fails and
548 0 if we cannot compute check result. */
550 chkp_get_check_result (struct check_info
*ci
, tree bounds
)
556 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
558 fprintf (dump_file
, "Trying to compute result of the check\n");
559 fprintf (dump_file
, " check: ");
560 print_gimple_stmt (dump_file
, ci
->stmt
, 0, 0);
561 fprintf (dump_file
, " address: ");
562 chkp_print_addr (ci
->addr
);
563 fprintf (dump_file
, "\n bounds: ");
564 print_generic_expr (dump_file
, bounds
, 0);
565 fprintf (dump_file
, "\n");
568 if (TREE_CODE (bounds
) != SSA_NAME
)
570 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
571 fprintf (dump_file
, " result: bounds tree code is not ssa_name\n");
575 bnd_def
= SSA_NAME_DEF_STMT (bounds
);
576 /* Currently we handle cases when bounds are result of bndmk
577 or loaded static bounds var. */
578 if (gimple_code (bnd_def
) == GIMPLE_CALL
579 && gimple_call_fndecl (bnd_def
) == chkp_bndmk_fndecl
)
581 bound_val
.pol
.create (0);
582 chkp_collect_value (gimple_call_arg (bnd_def
, 0), bound_val
);
583 if (ci
->type
== CHECK_UPPER_BOUND
)
586 size_val
.pol
.create (0);
587 chkp_collect_value (gimple_call_arg (bnd_def
, 1), size_val
);
588 chkp_add_addr_addr (bound_val
, size_val
);
589 size_val
.pol
.release ();
590 chkp_add_addr_item (bound_val
, integer_minus_one_node
, NULL
);
593 else if (gimple_code (bnd_def
) == GIMPLE_ASSIGN
594 && gimple_assign_rhs1 (bnd_def
) == chkp_get_zero_bounds_var ())
596 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
597 fprintf (dump_file
, " result: always pass with zero bounds\n");
600 else if (gimple_code (bnd_def
) == GIMPLE_ASSIGN
601 && gimple_assign_rhs1 (bnd_def
) == chkp_get_none_bounds_var ())
603 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
604 fprintf (dump_file
, " result: always fails with none bounds\n");
607 else if (gimple_code (bnd_def
) == GIMPLE_ASSIGN
608 && TREE_CODE (gimple_assign_rhs1 (bnd_def
)) == VAR_DECL
)
610 tree bnd_var
= gimple_assign_rhs1 (bnd_def
);
614 if (!DECL_INITIAL (bnd_var
)
615 || DECL_INITIAL (bnd_var
) == error_mark_node
)
617 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
618 fprintf (dump_file
, " result: cannot compute bounds\n");
622 gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var
)) == ADDR_EXPR
);
623 var
= TREE_OPERAND (DECL_INITIAL (bnd_var
), 0);
625 bound_val
.pol
.create (0);
626 chkp_collect_value (DECL_INITIAL (bnd_var
), bound_val
);
627 if (ci
->type
== CHECK_UPPER_BOUND
)
629 if (TREE_CODE (var
) == VAR_DECL
)
632 && !chkp_variable_size_type (TREE_TYPE (var
)))
633 size
= DECL_SIZE_UNIT (var
);
636 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
637 fprintf (dump_file
, " result: cannot compute bounds\n");
643 gcc_assert (TREE_CODE (var
) == STRING_CST
);
644 size
= build_int_cst (size_type_node
,
645 TREE_STRING_LENGTH (var
));
649 size_val
.pol
.create (0);
650 chkp_collect_value (size
, size_val
);
651 chkp_add_addr_addr (bound_val
, size_val
);
652 size_val
.pol
.release ();
653 chkp_add_addr_item (bound_val
, integer_minus_one_node
, NULL
);
658 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
659 fprintf (dump_file
, " result: cannot compute bounds\n");
663 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
665 fprintf (dump_file
, " bound value: ");
666 chkp_print_addr (bound_val
);
667 fprintf (dump_file
, "\n");
670 chkp_sub_addr_addr (bound_val
, ci
->addr
);
672 if (!chkp_is_constant_addr (bound_val
, &sign
))
674 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
675 fprintf (dump_file
, " result: cannot compute result\n");
680 || (ci
->type
== CHECK_UPPER_BOUND
&& sign
> 0)
681 || (ci
->type
== CHECK_LOWER_BOUND
&& sign
< 0))
683 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
684 fprintf (dump_file
, " result: always pass\n");
690 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
691 fprintf (dump_file
, " result: always fail\n");
696 bound_val
.pol
.release ();
701 /* Try to compare bounds value and address value
702 used in the check CI. If we can prove that check
703 always pass then remove it. */
705 chkp_remove_check_if_pass (struct check_info
*ci
)
709 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
711 fprintf (dump_file
, "Trying to remove check: ");
712 print_gimple_stmt (dump_file
, ci
->stmt
, 0, 0);
715 result
= chkp_get_check_result (ci
, ci
->bounds
);
719 gimple_stmt_iterator i
= gsi_for_stmt (ci
->stmt
);
721 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
722 fprintf (dump_file
, " action: delete check (always pass)\n");
724 gsi_remove (&i
, true);
725 unlink_stmt_vdef (ci
->stmt
);
726 release_defs (ci
->stmt
);
729 else if (result
== -1)
731 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
732 fprintf (dump_file
, " action: keep check (always fail)\n");
733 warning_at (gimple_location (ci
->stmt
), OPT_Wchkp
,
734 "memory access check always fail");
736 else if (result
== 0)
738 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
739 fprintf (dump_file
, " action: keep check (cannot compute result)\n");
743 /* For bounds used in CI check if bounds are produced by
744 intersection and we may use outer bounds instead. If
745 transformation is possible then fix check statement and
746 recompute its info. */
748 chkp_use_outer_bounds_if_possible (struct check_info
*ci
)
751 tree bnd1
, bnd2
, bnd_res
= NULL
;
752 int check_res1
, check_res2
;
754 if (TREE_CODE (ci
->bounds
) != SSA_NAME
)
757 bnd_def
= SSA_NAME_DEF_STMT (ci
->bounds
);
758 if (gimple_code (bnd_def
) != GIMPLE_CALL
759 || gimple_call_fndecl (bnd_def
) != chkp_intersect_fndecl
)
762 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
764 fprintf (dump_file
, "Check if bounds intersection is redundant: \n");
765 fprintf (dump_file
, " check: ");
766 print_gimple_stmt (dump_file
, ci
->stmt
, 0, 0);
767 fprintf (dump_file
, " intersection: ");
768 print_gimple_stmt (dump_file
, bnd_def
, 0, 0);
769 fprintf (dump_file
, "\n");
772 bnd1
= gimple_call_arg (bnd_def
, 0);
773 bnd2
= gimple_call_arg (bnd_def
, 1);
775 check_res1
= chkp_get_check_result (ci
, bnd1
);
776 check_res2
= chkp_get_check_result (ci
, bnd2
);
779 else if (check_res1
== -1)
781 else if (check_res2
== 1)
783 else if (check_res2
== -1)
788 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
790 fprintf (dump_file
, " action: use ");
791 print_generic_expr (dump_file
, bnd2
, 0);
792 fprintf (dump_file
, " instead of ");
793 print_generic_expr (dump_file
, ci
->bounds
, 0);
794 fprintf (dump_file
, "\n");
797 ci
->bounds
= bnd_res
;
798 gimple_call_set_arg (ci
->stmt
, 1, bnd_res
);
799 update_stmt (ci
->stmt
);
800 chkp_fill_check_info (ci
->stmt
, ci
);
804 /* Try to find checks whose bounds were produced by intersection
805 which does not affect check result. In such check outer bounds
806 are used instead. It allows to remove excess intersections
807 and helps to compare checks. */
809 chkp_remove_excess_intersections (void)
813 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
814 fprintf (dump_file
, "Searching for redundant bounds intersections...\n");
816 FOR_EACH_BB_FN (bb
, cfun
)
818 struct bb_checks
*bbc
= &check_infos
[bb
->index
];
821 /* Iterate through all found checks in BB. */
822 for (no
= 0; no
< bbc
->checks
.length (); no
++)
823 if (bbc
->checks
[no
].stmt
)
824 chkp_use_outer_bounds_if_possible (&bbc
->checks
[no
]);
828 /* Try to remove all checks which are known to alwyas pass. */
830 chkp_remove_constant_checks (void)
834 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
835 fprintf (dump_file
, "Searching for redundant checks...\n");
837 FOR_EACH_BB_FN (bb
, cfun
)
839 struct bb_checks
*bbc
= &check_infos
[bb
->index
];
842 /* Iterate through all found checks in BB. */
843 for (no
= 0; no
< bbc
->checks
.length (); no
++)
844 if (bbc
->checks
[no
].stmt
)
845 chkp_remove_check_if_pass (&bbc
->checks
[no
]);
849 /* Return fast version of string function FNCODE. */
851 chkp_get_nobnd_fndecl (enum built_in_function fncode
)
853 /* Check if we are allowed to use fast string functions. */
854 if (!flag_chkp_use_fast_string_functions
)
857 tree fndecl
= NULL_TREE
;
861 case BUILT_IN_MEMCPY_CHKP
:
862 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND
);
865 case BUILT_IN_MEMPCPY_CHKP
:
866 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND
);
869 case BUILT_IN_MEMMOVE_CHKP
:
870 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND
);
873 case BUILT_IN_MEMSET_CHKP
:
874 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND
);
877 case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP
:
878 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
881 case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP
:
882 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
885 case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP
:
886 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
889 case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP
:
890 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
898 fndecl
= chkp_maybe_clone_builtin_fndecl (fndecl
);
904 /* Return no-check version of string function FNCODE. */
906 chkp_get_nochk_fndecl (enum built_in_function fncode
)
908 /* Check if we are allowed to use fast string functions. */
909 if (!flag_chkp_use_nochk_string_functions
)
912 tree fndecl
= NULL_TREE
;
916 case BUILT_IN_MEMCPY_CHKP
:
917 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK
);
920 case BUILT_IN_MEMPCPY_CHKP
:
921 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK
);
924 case BUILT_IN_MEMMOVE_CHKP
:
925 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK
);
928 case BUILT_IN_MEMSET_CHKP
:
929 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK
);
932 case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP
:
933 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
936 case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP
:
937 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
940 case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP
:
941 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
944 case BUILT_IN_CHKP_MEMSET_NOBND_CHKP
:
945 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
953 fndecl
= chkp_maybe_clone_builtin_fndecl (fndecl
);
958 /* Find memcpy, mempcpy, memmove and memset calls, perform
959 checks before call and then call no_chk version of
960 functions. We do it on O2 to enable inlining of these
961 functions during expand.
963 Also try to find memcpy, mempcpy, memmove and memset calls
964 which are known to not write pointers to memory and use
965 faster function versions for them. */
967 chkp_optimize_string_function_calls (void)
971 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
972 fprintf (dump_file
, "Searching for replaceable string function calls...\n");
974 FOR_EACH_BB_FN (bb
, cfun
)
976 gimple_stmt_iterator i
;
978 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
980 gimple stmt
= gsi_stmt (i
);
983 if (gimple_code (stmt
) != GIMPLE_CALL
984 || !gimple_call_with_bounds_p (stmt
))
987 fndecl
= gimple_call_fndecl (stmt
);
989 if (!fndecl
|| DECL_BUILT_IN_CLASS (fndecl
) != BUILT_IN_NORMAL
)
992 if (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMCPY_CHKP
993 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMPCPY_CHKP
994 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMMOVE_CHKP
995 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMSET_CHKP
)
997 tree dst
= gimple_call_arg (stmt
, 0);
998 tree dst_bnd
= gimple_call_arg (stmt
, 1);
999 bool is_memset
= DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMSET_CHKP
;
1000 tree size
= gimple_call_arg (stmt
, is_memset
? 3 : 4);
1002 gimple_stmt_iterator j
;
1003 basic_block check_bb
;
1008 /* We may replace call with corresponding __chkp_*_nobnd
1009 call in case destination pointer base type is not
1011 if (POINTER_TYPE_P (TREE_TYPE (dst
))
1012 && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst
)))
1013 && !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst
))))
1016 = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl
));
1019 fndecl
= fndecl_nobnd
;
1022 fndecl_nochk
= chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl
));
1025 fndecl
= fndecl_nochk
;
1027 if (fndecl
!= gimple_call_fndecl (stmt
))
1029 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1031 fprintf (dump_file
, "Replacing call: ");
1032 print_gimple_stmt (dump_file
, stmt
, 0,
1033 TDF_VOPS
|TDF_MEMSYMS
);
1036 gimple_call_set_fndecl (stmt
, fndecl
);
1038 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1040 fprintf (dump_file
, "With a new call: ");
1041 print_gimple_stmt (dump_file
, stmt
, 0,
1042 TDF_VOPS
|TDF_MEMSYMS
);
1046 /* If there is no nochk version of function then
1047 do nothing. Otherwise insert checks before
1052 /* If size passed to call is known and > 0
1053 then we may insert checks unconditionally. */
1054 size_val
.pol
.create (0);
1055 chkp_collect_value (size
, size_val
);
1056 known
= chkp_is_constant_addr (size_val
, &sign
);
1057 size_val
.pol
.release ();
1059 /* If we are not sure size is not zero then we have
1060 to perform runtime check for size and perform
1061 checks only when size is not zero. */
1064 gimple check
= gimple_build_cond (NE_EXPR
,
1070 /* Split block before string function call. */
1072 check_bb
= insert_cond_bb (bb
, gsi_stmt (i
), check
);
1074 /* Set position for checks. */
1075 j
= gsi_last_bb (check_bb
);
1077 /* The block was splitted and therefore we
1078 need to set iterator to its end. */
1079 i
= gsi_last_bb (bb
);
1081 /* If size is known to be zero then no checks
1082 should be performed. */
1088 size
= size_binop (MINUS_EXPR
, size
, size_one_node
);
1091 tree src
= gimple_call_arg (stmt
, 2);
1092 tree src_bnd
= gimple_call_arg (stmt
, 3);
1094 chkp_check_mem_access (src
, fold_build_pointer_plus (src
, size
),
1095 src_bnd
, j
, gimple_location (stmt
),
1099 chkp_check_mem_access (dst
, fold_build_pointer_plus (dst
, size
),
1100 dst_bnd
, j
, gimple_location (stmt
),
1108 /* Intrumentation pass inserts most of bounds creation code
1109 in the header of the function. We want to move bounds
1110 creation closer to bounds usage to reduce bounds lifetime.
1111 We also try to avoid bounds creation code on paths where
1112 bounds are not used. */
1114 chkp_reduce_bounds_lifetime (void)
1116 basic_block bb
= FALLTHRU_EDGE (ENTRY_BLOCK_PTR_FOR_FN (cfun
))->dest
;
1117 gimple_stmt_iterator i
;
1119 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); )
1121 gimple dom_use
, use_stmt
, stmt
= gsi_stmt (i
);
1124 imm_use_iterator use_iter
;
1125 use_operand_p use_p
;
1127 bool want_move
= false;
1130 if (gimple_code (stmt
) == GIMPLE_CALL
1131 && gimple_call_fndecl (stmt
) == chkp_bndmk_fndecl
)
1134 if (gimple_code (stmt
) == GIMPLE_ASSIGN
1135 && POINTER_BOUNDS_P (gimple_assign_lhs (stmt
))
1136 && gimple_assign_rhs_code (stmt
) == VAR_DECL
)
1145 /* Check we do not increase other values lifetime. */
1146 FOR_EACH_PHI_OR_STMT_USE (use_p
, stmt
, iter
, SSA_OP_USE
)
1148 op
= USE_FROM_PTR (use_p
);
1150 if (TREE_CODE (op
) == SSA_NAME
1151 && gimple_code (SSA_NAME_DEF_STMT (op
)) != GIMPLE_NOP
)
1164 /* Check all usages of bounds. */
1165 if (gimple_code (stmt
) == GIMPLE_CALL
)
1166 op
= gimple_call_lhs (stmt
);
1169 gcc_assert (gimple_code (stmt
) == GIMPLE_ASSIGN
);
1170 op
= gimple_assign_lhs (stmt
);
1176 FOR_EACH_IMM_USE_STMT (use_stmt
, use_iter
, op
)
1178 if (is_gimple_debug (use_stmt
))
1182 dominated_by_p (CDI_DOMINATORS
,
1183 dom_bb
, gimple_bb (use_stmt
)))
1189 dom_bb
= nearest_common_dominator (CDI_DOMINATORS
, dom_bb
,
1190 gimple_bb (use_stmt
));
1193 else if (stmt_dominates_stmt_p (use_stmt
, dom_use
))
1195 else if (!stmt_dominates_stmt_p (dom_use
, use_stmt
)
1196 /* If dom_use and use_stmt are PHI nodes in one BB
1197 then it is OK to keep any of them as dom_use.
1198 stmt_dominates_stmt_p returns 0 for such
1199 combination, so check it here manually. */
1200 && (gimple_code (dom_use
) != GIMPLE_PHI
1201 || gimple_code (use_stmt
) != GIMPLE_PHI
1202 || gimple_bb (use_stmt
) != gimple_bb (dom_use
))
1205 dom_bb
= nearest_common_dominator (CDI_DOMINATORS
,
1206 gimple_bb (use_stmt
),
1207 gimple_bb (dom_use
));
1212 /* In case there is a single use, just move bounds
1213 creation to the use. */
1214 if (dom_use
|| dom_bb
)
1216 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1218 fprintf (dump_file
, "Moving creation of ");
1219 print_generic_expr (dump_file
, op
, 0);
1220 fprintf (dump_file
, " down to its use.\n");
1223 if (dom_use
&& gimple_code (dom_use
) == GIMPLE_PHI
)
1225 dom_bb
= get_immediate_dominator (CDI_DOMINATORS
,
1226 gimple_bb (dom_use
));
1231 || (dom_use
&& gimple_bb (dom_use
) == bb
))
1233 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1234 fprintf (dump_file
, "Cannot move statement bacause there is no "
1235 "suitable dominator block other than entry block.\n");
1243 gimple_stmt_iterator last
= gsi_last_bb (dom_bb
);
1244 if (!gsi_end_p (last
) && stmt_ends_bb_p (gsi_stmt (last
)))
1245 gsi_move_before (&i
, &last
);
1247 gsi_move_after (&i
, &last
);
1251 gimple_stmt_iterator gsi
= gsi_for_stmt (dom_use
);
1252 gsi_move_before (&i
, &gsi
);
1263 /* Initilize checker optimization pass. */
1265 chkp_opt_init (void)
1267 check_infos
.create (0);
1269 calculate_dominance_info (CDI_DOMINATORS
);
1270 calculate_dominance_info (CDI_POST_DOMINATORS
);
1272 /* With LTO constant bounds vars may be not initialized by now.
1273 Get constant bounds vars to handle their assignments during
1275 chkp_get_zero_bounds_var ();
1276 chkp_get_none_bounds_var ();
1279 /* Finalise checker optimization pass. */
1281 chkp_opt_fini (void)
1286 /* Checker optimization pass function. */
1288 chkp_opt_execute (void)
1292 /* This optimization may introduce new checks
1293 and thus we put it before checks search. */
1294 chkp_optimize_string_function_calls ();
1296 chkp_gather_checks_info ();
1298 chkp_remove_excess_intersections ();
1300 chkp_remove_constant_checks ();
1302 chkp_reduce_bounds_lifetime ();
1304 chkp_release_check_info ();
1313 chkp_opt_gate (void)
1315 return chkp_function_instrumented_p (cfun
->decl
)
1316 && (flag_chkp_optimize
> 0
1317 || (flag_chkp_optimize
== -1 && optimize
> 0));
1322 const pass_data pass_data_chkp_opt
=
1324 GIMPLE_PASS
, /* type */
1325 "chkpopt", /* name */
1326 OPTGROUP_NONE
, /* optinfo_flags */
1327 TV_NONE
, /* tv_id */
1328 PROP_ssa
| PROP_cfg
, /* properties_required */
1329 0, /* properties_provided */
1330 0, /* properties_destroyed */
1331 0, /* todo_flags_start */
1333 | TODO_update_ssa
/* todo_flags_finish */
1336 class pass_chkp_opt
: public gimple_opt_pass
1339 pass_chkp_opt (gcc::context
*ctxt
)
1340 : gimple_opt_pass (pass_data_chkp_opt
, ctxt
)
1343 /* opt_pass methods: */
1344 virtual opt_pass
* clone ()
1346 return new pass_chkp_opt (m_ctxt
);
1349 virtual bool gate (function
*)
1351 return chkp_opt_gate ();
1354 virtual unsigned int execute (function
*)
1356 return chkp_opt_execute ();
1359 }; // class pass_chkp_opt
1364 make_pass_chkp_opt (gcc::context
*ctxt
)
1366 return new pass_chkp_opt (ctxt
);