1 /* Pointer Bounds Checker optimization pass.
2 Copyright (C) 2014-2017 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 "tree-pass.h"
31 #include "gimple-pretty-print.h"
32 #include "diagnostic.h"
33 #include "fold-const.h"
35 #include "tree-ssa-loop-niter.h"
36 #include "gimple-iterator.h"
37 #include "tree-chkp.h"
54 vec
<struct pol_item
> pol
;
57 /* Structure to hold check informtation. */
60 /* Type of the check. */
62 /* Address used for the check. */
64 /* Bounds used for the check. */
66 /* Check statement. Can be NULL for removed checks. */
70 /* Structure to hold checks information for BB. */
73 vec
<struct check_info
, va_heap
, vl_ptr
> checks
;
76 static void chkp_collect_value (tree ssa_name
, address_t
&res
);
78 #define chkp_bndmk_fndecl \
79 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
80 #define chkp_intersect_fndecl \
81 (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
82 #define chkp_checkl_fndecl \
83 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
84 #define chkp_checku_fndecl \
85 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
87 static vec
<struct bb_checks
, va_heap
, vl_ptr
> check_infos
;
89 /* Comparator for pol_item structures I1 and I2 to be used
90 to find items with equal var. Also used for polynomial
93 chkp_pol_item_compare (const void *i1
, const void *i2
)
95 const struct pol_item
*p1
= (const struct pol_item
*)i1
;
96 const struct pol_item
*p2
= (const struct pol_item
*)i2
;
98 if (p1
->var
== p2
->var
)
100 else if (p1
->var
> p2
->var
)
106 /* Find polynomial item in ADDR with var equal to VAR
107 and return its index. Return -1 if item was not
110 chkp_pol_find (address_t
&addr
, tree var
)
113 int right
= addr
.pol
.length () - 1;
116 while (right
>= left
)
118 n
= (left
+ right
) / 2;
120 if (addr
.pol
[n
].var
== var
121 || (var
&& addr
.pol
[n
].var
122 && TREE_CODE (var
) == ADDR_EXPR
123 && TREE_CODE (addr
.pol
[n
].var
) == ADDR_EXPR
124 && TREE_OPERAND (var
, 0) == TREE_OPERAND (addr
.pol
[n
].var
, 0)))
126 else if (addr
.pol
[n
].var
> var
)
135 /* Return constant CST extended to size type. */
137 chkp_extend_const (tree cst
)
139 if (TYPE_PRECISION (TREE_TYPE (cst
)) < TYPE_PRECISION (size_type_node
))
140 return build_int_cst_type (size_type_node
, tree_to_shwi (cst
));
145 /* Add polynomial item CST * VAR to ADDR. */
147 chkp_add_addr_item (address_t
&addr
, tree cst
, tree var
)
149 int n
= chkp_pol_find (addr
, var
);
151 cst
= chkp_extend_const (cst
);
155 struct pol_item item
;
159 addr
.pol
.safe_push (item
);
160 addr
.pol
.qsort (&chkp_pol_item_compare
);
164 addr
.pol
[n
].cst
= fold_build2 (PLUS_EXPR
, TREE_TYPE (addr
.pol
[n
].cst
),
165 addr
.pol
[n
].cst
, cst
);
166 if (TREE_CODE (addr
.pol
[n
].cst
) == INTEGER_CST
167 && integer_zerop (addr
.pol
[n
].cst
))
168 addr
.pol
.ordered_remove (n
);
172 /* Subtract polynomial item CST * VAR from ADDR. */
174 chkp_sub_addr_item (address_t
&addr
, tree cst
, tree var
)
176 int n
= chkp_pol_find (addr
, var
);
178 cst
= chkp_extend_const (cst
);
182 struct pol_item item
;
183 item
.cst
= fold_build2 (MINUS_EXPR
, TREE_TYPE (cst
),
184 integer_zero_node
, cst
);
187 addr
.pol
.safe_push (item
);
188 addr
.pol
.qsort (&chkp_pol_item_compare
);
192 addr
.pol
[n
].cst
= fold_build2 (MINUS_EXPR
, TREE_TYPE (addr
.pol
[n
].cst
),
193 addr
.pol
[n
].cst
, cst
);
194 if (TREE_CODE (addr
.pol
[n
].cst
) == INTEGER_CST
195 && integer_zerop (addr
.pol
[n
].cst
))
196 addr
.pol
.ordered_remove (n
);
200 /* Add address DELTA to ADDR. */
202 chkp_add_addr_addr (address_t
&addr
, address_t
&delta
)
205 for (i
= 0; i
< delta
.pol
.length (); i
++)
206 chkp_add_addr_item (addr
, delta
.pol
[i
].cst
, delta
.pol
[i
].var
);
209 /* Subtract address DELTA from ADDR. */
211 chkp_sub_addr_addr (address_t
&addr
, address_t
&delta
)
214 for (i
= 0; i
< delta
.pol
.length (); i
++)
215 chkp_sub_addr_item (addr
, delta
.pol
[i
].cst
, delta
.pol
[i
].var
);
218 /* Mutiply address ADDR by integer constant MULT. */
220 chkp_mult_addr (address_t
&addr
, tree mult
)
223 for (i
= 0; i
< addr
.pol
.length (); i
++)
224 addr
.pol
[i
].cst
= fold_build2 (MULT_EXPR
, TREE_TYPE (addr
.pol
[i
].cst
),
225 addr
.pol
[i
].cst
, mult
);
228 /* Return 1 if we may prove ADDR has a constant value with
229 determined sign, which is put into *SIGN. Otherwise
232 chkp_is_constant_addr (const address_t
&addr
, int *sign
)
236 if (addr
.pol
.length () == 0)
238 else if (addr
.pol
.length () > 1)
240 else if (addr
.pol
[0].var
)
242 else if (TREE_CODE (addr
.pol
[0].cst
) != INTEGER_CST
)
244 else if (integer_zerop (addr
.pol
[0].cst
))
246 else if (tree_int_cst_sign_bit (addr
.pol
[0].cst
))
254 /* Dump ADDR into dump_file. */
256 chkp_print_addr (const address_t
&addr
)
259 for (n
= 0; n
< addr
.pol
.length (); n
++)
262 fprintf (dump_file
, " + ");
264 if (addr
.pol
[n
].var
== NULL_TREE
)
265 print_generic_expr (dump_file
, addr
.pol
[n
].cst
);
268 if (TREE_CODE (addr
.pol
[n
].cst
) != INTEGER_CST
269 || !integer_onep (addr
.pol
[n
].cst
))
271 print_generic_expr (dump_file
, addr
.pol
[n
].cst
);
272 fprintf (dump_file
, " * ");
274 print_generic_expr (dump_file
, addr
.pol
[n
].var
);
279 /* Compute value of PTR and put it into address RES.
280 PTR has to be ADDR_EXPR. */
282 chkp_collect_addr_value (tree ptr
, address_t
&res
)
284 tree obj
= TREE_OPERAND (ptr
, 0);
287 switch (TREE_CODE (obj
))
290 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
294 chkp_collect_value (TREE_OPERAND (obj
, 0), res
);
296 chkp_collect_value (TREE_OPERAND (obj
, 1), addr
);
297 chkp_add_addr_addr (res
, addr
);
302 chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj
, 0)), res
);
304 chkp_collect_value (TREE_OPERAND (obj
, 1), addr
);
305 chkp_mult_addr (addr
, array_ref_element_size (obj
));
306 chkp_add_addr_addr (res
, addr
);
312 tree str
= TREE_OPERAND (obj
, 0);
313 tree field
= TREE_OPERAND (obj
, 1);
314 chkp_collect_value (build_fold_addr_expr (str
), res
);
316 chkp_collect_value (component_ref_field_offset (obj
), addr
);
317 chkp_add_addr_addr (res
, addr
);
319 if (DECL_FIELD_BIT_OFFSET (field
))
322 chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR
, size_type_node
,
323 DECL_FIELD_BIT_OFFSET (field
),
324 size_int (BITS_PER_UNIT
)),
326 chkp_add_addr_addr (res
, addr
);
333 chkp_add_addr_item (res
, integer_one_node
, ptr
);
338 /* Compute value of PTR and put it into address RES. */
340 chkp_collect_value (tree ptr
, address_t
&res
)
343 enum gimple_code code
;
344 enum tree_code rhs_code
;
348 if (TREE_CODE (ptr
) == INTEGER_CST
)
350 chkp_add_addr_item (res
, ptr
, NULL
);
353 else if (TREE_CODE (ptr
) == ADDR_EXPR
)
355 chkp_collect_addr_value (ptr
, res
);
358 else if (TREE_CODE (ptr
) != SSA_NAME
)
360 chkp_add_addr_item (res
, integer_one_node
, ptr
);
364 /* Now we handle the case when polynomial is computed
366 def_stmt
= SSA_NAME_DEF_STMT (ptr
);
367 code
= gimple_code (def_stmt
);
369 /* Currently we do not walk through statements other
371 if (code
!= GIMPLE_ASSIGN
)
373 chkp_add_addr_item (res
, integer_one_node
, ptr
);
377 rhs_code
= gimple_assign_rhs_code (def_stmt
);
378 rhs1
= gimple_assign_rhs1 (def_stmt
);
385 chkp_collect_value (rhs1
, res
);
389 case POINTER_PLUS_EXPR
:
390 chkp_collect_value (rhs1
, res
);
392 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
393 chkp_add_addr_addr (res
, addr
);
398 chkp_collect_value (rhs1
, res
);
400 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), addr
);
401 chkp_sub_addr_addr (res
, addr
);
406 if (TREE_CODE (rhs1
) == SSA_NAME
407 && TREE_CODE (gimple_assign_rhs2 (def_stmt
)) == INTEGER_CST
)
409 chkp_collect_value (rhs1
, res
);
410 chkp_mult_addr (res
, gimple_assign_rhs2 (def_stmt
));
412 else if (TREE_CODE (gimple_assign_rhs2 (def_stmt
)) == SSA_NAME
413 && TREE_CODE (rhs1
) == INTEGER_CST
)
415 chkp_collect_value (gimple_assign_rhs2 (def_stmt
), res
);
416 chkp_mult_addr (res
, rhs1
);
419 chkp_add_addr_item (res
, integer_one_node
, ptr
);
423 chkp_add_addr_item (res
, integer_one_node
, ptr
);
428 /* Fill check_info structure *CI with information about
431 chkp_fill_check_info (gimple
*stmt
, struct check_info
*ci
)
433 ci
->addr
.pol
.create (0);
434 ci
->bounds
= gimple_call_arg (stmt
, 1);
435 chkp_collect_value (gimple_call_arg (stmt
, 0), ci
->addr
);
436 ci
->type
= (gimple_call_fndecl (stmt
) == chkp_checkl_fndecl
438 : CHECK_UPPER_BOUND
);
442 /* Release structures holding check information
443 for current function. */
445 chkp_release_check_info (void)
449 if (check_infos
.exists ())
451 for (n
= 0; n
< check_infos
.length (); n
++)
453 for (m
= 0; m
< check_infos
[n
].checks
.length (); m
++)
454 if (check_infos
[n
].checks
[m
].addr
.pol
.exists ())
455 check_infos
[n
].checks
[m
].addr
.pol
.release ();
456 check_infos
[n
].checks
.release ();
458 check_infos
.release ();
462 /* Create structures to hold check information
463 for current function. */
465 chkp_init_check_info (void)
467 struct bb_checks empty_bbc
;
470 empty_bbc
.checks
= vNULL
;
472 chkp_release_check_info ();
474 check_infos
.create (last_basic_block_for_fn (cfun
));
475 for (n
= 0; n
< last_basic_block_for_fn (cfun
); n
++)
477 check_infos
.safe_push (empty_bbc
);
478 check_infos
.last ().checks
.create (0);
482 /* Find all checks in current function and store info about them
485 chkp_gather_checks_info (void)
488 gimple_stmt_iterator i
;
490 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
491 fprintf (dump_file
, "Gathering information about checks...\n");
493 chkp_init_check_info ();
495 FOR_EACH_BB_FN (bb
, cfun
)
497 struct bb_checks
*bbc
= &check_infos
[bb
->index
];
499 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
500 fprintf (dump_file
, "Searching checks in BB%d...\n", bb
->index
);
502 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
504 gimple
*stmt
= gsi_stmt (i
);
506 if (gimple_code (stmt
) != GIMPLE_CALL
)
509 if (gimple_call_fndecl (stmt
) == chkp_checkl_fndecl
510 || gimple_call_fndecl (stmt
) == chkp_checku_fndecl
)
512 struct check_info ci
;
514 chkp_fill_check_info (stmt
, &ci
);
515 bbc
->checks
.safe_push (ci
);
517 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
519 fprintf (dump_file
, "Adding check information:\n");
520 fprintf (dump_file
, " bounds: ");
521 print_generic_expr (dump_file
, ci
.bounds
);
522 fprintf (dump_file
, "\n address: ");
523 chkp_print_addr (ci
.addr
);
524 fprintf (dump_file
, "\n check: ");
525 print_gimple_stmt (dump_file
, stmt
, 0);
532 /* Return 1 if check CI against BOUNDS always pass,
533 -1 if check CI against BOUNDS always fails and
534 0 if we cannot compute check result. */
536 chkp_get_check_result (struct check_info
*ci
, tree bounds
)
542 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
544 fprintf (dump_file
, "Trying to compute result of the check\n");
545 fprintf (dump_file
, " check: ");
546 print_gimple_stmt (dump_file
, ci
->stmt
, 0);
547 fprintf (dump_file
, " address: ");
548 chkp_print_addr (ci
->addr
);
549 fprintf (dump_file
, "\n bounds: ");
550 print_generic_expr (dump_file
, bounds
);
551 fprintf (dump_file
, "\n");
554 if (TREE_CODE (bounds
) != SSA_NAME
)
556 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
557 fprintf (dump_file
, " result: bounds tree code is not ssa_name\n");
561 bnd_def
= SSA_NAME_DEF_STMT (bounds
);
562 /* Currently we handle cases when bounds are result of bndmk
563 or loaded static bounds var. */
564 if (gimple_code (bnd_def
) == GIMPLE_CALL
565 && gimple_call_fndecl (bnd_def
) == chkp_bndmk_fndecl
)
567 bound_val
.pol
.create (0);
568 chkp_collect_value (gimple_call_arg (bnd_def
, 0), bound_val
);
569 if (ci
->type
== CHECK_UPPER_BOUND
)
572 size_val
.pol
.create (0);
573 chkp_collect_value (gimple_call_arg (bnd_def
, 1), size_val
);
574 chkp_add_addr_addr (bound_val
, size_val
);
575 size_val
.pol
.release ();
576 chkp_add_addr_item (bound_val
, integer_minus_one_node
, NULL
);
579 else if (gimple_code (bnd_def
) == GIMPLE_ASSIGN
580 && gimple_assign_rhs1 (bnd_def
) == chkp_get_zero_bounds_var ())
582 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
583 fprintf (dump_file
, " result: always pass with zero bounds\n");
586 else if (gimple_code (bnd_def
) == GIMPLE_ASSIGN
587 && gimple_assign_rhs1 (bnd_def
) == chkp_get_none_bounds_var ())
589 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
590 fprintf (dump_file
, " result: always fails with none bounds\n");
593 else if (gimple_code (bnd_def
) == GIMPLE_ASSIGN
594 && TREE_CODE (gimple_assign_rhs1 (bnd_def
)) == VAR_DECL
)
596 tree bnd_var
= gimple_assign_rhs1 (bnd_def
);
600 if (!DECL_INITIAL (bnd_var
)
601 || DECL_INITIAL (bnd_var
) == error_mark_node
)
603 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
604 fprintf (dump_file
, " result: cannot compute bounds\n");
608 gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var
)) == ADDR_EXPR
);
609 var
= TREE_OPERAND (DECL_INITIAL (bnd_var
), 0);
611 bound_val
.pol
.create (0);
612 chkp_collect_value (DECL_INITIAL (bnd_var
), bound_val
);
613 if (ci
->type
== CHECK_UPPER_BOUND
)
618 && !chkp_variable_size_type (TREE_TYPE (var
)))
619 size
= DECL_SIZE_UNIT (var
);
622 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
623 fprintf (dump_file
, " result: cannot compute bounds\n");
629 gcc_assert (TREE_CODE (var
) == STRING_CST
);
630 size
= build_int_cst (size_type_node
,
631 TREE_STRING_LENGTH (var
));
635 size_val
.pol
.create (0);
636 chkp_collect_value (size
, size_val
);
637 chkp_add_addr_addr (bound_val
, size_val
);
638 size_val
.pol
.release ();
639 chkp_add_addr_item (bound_val
, integer_minus_one_node
, NULL
);
644 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
645 fprintf (dump_file
, " result: cannot compute bounds\n");
649 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
651 fprintf (dump_file
, " bound value: ");
652 chkp_print_addr (bound_val
);
653 fprintf (dump_file
, "\n");
656 chkp_sub_addr_addr (bound_val
, ci
->addr
);
658 if (!chkp_is_constant_addr (bound_val
, &sign
))
660 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
661 fprintf (dump_file
, " result: cannot compute result\n");
666 || (ci
->type
== CHECK_UPPER_BOUND
&& sign
> 0)
667 || (ci
->type
== CHECK_LOWER_BOUND
&& sign
< 0))
669 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
670 fprintf (dump_file
, " result: always pass\n");
676 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
677 fprintf (dump_file
, " result: always fail\n");
682 bound_val
.pol
.release ();
687 /* Try to compare bounds value and address value
688 used in the check CI. If we can prove that check
689 always pass then remove it. */
691 chkp_remove_check_if_pass (struct check_info
*ci
)
695 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
697 fprintf (dump_file
, "Trying to remove check: ");
698 print_gimple_stmt (dump_file
, ci
->stmt
, 0);
701 result
= chkp_get_check_result (ci
, ci
->bounds
);
705 gimple_stmt_iterator i
= gsi_for_stmt (ci
->stmt
);
707 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
708 fprintf (dump_file
, " action: delete check (always pass)\n");
710 gsi_remove (&i
, true);
711 unlink_stmt_vdef (ci
->stmt
);
712 release_defs (ci
->stmt
);
715 else if (result
== -1)
717 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
718 fprintf (dump_file
, " action: keep check (always fail)\n");
719 warning_at (gimple_location (ci
->stmt
), OPT_Wchkp
,
720 "memory access check always fail");
722 else if (result
== 0)
724 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
725 fprintf (dump_file
, " action: keep check (cannot compute result)\n");
729 /* For bounds used in CI check if bounds are produced by
730 intersection and we may use outer bounds instead. If
731 transformation is possible then fix check statement and
732 recompute its info. */
734 chkp_use_outer_bounds_if_possible (struct check_info
*ci
)
737 tree bnd1
, bnd2
, bnd_res
= NULL
;
738 int check_res1
, check_res2
;
740 if (TREE_CODE (ci
->bounds
) != SSA_NAME
)
743 bnd_def
= SSA_NAME_DEF_STMT (ci
->bounds
);
744 if (gimple_code (bnd_def
) != GIMPLE_CALL
745 || gimple_call_fndecl (bnd_def
) != chkp_intersect_fndecl
)
748 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
750 fprintf (dump_file
, "Check if bounds intersection is redundant: \n");
751 fprintf (dump_file
, " check: ");
752 print_gimple_stmt (dump_file
, ci
->stmt
, 0);
753 fprintf (dump_file
, " intersection: ");
754 print_gimple_stmt (dump_file
, bnd_def
, 0);
755 fprintf (dump_file
, "\n");
758 bnd1
= gimple_call_arg (bnd_def
, 0);
759 bnd2
= gimple_call_arg (bnd_def
, 1);
761 check_res1
= chkp_get_check_result (ci
, bnd1
);
762 check_res2
= chkp_get_check_result (ci
, bnd2
);
765 else if (check_res1
== -1)
767 else if (check_res2
== 1)
769 else if (check_res2
== -1)
774 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
776 fprintf (dump_file
, " action: use ");
777 print_generic_expr (dump_file
, bnd2
);
778 fprintf (dump_file
, " instead of ");
779 print_generic_expr (dump_file
, ci
->bounds
);
780 fprintf (dump_file
, "\n");
783 ci
->bounds
= bnd_res
;
784 gimple_call_set_arg (ci
->stmt
, 1, bnd_res
);
785 update_stmt (ci
->stmt
);
786 chkp_fill_check_info (ci
->stmt
, ci
);
790 /* Try to find checks whose bounds were produced by intersection
791 which does not affect check result. In such check outer bounds
792 are used instead. It allows to remove excess intersections
793 and helps to compare checks. */
795 chkp_remove_excess_intersections (void)
799 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
800 fprintf (dump_file
, "Searching for redundant bounds intersections...\n");
802 FOR_EACH_BB_FN (bb
, cfun
)
804 struct bb_checks
*bbc
= &check_infos
[bb
->index
];
807 /* Iterate through all found checks in BB. */
808 for (no
= 0; no
< bbc
->checks
.length (); no
++)
809 if (bbc
->checks
[no
].stmt
)
810 chkp_use_outer_bounds_if_possible (&bbc
->checks
[no
]);
814 /* Try to remove all checks which are known to alwyas pass. */
816 chkp_remove_constant_checks (void)
820 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
821 fprintf (dump_file
, "Searching for redundant checks...\n");
823 FOR_EACH_BB_FN (bb
, cfun
)
825 struct bb_checks
*bbc
= &check_infos
[bb
->index
];
828 /* Iterate through all found checks in BB. */
829 for (no
= 0; no
< bbc
->checks
.length (); no
++)
830 if (bbc
->checks
[no
].stmt
)
831 chkp_remove_check_if_pass (&bbc
->checks
[no
]);
835 /* Return fast version of string function FNCODE. */
837 chkp_get_nobnd_fndecl (enum built_in_function fncode
)
839 /* Check if we are allowed to use fast string functions. */
840 if (!flag_chkp_use_fast_string_functions
)
843 tree fndecl
= NULL_TREE
;
847 case BUILT_IN_MEMCPY_CHKP
:
848 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND
);
851 case BUILT_IN_MEMPCPY_CHKP
:
852 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND
);
855 case BUILT_IN_MEMMOVE_CHKP
:
856 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND
);
859 case BUILT_IN_MEMSET_CHKP
:
860 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND
);
863 case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP
:
864 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
867 case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP
:
868 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
871 case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP
:
872 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
875 case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP
:
876 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
884 fndecl
= chkp_maybe_clone_builtin_fndecl (fndecl
);
890 /* Return no-check version of string function FNCODE. */
892 chkp_get_nochk_fndecl (enum built_in_function fncode
)
894 /* Check if we are allowed to use fast string functions. */
895 if (!flag_chkp_use_nochk_string_functions
)
898 tree fndecl
= NULL_TREE
;
902 case BUILT_IN_MEMCPY_CHKP
:
903 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK
);
906 case BUILT_IN_MEMPCPY_CHKP
:
907 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK
);
910 case BUILT_IN_MEMMOVE_CHKP
:
911 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK
);
914 case BUILT_IN_MEMSET_CHKP
:
915 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK
);
918 case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP
:
919 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
);
922 case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP
:
923 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK
);
926 case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP
:
927 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK
);
930 case BUILT_IN_CHKP_MEMSET_NOBND_CHKP
:
931 fndecl
= builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK
);
939 fndecl
= chkp_maybe_clone_builtin_fndecl (fndecl
);
944 /* Find memcpy, mempcpy, memmove and memset calls, perform
945 checks before call and then call no_chk version of
946 functions. We do it on O2 to enable inlining of these
947 functions during expand.
949 Also try to find memcpy, mempcpy, memmove and memset calls
950 which are known to not write pointers to memory and use
951 faster function versions for them. */
953 chkp_optimize_string_function_calls (void)
957 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
958 fprintf (dump_file
, "Searching for replaceable string function calls...\n");
960 FOR_EACH_BB_FN (bb
, cfun
)
962 gimple_stmt_iterator i
;
964 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
966 gimple
*stmt
= gsi_stmt (i
);
969 if (!is_gimple_call (stmt
)
970 || !gimple_call_with_bounds_p (stmt
)
971 || !gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
974 fndecl
= gimple_call_fndecl (stmt
);
975 if (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMCPY_CHKP
976 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMPCPY_CHKP
977 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMMOVE_CHKP
978 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMSET_CHKP
)
980 tree dst
= gimple_call_arg (stmt
, 0);
981 tree dst_bnd
= gimple_call_arg (stmt
, 1);
982 bool is_memset
= DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_MEMSET_CHKP
;
983 tree size
= gimple_call_arg (stmt
, is_memset
? 3 : 4);
985 gimple_stmt_iterator j
;
986 basic_block check_bb
;
991 /* We may replace call with corresponding __chkp_*_nobnd
992 call in case destination pointer base type is not
994 if (POINTER_TYPE_P (TREE_TYPE (dst
))
995 && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (dst
)))
996 && !chkp_type_has_pointer (TREE_TYPE (TREE_TYPE (dst
))))
999 = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl
));
1002 fndecl
= fndecl_nobnd
;
1005 fndecl_nochk
= chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl
));
1008 fndecl
= fndecl_nochk
;
1010 if (fndecl
!= gimple_call_fndecl (stmt
))
1012 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1014 fprintf (dump_file
, "Replacing call: ");
1015 print_gimple_stmt (dump_file
, stmt
, 0,
1016 TDF_VOPS
|TDF_MEMSYMS
);
1019 gimple_call_set_fndecl (stmt
, fndecl
);
1021 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1023 fprintf (dump_file
, "With a new call: ");
1024 print_gimple_stmt (dump_file
, stmt
, 0,
1025 TDF_VOPS
|TDF_MEMSYMS
);
1029 /* If there is no nochk version of function then
1030 do nothing. Otherwise insert checks before
1035 /* If size passed to call is known and > 0
1036 then we may insert checks unconditionally. */
1037 size_val
.pol
.create (0);
1038 chkp_collect_value (size
, size_val
);
1039 known
= chkp_is_constant_addr (size_val
, &sign
);
1040 size_val
.pol
.release ();
1042 /* If we are not sure size is not zero then we have
1043 to perform runtime check for size and perform
1044 checks only when size is not zero. */
1047 gimple
*check
= gimple_build_cond (NE_EXPR
,
1053 /* Split block before string function call. */
1055 check_bb
= insert_cond_bb (bb
, gsi_stmt (i
), check
);
1057 /* Set position for checks. */
1058 j
= gsi_last_bb (check_bb
);
1060 /* The block was splitted and therefore we
1061 need to set iterator to its end. */
1062 i
= gsi_last_bb (bb
);
1064 /* If size is known to be zero then no checks
1065 should be performed. */
1071 size
= size_binop (MINUS_EXPR
, size
, size_one_node
);
1074 tree src
= gimple_call_arg (stmt
, 2);
1075 tree src_bnd
= gimple_call_arg (stmt
, 3);
1077 chkp_check_mem_access (src
, fold_build_pointer_plus (src
, size
),
1078 src_bnd
, j
, gimple_location (stmt
),
1082 chkp_check_mem_access (dst
, fold_build_pointer_plus (dst
, size
),
1083 dst_bnd
, j
, gimple_location (stmt
),
1091 /* Intrumentation pass inserts most of bounds creation code
1092 in the header of the function. We want to move bounds
1093 creation closer to bounds usage to reduce bounds lifetime.
1094 We also try to avoid bounds creation code on paths where
1095 bounds are not used. */
1097 chkp_reduce_bounds_lifetime (void)
1099 basic_block bb
= FALLTHRU_EDGE (ENTRY_BLOCK_PTR_FOR_FN (cfun
))->dest
;
1100 gimple_stmt_iterator i
;
1102 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); )
1104 gimple
*dom_use
, *use_stmt
, *stmt
= gsi_stmt (i
);
1107 imm_use_iterator use_iter
;
1108 use_operand_p use_p
;
1110 bool want_move
= false;
1113 if (gimple_code (stmt
) == GIMPLE_CALL
1114 && gimple_call_fndecl (stmt
) == chkp_bndmk_fndecl
)
1117 if (gimple_code (stmt
) == GIMPLE_ASSIGN
1118 && POINTER_BOUNDS_P (gimple_assign_lhs (stmt
))
1119 && gimple_assign_rhs_code (stmt
) == VAR_DECL
)
1128 /* Check we do not increase other values lifetime. */
1129 FOR_EACH_PHI_OR_STMT_USE (use_p
, stmt
, iter
, SSA_OP_USE
)
1131 op
= USE_FROM_PTR (use_p
);
1133 if (TREE_CODE (op
) == SSA_NAME
1134 && gimple_code (SSA_NAME_DEF_STMT (op
)) != GIMPLE_NOP
)
1147 /* Check all usages of bounds. */
1148 if (gimple_code (stmt
) == GIMPLE_CALL
)
1149 op
= gimple_call_lhs (stmt
);
1152 gcc_assert (gimple_code (stmt
) == GIMPLE_ASSIGN
);
1153 op
= gimple_assign_lhs (stmt
);
1159 FOR_EACH_IMM_USE_STMT (use_stmt
, use_iter
, op
)
1161 if (is_gimple_debug (use_stmt
))
1165 dominated_by_p (CDI_DOMINATORS
,
1166 dom_bb
, gimple_bb (use_stmt
)))
1172 dom_bb
= nearest_common_dominator (CDI_DOMINATORS
, dom_bb
,
1173 gimple_bb (use_stmt
));
1176 else if (stmt_dominates_stmt_p (use_stmt
, dom_use
))
1178 else if (!stmt_dominates_stmt_p (dom_use
, use_stmt
)
1179 /* If dom_use and use_stmt are PHI nodes in one BB
1180 then it is OK to keep any of them as dom_use.
1181 stmt_dominates_stmt_p returns 0 for such
1182 combination, so check it here manually. */
1183 && (gimple_code (dom_use
) != GIMPLE_PHI
1184 || gimple_code (use_stmt
) != GIMPLE_PHI
1185 || gimple_bb (use_stmt
) != gimple_bb (dom_use
))
1188 dom_bb
= nearest_common_dominator (CDI_DOMINATORS
,
1189 gimple_bb (use_stmt
),
1190 gimple_bb (dom_use
));
1195 /* In case there is a single use, just move bounds
1196 creation to the use. */
1197 if (dom_use
|| dom_bb
)
1199 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1201 fprintf (dump_file
, "Moving creation of ");
1202 print_generic_expr (dump_file
, op
);
1203 fprintf (dump_file
, " down to its use.\n");
1206 if (dom_use
&& gimple_code (dom_use
) == GIMPLE_PHI
)
1208 dom_bb
= get_immediate_dominator (CDI_DOMINATORS
,
1209 gimple_bb (dom_use
));
1214 || (dom_use
&& gimple_bb (dom_use
) == bb
))
1216 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1217 fprintf (dump_file
, "Cannot move statement bacause there is no "
1218 "suitable dominator block other than entry block.\n");
1226 gimple_stmt_iterator last
= gsi_last_bb (dom_bb
);
1227 if (!gsi_end_p (last
) && stmt_ends_bb_p (gsi_stmt (last
)))
1228 gsi_move_before (&i
, &last
);
1230 gsi_move_after (&i
, &last
);
1234 gimple_stmt_iterator gsi
= gsi_for_stmt (dom_use
);
1235 gsi_move_before (&i
, &gsi
);
1238 gimple_set_vdef (stmt
, NULL_TREE
);
1239 gimple_set_vuse (stmt
, NULL_TREE
);
1248 /* Initilize checker optimization pass. */
1250 chkp_opt_init (void)
1252 check_infos
.create (0);
1254 calculate_dominance_info (CDI_DOMINATORS
);
1255 calculate_dominance_info (CDI_POST_DOMINATORS
);
1257 /* With LTO constant bounds vars may be not initialized by now.
1258 Get constant bounds vars to handle their assignments during
1260 chkp_get_zero_bounds_var ();
1261 chkp_get_none_bounds_var ();
1264 /* Finalise checker optimization pass. */
1266 chkp_opt_fini (void)
1270 free_dominance_info (CDI_POST_DOMINATORS
);
1273 /* Checker optimization pass function. */
1275 chkp_opt_execute (void)
1279 /* This optimization may introduce new checks
1280 and thus we put it before checks search. */
1281 chkp_optimize_string_function_calls ();
1283 chkp_gather_checks_info ();
1285 chkp_remove_excess_intersections ();
1287 chkp_remove_constant_checks ();
1289 chkp_reduce_bounds_lifetime ();
1291 chkp_release_check_info ();
1300 chkp_opt_gate (void)
1302 return chkp_function_instrumented_p (cfun
->decl
)
1303 && (flag_chkp_optimize
> 0
1304 || (flag_chkp_optimize
== -1 && optimize
> 0));
1309 const pass_data pass_data_chkp_opt
=
1311 GIMPLE_PASS
, /* type */
1312 "chkpopt", /* name */
1313 OPTGROUP_NONE
, /* optinfo_flags */
1314 TV_NONE
, /* tv_id */
1315 PROP_ssa
| PROP_cfg
, /* properties_required */
1316 0, /* properties_provided */
1317 0, /* properties_destroyed */
1318 0, /* todo_flags_start */
1320 | TODO_update_ssa
/* todo_flags_finish */
1323 class pass_chkp_opt
: public gimple_opt_pass
1326 pass_chkp_opt (gcc::context
*ctxt
)
1327 : gimple_opt_pass (pass_data_chkp_opt
, ctxt
)
1330 /* opt_pass methods: */
1331 virtual opt_pass
* clone ()
1333 return new pass_chkp_opt (m_ctxt
);
1336 virtual bool gate (function
*)
1338 return chkp_opt_gate ();
1341 virtual unsigned int execute (function
*)
1343 return chkp_opt_execute ();
1346 }; // class pass_chkp_opt
1351 make_pass_chkp_opt (gcc::context
*ctxt
)
1353 return new pass_chkp_opt (ctxt
);