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"
31 #include "fold-const.h"
34 #include "tree-pass.h"
36 #include "tree-ssa-address.h"
38 #include "tree-ssa-loop-niter.h"
39 #include "gimple-pretty-print.h"
40 #include "gimple-iterator.h"
42 #include "gimplify-me.h"
44 #include "insn-config.h"
53 #include "tree-chkp.h"
55 #include "diagnostic.h"
71 vec
<struct pol_item
> pol
;
74 /* Structure to hold check informtation. */
77 /* Type of the check. */
79 /* Address used for the check. */
81 /* Bounds used for the check. */
83 /* Check statement. Can be NULL for removed checks. */
87 /* Structure to hold checks information for BB. */
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
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
)
117 else if (p1
->var
> p2
->var
)
123 /* Find polynomial item in ADDR with var equal to VAR
124 and return its index. Return -1 if item was not
127 chkp_pol_find (address_t
&addr
, tree var
)
130 int right
= addr
.pol
.length () - 1;
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)))
143 else if (addr
.pol
[n
].var
> var
)
152 /* Return constant CST extended to size type. */
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
));
162 /* Add polynomial item CST * VAR to ADDR. */
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
);
172 struct pol_item item
;
176 addr
.pol
.safe_push (item
);
177 addr
.pol
.qsort (&chkp_pol_item_compare
);
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. */
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
);
199 struct pol_item item
;
200 item
.cst
= fold_build2 (MINUS_EXPR
, TREE_TYPE (cst
),
201 integer_zero_node
, cst
);
204 addr
.pol
.safe_push (item
);
205 addr
.pol
.qsort (&chkp_pol_item_compare
);
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. */
219 chkp_add_addr_addr (address_t
&addr
, address_t
&delta
)
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. */
228 chkp_sub_addr_addr (address_t
&addr
, address_t
&delta
)
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. */
237 chkp_mult_addr (address_t
&addr
, tree mult
)
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
249 chkp_is_constant_addr (const address_t
&addr
, int *sign
)
253 if (addr
.pol
.length () == 0)
255 else if (addr
.pol
.length () > 1)
257 else if (addr
.pol
[0].var
)
259 else if (integer_zerop (addr
.pol
[0].cst
))
261 else if (tree_int_cst_sign_bit (addr
.pol
[0].cst
))
269 /* Dump ADDR into dump_file. */
271 chkp_print_addr (const address_t
&addr
)
274 for (n
= 0; n
< addr
.pol
.length (); n
++)
277 fprintf (dump_file
, " + ");
279 if (addr
.pol
[n
].var
== NULL_TREE
)
280 print_generic_expr (dump_file
, addr
.pol
[n
].cst
, 0);
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. */
297 chkp_collect_addr_value (tree ptr
, address_t
&res
)
299 tree obj
= TREE_OPERAND (ptr
, 0);
302 switch (TREE_CODE (obj
))
305 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
309 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
311 chkp_collect_value (TREE_OPERAND (obj
, 1), addr
);
312 chkp_add_addr_addr (res
, addr
);
317 chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj
, 0)), res
);
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
);
327 tree str
= TREE_OPERAND (obj
, 0);
328 tree field
= TREE_OPERAND (obj
, 1);
329 chkp_collect_value (build_fold_addr_expr (str
), res
);
331 chkp_collect_value (component_ref_field_offset (obj
), addr
);
332 chkp_add_addr_addr (res
, addr
);
334 if (DECL_FIELD_BIT_OFFSET (field
))
337 chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR
, size_type_node
,
338 DECL_FIELD_BIT_OFFSET (field
),
339 size_int (BITS_PER_UNIT
)),
341 chkp_add_addr_addr (res
, addr
);
348 chkp_add_addr_item (res
, integer_one_node
, ptr
);
353 /* Compute value of PTR and put it into address RES. */
355 chkp_collect_value (tree ptr
, address_t
&res
)
358 enum gimple_code code
;
359 enum tree_code rhs_code
;
363 if (TREE_CODE (ptr
) == INTEGER_CST
)
365 chkp_add_addr_item (res
, ptr
, NULL
);
368 else if (TREE_CODE (ptr
) == ADDR_EXPR
)
370 chkp_collect_addr_value (ptr
, res
);
373 else if (TREE_CODE (ptr
) != SSA_NAME
)
375 chkp_add_addr_item (res
, integer_one_node
, ptr
);
379 /* Now we handle the case when polynomial is computed
381 def_stmt
= SSA_NAME_DEF_STMT (ptr
);
382 code
= gimple_code (def_stmt
);
384 /* Currently we do not walk through statements other
386 if (code
!= GIMPLE_ASSIGN
)
388 chkp_add_addr_item (res
, integer_one_node
, ptr
);
392 rhs_code
= gimple_assign_rhs_code (def_stmt
);
393 rhs1
= gimple_assign_rhs1 (def_stmt
);
400 chkp_collect_value (rhs1
, res
);
404 case POINTER_PLUS_EXPR
:
405 chkp_collect_value (rhs1
, res
);
407 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
408 chkp_add_addr_addr (res
, addr
);
413 chkp_collect_value (rhs1
, res
);
415 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
416 chkp_sub_addr_addr (res
, addr
);
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
);
434 chkp_add_addr_item (res
, integer_one_node
, ptr
);
438 chkp_add_addr_item (res
, integer_one_node
, ptr
);
443 /* Fill check_info structure *CI with information about
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
453 : CHECK_UPPER_BOUND
);
457 /* Release structures holding check information
458 for current function. */
460 chkp_release_check_info (void)
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. */
480 chkp_init_check_info (void)
482 struct bb_checks empty_bbc
;
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
500 chkp_gather_checks_info (void)
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
)
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. */
551 chkp_get_check_result (struct check_info
*ci
, tree bounds
)
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");
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
)
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");
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");
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
);
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");
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
)
633 && !chkp_variable_size_type (TREE_TYPE (var
)))
634 size
= DECL_SIZE_UNIT (var
);
637 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
638 fprintf (dump_file
, " result: cannot compute bounds\n");
644 gcc_assert (TREE_CODE (var
) == STRING_CST
);
645 size
= build_int_cst (size_type_node
,
646 TREE_STRING_LENGTH (var
));
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
);
659 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
660 fprintf (dump_file
, " result: cannot compute bounds\n");
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");
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");
691 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
692 fprintf (dump_file
, " result: always fail\n");
697 bound_val
.pol
.release ();
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. */
706 chkp_remove_check_if_pass (struct check_info
*ci
)
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
);
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
);
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. */
749 chkp_use_outer_bounds_if_possible (struct check_info
*ci
)
752 tree bnd1
, bnd2
, bnd_res
= NULL
;
753 int check_res1
, check_res2
;
755 if (TREE_CODE (ci
->bounds
) != SSA_NAME
)
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
)
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
);
780 else if (check_res1
== -1)
782 else if (check_res2
== 1)
784 else if (check_res2
== -1)
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. */
810 chkp_remove_excess_intersections (void)
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
];
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. */
831 chkp_remove_constant_checks (void)
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
];
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. */
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
)
858 tree fndecl
= NULL_TREE
;
862 case BUILT_IN_MEMCPY_CHKP
:
863 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND
);
866 case BUILT_IN_MEMPCPY_CHKP
:
867 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND
);
870 case BUILT_IN_MEMMOVE_CHKP
:
871 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND
);
874 case BUILT_IN_MEMSET_CHKP
:
875 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND
);
878 case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP
:
879 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
882 case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP
:
883 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
886 case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP
:
887 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
890 case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP
:
891 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
899 fndecl
= chkp_maybe_clone_builtin_fndecl (fndecl
);
905 /* Return no-check version of string function FNCODE. */
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
)
913 tree fndecl
= NULL_TREE
;
917 case BUILT_IN_MEMCPY_CHKP
:
918 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK
);
921 case BUILT_IN_MEMPCPY_CHKP
:
922 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK
);
925 case BUILT_IN_MEMMOVE_CHKP
:
926 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK
);
929 case BUILT_IN_MEMSET_CHKP
:
930 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK
);
933 case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP
:
934 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
937 case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP
:
938 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
941 case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP
:
942 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
945 case BUILT_IN_CHKP_MEMSET_NOBND_CHKP
:
946 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
954 fndecl
= chkp_maybe_clone_builtin_fndecl (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. */
968 chkp_optimize_string_function_calls (void)
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
);
984 if (gimple_code (stmt
) != GIMPLE_CALL
985 || !gimple_call_with_bounds_p (stmt
))
988 fndecl
= gimple_call_fndecl (stmt
);
990 if (!fndecl
|| DECL_BUILT_IN_CLASS (fndecl
) != BUILT_IN_NORMAL
)
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);
1003 gimple_stmt_iterator j
;
1004 basic_block check_bb
;
1009 /* We may replace call with corresponding __chkp_*_nobnd
1010 call in case destination pointer base type is not
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
))))
1017 = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl
));
1020 fndecl
= fndecl_nobnd
;
1023 fndecl_nochk
= chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl
));
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
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. */
1065 gimple check
= gimple_build_cond (NE_EXPR
,
1071 /* Split block before string function call. */
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. */
1089 size
= size_binop (MINUS_EXPR
, size
, size_one_node
);
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
),
1100 chkp_check_mem_access (dst
, fold_build_pointer_plus (dst
, size
),
1101 dst_bnd
, j
, gimple_location (stmt
),
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. */
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
);
1125 imm_use_iterator use_iter
;
1126 use_operand_p use_p
;
1128 bool want_move
= false;
1131 if (gimple_code (stmt
) == GIMPLE_CALL
1132 && gimple_call_fndecl (stmt
) == chkp_bndmk_fndecl
)
1135 if (gimple_code (stmt
) == GIMPLE_ASSIGN
1136 && POINTER_BOUNDS_P (gimple_assign_lhs (stmt
))
1137 && gimple_assign_rhs_code (stmt
) == VAR_DECL
)
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
)
1165 /* Check all usages of bounds. */
1166 if (gimple_code (stmt
) == GIMPLE_CALL
)
1167 op
= gimple_call_lhs (stmt
);
1170 gcc_assert (gimple_code (stmt
) == GIMPLE_ASSIGN
);
1171 op
= gimple_assign_lhs (stmt
);
1177 FOR_EACH_IMM_USE_STMT (use_stmt
, use_iter
, op
)
1179 if (is_gimple_debug (use_stmt
))
1183 dominated_by_p (CDI_DOMINATORS
,
1184 dom_bb
, gimple_bb (use_stmt
)))
1190 dom_bb
= nearest_common_dominator (CDI_DOMINATORS
, dom_bb
,
1191 gimple_bb (use_stmt
));
1194 else if (stmt_dominates_stmt_p (use_stmt
, dom_use
))
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
));
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
));
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");
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
);
1248 gsi_move_after (&i
, &last
);
1252 gimple_stmt_iterator gsi
= gsi_for_stmt (dom_use
);
1253 gsi_move_before (&i
, &gsi
);
1264 /* Initilize checker optimization pass. */
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
1276 chkp_get_zero_bounds_var ();
1277 chkp_get_none_bounds_var ();
1280 /* Finalise checker optimization pass. */
1282 chkp_opt_fini (void)
1286 free_dominance_info (CDI_POST_DOMINATORS
);
1289 /* Checker optimization pass function. */
1291 chkp_opt_execute (void)
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 ();
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));
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 */
1336 | TODO_update_ssa
/* todo_flags_finish */
1339 class pass_chkp_opt
: public gimple_opt_pass
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
1367 make_pass_chkp_opt (gcc::context
*ctxt
)
1369 return new pass_chkp_opt (ctxt
);