]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/tree-chkp-opt.c
Update copyright years.
[thirdparty/gcc.git] / gcc / tree-chkp-opt.c
CommitLineData
d5e254e1 1/* Pointer Bounds Checker optimization pass.
5624e564 2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
d5e254e1
IE
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tree-core.h"
25#include "tree.h"
26#include "target.h"
27#include "tree-cfg.h"
28#include "tree-pass.h"
29#include "is-a.h"
30#include "cfgloop.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"
36#include "tree-ssa.h"
37#include "predict.h"
38#include "dominance.h"
39#include "cfg.h"
40#include "basic-block.h"
41#include "tree-ssa-loop-niter.h"
42#include "gimple-expr.h"
43#include "gimple.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"
49#include "gimplify.h"
50#include "gimplify-me.h"
51#include "expr.h"
52#include "tree-chkp.h"
e4727812 53#include "ipa-chkp.h"
d5e254e1
IE
54#include "diagnostic.h"
55
56enum check_type
57{
58 CHECK_LOWER_BOUND,
59 CHECK_UPPER_BOUND
60};
61
62struct pol_item
63{
64 tree cst;
65 tree var;
66};
67
68struct address_t
69{
70 vec<struct pol_item> pol;
71};
72
73/* Structure to hold check informtation. */
74struct check_info
75{
76 /* Type of the check. */
77 check_type type;
78 /* Address used for the check. */
79 address_t addr;
80 /* Bounds used for the check. */
81 tree bounds;
82 /* Check statement. Can be NULL for removed checks. */
83 gimple stmt;
84};
85
86/* Structure to hold checks information for BB. */
87struct bb_checks
88{
89 vec<struct check_info, va_heap, vl_ptr> checks;
90};
91
92static void chkp_collect_value (tree ssa_name, address_t &res);
93
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))
102
103static vec<struct bb_checks, va_heap, vl_ptr> check_infos = vNULL;
104
105/* Comparator for pol_item structures I1 and I2 to be used
106 to find items with equal var. Also used for polynomial
107 sorting. */
108static int
109chkp_pol_item_compare (const void *i1, const void *i2)
110{
111 const struct pol_item *p1 = (const struct pol_item *)i1;
112 const struct pol_item *p2 = (const struct pol_item *)i2;
113
114 if (p1->var == p2->var)
115 return 0;
116 else if (p1->var > p2->var)
117 return 1;
118 else
119 return -1;
120}
121
122/* Find polynomial item in ADDR with var equal to VAR
123 and return its index. Return -1 if item was not
124 found. */
125static int
126chkp_pol_find (address_t &addr, tree var)
127{
128 int left = 0;
129 int right = addr.pol.length () - 1;
130 int n;
131
132 while (right >= left)
133 {
134 n = (left + right) / 2;
135
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)))
141 return n;
142 else if (addr.pol[n].var > var)
143 right = n - 1;
144 else
145 left = n + 1;
146 }
147
148 return -1;
149}
150
151/* Return constant CST extended to size type. */
152static tree
153chkp_extend_const (tree cst)
154{
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));
157
158 return cst;
159}
160
161/* Add polynomial item CST * VAR to ADDR. */
162static void
163chkp_add_addr_item (address_t &addr, tree cst, tree var)
164{
165 int n = chkp_pol_find (addr, var);
166
167 cst = chkp_extend_const (cst);
168
169 if (n < 0)
170 {
171 struct pol_item item;
172 item.cst = cst;
173 item.var = var;
174
175 addr.pol.safe_push (item);
176 addr.pol.qsort (&chkp_pol_item_compare);
177 }
178 else
179 {
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);
185 }
186}
187
188/* Subtract polynomial item CST * VAR from ADDR. */
189static void
190chkp_sub_addr_item (address_t &addr, tree cst, tree var)
191{
192 int n = chkp_pol_find (addr, var);
193
194 cst = chkp_extend_const (cst);
195
196 if (n < 0)
197 {
198 struct pol_item item;
199 item.cst = fold_build2 (MINUS_EXPR, TREE_TYPE (cst),
200 integer_zero_node, cst);
201 item.var = var;
202
203 addr.pol.safe_push (item);
204 addr.pol.qsort (&chkp_pol_item_compare);
205 }
206 else
207 {
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);
213 }
214}
215
216/* Add address DELTA to ADDR. */
217static void
218chkp_add_addr_addr (address_t &addr, address_t &delta)
219{
220 unsigned int i;
221 for (i = 0; i < delta.pol.length (); i++)
222 chkp_add_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
223}
224
225/* Subtract address DELTA from ADDR. */
226static void
227chkp_sub_addr_addr (address_t &addr, address_t &delta)
228{
229 unsigned int i;
230 for (i = 0; i < delta.pol.length (); i++)
231 chkp_sub_addr_item (addr, delta.pol[i].cst, delta.pol[i].var);
232}
233
234/* Mutiply address ADDR by integer constant MULT. */
235static void
236chkp_mult_addr (address_t &addr, tree mult)
237{
238 unsigned int i;
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);
242}
243
244/* Return 1 if we may prove ADDR has a constant value with
245 determined sign, which is put into *SIGN. Otherwise
246 return 0. */
247static bool
248chkp_is_constant_addr (const address_t &addr, int *sign)
249{
250 *sign = 0;
251
252 if (addr.pol.length () == 0)
253 return true;
254 else if (addr.pol.length () > 1)
255 return false;
256 else if (addr.pol[0].var)
257 return false;
258 else if (integer_zerop (addr.pol[0].cst))
259 *sign = 0;
260 else if (tree_int_cst_sign_bit (addr.pol[0].cst))
261 *sign = -1;
262 else
263 *sign = 1;
264
265 return true;
266}
267
268/* Dump ADDR into dump_file. */
269static void
270chkp_print_addr (const address_t &addr)
271{
272 unsigned int n = 0;
273 for (n = 0; n < addr.pol.length (); n++)
274 {
275 if (n > 0)
276 fprintf (dump_file, " + ");
277
278 if (addr.pol[n].var == NULL_TREE)
279 print_generic_expr (dump_file, addr.pol[n].cst, 0);
280 else
281 {
282 if (TREE_CODE (addr.pol[n].cst) != INTEGER_CST
283 || !integer_onep (addr.pol[n].cst))
284 {
285 print_generic_expr (dump_file, addr.pol[n].cst, 0);
286 fprintf (dump_file, " * ");
287 }
288 print_generic_expr (dump_file, addr.pol[n].var, 0);
289 }
290 }
291}
292
293/* Compute value of PTR and put it into address RES.
294 PTR has to be ADDR_EXPR. */
295static void
296chkp_collect_addr_value (tree ptr, address_t &res)
297{
298 tree obj = TREE_OPERAND (ptr, 0);
299 address_t addr;
300
301 switch (TREE_CODE (obj))
302 {
303 case INDIRECT_REF:
304 chkp_collect_value (TREE_OPERAND (obj, 0), res);
305 break;
306
307 case MEM_REF:
308 chkp_collect_value (TREE_OPERAND (obj, 0), res);
309 addr.pol.create (0);
310 chkp_collect_value (TREE_OPERAND (obj, 1), addr);
311 chkp_add_addr_addr (res, addr);
312 addr.pol.release ();
313 break;
314
315 case ARRAY_REF:
316 chkp_collect_value (build_fold_addr_expr (TREE_OPERAND (obj, 0)), res);
317 addr.pol.create (0);
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);
321 addr.pol.release ();
322 break;
323
324 case COMPONENT_REF:
325 {
326 tree str = TREE_OPERAND (obj, 0);
327 tree field = TREE_OPERAND (obj, 1);
328 chkp_collect_value (build_fold_addr_expr (str), res);
329 addr.pol.create (0);
330 chkp_collect_value (component_ref_field_offset (obj), addr);
331 chkp_add_addr_addr (res, addr);
332 addr.pol.release ();
333 if (DECL_FIELD_BIT_OFFSET (field))
334 {
335 addr.pol.create (0);
336 chkp_collect_value (fold_build2 (TRUNC_DIV_EXPR, size_type_node,
337 DECL_FIELD_BIT_OFFSET (field),
338 size_int (BITS_PER_UNIT)),
339 addr);
340 chkp_add_addr_addr (res, addr);
341 addr.pol.release ();
342 }
343 }
344 break;
345
346 default:
347 chkp_add_addr_item (res, integer_one_node, ptr);
348 break;
349 }
350}
351
352/* Compute value of PTR and put it into address RES. */
353static void
354chkp_collect_value (tree ptr, address_t &res)
355{
356 gimple def_stmt;
357 enum gimple_code code;
358 enum tree_code rhs_code;
359 address_t addr;
360 tree rhs1;
361
362 if (TREE_CODE (ptr) == INTEGER_CST)
363 {
364 chkp_add_addr_item (res, ptr, NULL);
365 return;
366 }
367 else if (TREE_CODE (ptr) == ADDR_EXPR)
368 {
369 chkp_collect_addr_value (ptr, res);
370 return;
371 }
372 else if (TREE_CODE (ptr) != SSA_NAME)
373 {
374 chkp_add_addr_item (res, integer_one_node, ptr);
375 return;
376 }
377
378 /* Now we handle the case when polynomial is computed
379 for SSA NAME. */
380 def_stmt = SSA_NAME_DEF_STMT (ptr);
381 code = gimple_code (def_stmt);
382
383 /* Currently we do not walk through statements other
384 than assignment. */
385 if (code != GIMPLE_ASSIGN)
386 {
387 chkp_add_addr_item (res, integer_one_node, ptr);
388 return;
389 }
390
391 rhs_code = gimple_assign_rhs_code (def_stmt);
392 rhs1 = gimple_assign_rhs1 (def_stmt);
393
394 switch (rhs_code)
395 {
396 case SSA_NAME:
397 case INTEGER_CST:
398 case ADDR_EXPR:
399 chkp_collect_value (rhs1, res);
400 break;
401
402 case PLUS_EXPR:
403 case POINTER_PLUS_EXPR:
404 chkp_collect_value (rhs1, res);
405 addr.pol.create (0);
406 chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
407 chkp_add_addr_addr (res, addr);
408 addr.pol.release ();
409 break;
410
411 case MINUS_EXPR:
412 chkp_collect_value (rhs1, res);
413 addr.pol.create (0);
414 chkp_collect_value (gimple_assign_rhs2 (def_stmt), addr);
415 chkp_sub_addr_addr (res, addr);
416 addr.pol.release ();
417 break;
418
419 case MULT_EXPR:
420 if (TREE_CODE (rhs1) == SSA_NAME
421 && TREE_CODE (gimple_assign_rhs2 (def_stmt)) == INTEGER_CST)
422 {
423 chkp_collect_value (rhs1, res);
424 chkp_mult_addr (res, gimple_assign_rhs2 (def_stmt));
425 }
426 else if (TREE_CODE (gimple_assign_rhs2 (def_stmt)) == SSA_NAME
427 && TREE_CODE (rhs1) == INTEGER_CST)
428 {
429 chkp_collect_value (gimple_assign_rhs2 (def_stmt), res);
430 chkp_mult_addr (res, rhs1);
431 }
432 else
433 chkp_add_addr_item (res, integer_one_node, ptr);
434 break;
435
436 default:
437 chkp_add_addr_item (res, integer_one_node, ptr);
438 break;
439 }
440}
441
442/* Fill check_info structure *CI with information about
443 check STMT. */
444static void
445chkp_fill_check_info (gimple stmt, struct check_info *ci)
446{
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
451 ? CHECK_LOWER_BOUND
452 : CHECK_UPPER_BOUND);
453 ci->stmt = stmt;
454}
455
456/* Release structures holding check information
457 for current function. */
458static void
459chkp_release_check_info (void)
460{
461 unsigned int n, m;
462
463 if (check_infos.exists ())
464 {
465 for (n = 0; n < check_infos.length (); n++)
466 {
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 ();
471 }
472 check_infos.release ();
473 }
474}
475
476/* Create structures to hold check information
477 for current function. */
478static void
479chkp_init_check_info (void)
480{
481 struct bb_checks empty_bbc;
482 int n;
483
484 empty_bbc.checks = vNULL;
485
486 chkp_release_check_info ();
487
488 check_infos.create (last_basic_block_for_fn (cfun));
489 for (n = 0; n < last_basic_block_for_fn (cfun); n++)
490 {
491 check_infos.safe_push (empty_bbc);
492 check_infos.last ().checks.create (0);
493 }
494}
495
496/* Find all checks in current function and store info about them
497 in check_infos. */
498static void
499chkp_gather_checks_info (void)
500{
501 basic_block bb;
502 gimple_stmt_iterator i;
503
504 if (dump_file && (dump_flags & TDF_DETAILS))
505 fprintf (dump_file, "Gathering information about checks...\n");
506
507 chkp_init_check_info ();
508
509 FOR_EACH_BB_FN (bb, cfun)
510 {
511 struct bb_checks *bbc = &check_infos[bb->index];
512
513 if (dump_file && (dump_flags & TDF_DETAILS))
514 fprintf (dump_file, "Searching checks in BB%d...\n", bb->index);
515
516 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
517 {
518 gimple stmt = gsi_stmt (i);
519
520 if (gimple_code (stmt) != GIMPLE_CALL)
521 continue;
522
523 if (gimple_call_fndecl (stmt) == chkp_checkl_fndecl
524 || gimple_call_fndecl (stmt) == chkp_checku_fndecl)
525 {
526 struct check_info ci;
527
528 chkp_fill_check_info (stmt, &ci);
529 bbc->checks.safe_push (ci);
530
531 if (dump_file && (dump_flags & TDF_DETAILS))
532 {
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);
540 }
541 }
542 }
543 }
544}
545
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. */
549static int
550chkp_get_check_result (struct check_info *ci, tree bounds)
551{
552 gimple bnd_def;
553 address_t bound_val;
554 int sign, res = 0;
555
556 if (dump_file && (dump_flags & TDF_DETAILS))
557 {
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");
566 }
567
568 if (TREE_CODE (bounds) != SSA_NAME)
569 {
570 if (dump_file && (dump_flags & TDF_DETAILS))
571 fprintf (dump_file, " result: bounds tree code is not ssa_name\n");
572 return 0;
573 }
574
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)
580 {
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)
584 {
585 address_t size_val;
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);
591 }
592 }
593 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
594 && gimple_assign_rhs1 (bnd_def) == chkp_get_zero_bounds_var ())
595 {
596 if (dump_file && (dump_flags & TDF_DETAILS))
597 fprintf (dump_file, " result: always pass with zero bounds\n");
598 return 1;
599 }
600 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
601 && gimple_assign_rhs1 (bnd_def) == chkp_get_none_bounds_var ())
602 {
603 if (dump_file && (dump_flags & TDF_DETAILS))
604 fprintf (dump_file, " result: always fails with none bounds\n");
605 return -1;
606 }
607 else if (gimple_code (bnd_def) == GIMPLE_ASSIGN
608 && TREE_CODE (gimple_assign_rhs1 (bnd_def)) == VAR_DECL)
609 {
610 tree bnd_var = gimple_assign_rhs1 (bnd_def);
611 tree var;
612 tree size;
613
614 if (!DECL_INITIAL (bnd_var)
615 || DECL_INITIAL (bnd_var) == error_mark_node)
616 {
617 if (dump_file && (dump_flags & TDF_DETAILS))
618 fprintf (dump_file, " result: cannot compute bounds\n");
619 return 0;
620 }
621
622 gcc_assert (TREE_CODE (DECL_INITIAL (bnd_var)) == ADDR_EXPR);
623 var = TREE_OPERAND (DECL_INITIAL (bnd_var), 0);
624
625 bound_val.pol.create (0);
626 chkp_collect_value (DECL_INITIAL (bnd_var), bound_val);
627 if (ci->type == CHECK_UPPER_BOUND)
628 {
629 if (TREE_CODE (var) == VAR_DECL)
630 {
631 if (DECL_SIZE (var)
632 && !chkp_variable_size_type (TREE_TYPE (var)))
633 size = DECL_SIZE_UNIT (var);
634 else
635 {
636 if (dump_file && (dump_flags & TDF_DETAILS))
637 fprintf (dump_file, " result: cannot compute bounds\n");
638 return 0;
639 }
640 }
641 else
642 {
643 gcc_assert (TREE_CODE (var) == STRING_CST);
644 size = build_int_cst (size_type_node,
645 TREE_STRING_LENGTH (var));
646 }
647
648 address_t size_val;
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);
654 }
655 }
656 else
657 {
658 if (dump_file && (dump_flags & TDF_DETAILS))
659 fprintf (dump_file, " result: cannot compute bounds\n");
660 return 0;
661 }
662
663 if (dump_file && (dump_flags & TDF_DETAILS))
664 {
665 fprintf (dump_file, " bound value: ");
666 chkp_print_addr (bound_val);
667 fprintf (dump_file, "\n");
668 }
669
670 chkp_sub_addr_addr (bound_val, ci->addr);
671
672 if (!chkp_is_constant_addr (bound_val, &sign))
673 {
674 if (dump_file && (dump_flags & TDF_DETAILS))
675 fprintf (dump_file, " result: cannot compute result\n");
676
677 res = 0;
678 }
679 else if (sign == 0
680 || (ci->type == CHECK_UPPER_BOUND && sign > 0)
681 || (ci->type == CHECK_LOWER_BOUND && sign < 0))
682 {
683 if (dump_file && (dump_flags & TDF_DETAILS))
684 fprintf (dump_file, " result: always pass\n");
685
686 res = 1;
687 }
688 else
689 {
690 if (dump_file && (dump_flags & TDF_DETAILS))
691 fprintf (dump_file, " result: always fail\n");
692
693 res = -1;
694 }
695
696 bound_val.pol.release ();
697
698 return res;
699}
700
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. */
704static void
705chkp_remove_check_if_pass (struct check_info *ci)
706{
707 int result = 0;
708
709 if (dump_file && (dump_flags & TDF_DETAILS))
710 {
711 fprintf (dump_file, "Trying to remove check: ");
712 print_gimple_stmt (dump_file, ci->stmt, 0, 0);
713 }
714
715 result = chkp_get_check_result (ci, ci->bounds);
716
717 if (result == 1)
718 {
719 gimple_stmt_iterator i = gsi_for_stmt (ci->stmt);
720
721 if (dump_file && (dump_flags & TDF_DETAILS))
722 fprintf (dump_file, " action: delete check (always pass)\n");
723
724 gsi_remove (&i, true);
725 unlink_stmt_vdef (ci->stmt);
726 release_defs (ci->stmt);
727 ci->stmt = NULL;
728 }
729 else if (result == -1)
730 {
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");
735 }
736 else if (result == 0)
737 {
738 if (dump_file && (dump_flags & TDF_DETAILS))
739 fprintf (dump_file, " action: keep check (cannot compute result)\n");
740 }
741}
742
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. */
747static void
748chkp_use_outer_bounds_if_possible (struct check_info *ci)
749{
750 gimple bnd_def;
751 tree bnd1, bnd2, bnd_res = NULL;
752 int check_res1, check_res2;
753
754 if (TREE_CODE (ci->bounds) != SSA_NAME)
755 return;
756
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)
760 return;
761
762 if (dump_file && (dump_flags & TDF_DETAILS))
763 {
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");
770 }
771
772 bnd1 = gimple_call_arg (bnd_def, 0);
773 bnd2 = gimple_call_arg (bnd_def, 1);
774
775 check_res1 = chkp_get_check_result (ci, bnd1);
776 check_res2 = chkp_get_check_result (ci, bnd2);
777 if (check_res1 == 1)
778 bnd_res = bnd2;
779 else if (check_res1 == -1)
780 bnd_res = bnd1;
781 else if (check_res2 == 1)
782 bnd_res = bnd1;
783 else if (check_res2 == -1)
784 bnd_res = bnd2;
785
786 if (bnd_res)
787 {
788 if (dump_file && (dump_flags & TDF_DETAILS))
789 {
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");
795 }
796
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);
801 }
802}
803
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. */
808static void
809chkp_remove_excess_intersections (void)
810{
811 basic_block bb;
812
813 if (dump_file && (dump_flags & TDF_DETAILS))
814 fprintf (dump_file, "Searching for redundant bounds intersections...\n");
815
816 FOR_EACH_BB_FN (bb, cfun)
817 {
818 struct bb_checks *bbc = &check_infos[bb->index];
819 unsigned int no;
820
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]);
825 }
826}
827
828/* Try to remove all checks which are known to alwyas pass. */
829static void
830chkp_remove_constant_checks (void)
831{
832 basic_block bb;
833
834 if (dump_file && (dump_flags & TDF_DETAILS))
835 fprintf (dump_file, "Searching for redundant checks...\n");
836
837 FOR_EACH_BB_FN (bb, cfun)
838 {
839 struct bb_checks *bbc = &check_infos[bb->index];
840 unsigned int no;
841
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]);
846 }
847}
848
e4727812
IE
849/* Return fast version of string function FNCODE. */
850static tree
851chkp_get_nobnd_fndecl (enum built_in_function fncode)
852{
853 /* Check if we are allowed to use fast string functions. */
854 if (!flag_chkp_use_fast_string_functions)
855 return NULL_TREE;
856
857 tree fndecl = NULL_TREE;
858
859 switch (fncode)
860 {
861 case BUILT_IN_MEMCPY_CHKP:
862 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND);
863 break;
864
865 case BUILT_IN_MEMPCPY_CHKP:
866 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND);
867 break;
868
869 case BUILT_IN_MEMMOVE_CHKP:
870 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND);
871 break;
872
873 case BUILT_IN_MEMSET_CHKP:
874 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND);
875 break;
876
877 case BUILT_IN_CHKP_MEMCPY_NOCHK_CHKP:
878 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
879 break;
880
881 case BUILT_IN_CHKP_MEMPCPY_NOCHK_CHKP:
882 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
883 break;
884
885 case BUILT_IN_CHKP_MEMMOVE_NOCHK_CHKP:
886 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
887 break;
888
889 case BUILT_IN_CHKP_MEMSET_NOCHK_CHKP:
890 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
891 break;
892
893 default:
894 break;
895 }
896
897 if (fndecl)
898 fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
899
900 return fndecl;
901}
902
903
904/* Return no-check version of string function FNCODE. */
905static tree
906chkp_get_nochk_fndecl (enum built_in_function fncode)
907{
908 /* Check if we are allowed to use fast string functions. */
909 if (!flag_chkp_use_nochk_string_functions)
910 return NULL_TREE;
911
912 tree fndecl = NULL_TREE;
913
914 switch (fncode)
915 {
916 case BUILT_IN_MEMCPY_CHKP:
917 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOCHK);
918 break;
919
920 case BUILT_IN_MEMPCPY_CHKP:
921 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOCHK);
922 break;
923
924 case BUILT_IN_MEMMOVE_CHKP:
925 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOCHK);
926 break;
927
928 case BUILT_IN_MEMSET_CHKP:
929 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOCHK);
930 break;
931
932 case BUILT_IN_CHKP_MEMCPY_NOBND_CHKP:
933 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK);
934 break;
935
936 case BUILT_IN_CHKP_MEMPCPY_NOBND_CHKP:
937 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK);
938 break;
939
940 case BUILT_IN_CHKP_MEMMOVE_NOBND_CHKP:
941 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMMOVE_NOBND_NOCHK);
942 break;
943
944 case BUILT_IN_CHKP_MEMSET_NOBND_CHKP:
945 fndecl = builtin_decl_implicit (BUILT_IN_CHKP_MEMSET_NOBND_NOCHK);
946 break;
947
948 default:
949 break;
950 }
951
952 if (fndecl)
953 fndecl = chkp_maybe_clone_builtin_fndecl (fndecl);
954
955 return fndecl;
956}
957
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.
962
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. */
966static void
967chkp_optimize_string_function_calls (void)
968{
969 basic_block bb;
970
971 if (dump_file && (dump_flags & TDF_DETAILS))
972 fprintf (dump_file, "Searching for replaceable string function calls...\n");
973
974 FOR_EACH_BB_FN (bb, cfun)
975 {
976 gimple_stmt_iterator i;
977
978 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
979 {
980 gimple stmt = gsi_stmt (i);
981 tree fndecl;
982
983 if (gimple_code (stmt) != GIMPLE_CALL
984 || !gimple_call_with_bounds_p (stmt))
985 continue;
986
987 fndecl = gimple_call_fndecl (stmt);
988
989 if (!fndecl || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
990 continue;
991
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)
996 {
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);
1001 tree fndecl_nochk;
1002 gimple_stmt_iterator j;
1003 basic_block check_bb;
1004 address_t size_val;
1005 int sign;
1006 bool known;
1007
1008 /* We may replace call with corresponding __chkp_*_nobnd
1009 call in case destination pointer base type is not
1010 void or pointer. */
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))))
1014 {
1015 tree fndecl_nobnd
1016 = chkp_get_nobnd_fndecl (DECL_FUNCTION_CODE (fndecl));
1017
1018 if (fndecl_nobnd)
1019 fndecl = fndecl_nobnd;
1020 }
1021
1022 fndecl_nochk = chkp_get_nochk_fndecl (DECL_FUNCTION_CODE (fndecl));
1023
1024 if (fndecl_nochk)
1025 fndecl = fndecl_nochk;
1026
1027 if (fndecl != gimple_call_fndecl (stmt))
1028 {
1029 if (dump_file && (dump_flags & TDF_DETAILS))
1030 {
1031 fprintf (dump_file, "Replacing call: ");
1032 print_gimple_stmt (dump_file, stmt, 0,
1033 TDF_VOPS|TDF_MEMSYMS);
1034 }
1035
1036 gimple_call_set_fndecl (stmt, fndecl);
1037
1038 if (dump_file && (dump_flags & TDF_DETAILS))
1039 {
1040 fprintf (dump_file, "With a new call: ");
1041 print_gimple_stmt (dump_file, stmt, 0,
1042 TDF_VOPS|TDF_MEMSYMS);
1043 }
1044 }
1045
1046 /* If there is no nochk version of function then
1047 do nothing. Otherwise insert checks before
1048 the call. */
1049 if (!fndecl_nochk)
1050 continue;
1051
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 ();
1058
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. */
1062 if (!known)
1063 {
1064 gimple check = gimple_build_cond (NE_EXPR,
1065 size,
1066 size_zero_node,
1067 NULL_TREE,
1068 NULL_TREE);
1069
1070 /* Split block before string function call. */
1071 gsi_prev (&i);
1072 check_bb = insert_cond_bb (bb, gsi_stmt (i), check);
1073
1074 /* Set position for checks. */
1075 j = gsi_last_bb (check_bb);
1076
1077 /* The block was splitted and therefore we
1078 need to set iterator to its end. */
1079 i = gsi_last_bb (bb);
1080 }
1081 /* If size is known to be zero then no checks
1082 should be performed. */
1083 else if (!sign)
1084 continue;
1085 else
1086 j = i;
1087
1088 size = size_binop (MINUS_EXPR, size, size_one_node);
1089 if (!is_memset)
1090 {
1091 tree src = gimple_call_arg (stmt, 2);
1092 tree src_bnd = gimple_call_arg (stmt, 3);
1093
1094 chkp_check_mem_access (src, fold_build_pointer_plus (src, size),
1095 src_bnd, j, gimple_location (stmt),
1096 integer_zero_node);
1097 }
1098
1099 chkp_check_mem_access (dst, fold_build_pointer_plus (dst, size),
1100 dst_bnd, j, gimple_location (stmt),
1101 integer_one_node);
1102
1103 }
1104 }
1105 }
1106}
1107
d5e254e1
IE
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. */
1113static void
1114chkp_reduce_bounds_lifetime (void)
1115{
1116 basic_block bb = FALLTHRU_EDGE (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest;
1117 gimple_stmt_iterator i;
1118
1119 for (i = gsi_start_bb (bb); !gsi_end_p (i); )
1120 {
1121 gimple dom_use, use_stmt, stmt = gsi_stmt (i);
1122 basic_block dom_bb;
1123 ssa_op_iter iter;
1124 imm_use_iterator use_iter;
1125 use_operand_p use_p;
1126 tree op;
1127 bool want_move = false;
1128 bool deps = false;
1129
1130 if (gimple_code (stmt) == GIMPLE_CALL
1131 && gimple_call_fndecl (stmt) == chkp_bndmk_fndecl)
1132 want_move = true;
1133
1134 if (gimple_code (stmt) == GIMPLE_ASSIGN
1135 && POINTER_BOUNDS_P (gimple_assign_lhs (stmt))
1136 && gimple_assign_rhs_code (stmt) == VAR_DECL)
1137 want_move = true;
1138
1139 if (!want_move)
1140 {
1141 gsi_next (&i);
1142 continue;
1143 }
1144
1145 /* Check we do not increase other values lifetime. */
1146 FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
1147 {
1148 op = USE_FROM_PTR (use_p);
1149
1150 if (TREE_CODE (op) == SSA_NAME
1151 && gimple_code (SSA_NAME_DEF_STMT (op)) != GIMPLE_NOP)
1152 {
1153 deps = true;
1154 break;
1155 }
1156 }
1157
1158 if (deps)
1159 {
1160 gsi_next (&i);
1161 continue;
1162 }
1163
1164 /* Check all usages of bounds. */
1165 if (gimple_code (stmt) == GIMPLE_CALL)
1166 op = gimple_call_lhs (stmt);
1167 else
1168 {
1169 gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
1170 op = gimple_assign_lhs (stmt);
1171 }
1172
1173 dom_use = NULL;
1174 dom_bb = NULL;
1175
1176 FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, op)
1177 {
41866363
IE
1178 if (is_gimple_debug (use_stmt))
1179 continue;
1180
d5e254e1
IE
1181 if (dom_bb &&
1182 dominated_by_p (CDI_DOMINATORS,
1183 dom_bb, gimple_bb (use_stmt)))
1184 {
1185 dom_use = use_stmt;
1186 dom_bb = NULL;
1187 }
1188 else if (dom_bb)
1189 dom_bb = nearest_common_dominator (CDI_DOMINATORS, dom_bb,
1190 gimple_bb (use_stmt));
1191 else if (!dom_use)
1192 dom_use = use_stmt;
1193 else if (stmt_dominates_stmt_p (use_stmt, dom_use))
1194 dom_use = use_stmt;
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))
1203 )
1204 {
1205 dom_bb = nearest_common_dominator (CDI_DOMINATORS,
1206 gimple_bb (use_stmt),
1207 gimple_bb (dom_use));
1208 dom_use = NULL;
1209 }
1210 }
1211
1212 /* In case there is a single use, just move bounds
1213 creation to the use. */
1214 if (dom_use || dom_bb)
1215 {
1216 if (dump_file && (dump_flags & TDF_DETAILS))
1217 {
1218 fprintf (dump_file, "Moving creation of ");
1219 print_generic_expr (dump_file, op, 0);
1220 fprintf (dump_file, " down to its use.\n");
1221 }
1222
1223 if (dom_use && gimple_code (dom_use) == GIMPLE_PHI)
1224 {
1225 dom_bb = get_immediate_dominator (CDI_DOMINATORS,
1226 gimple_bb (dom_use));
1227 dom_use = NULL;
1228 }
1229
1230 if (dom_bb == bb
1231 || (dom_use && gimple_bb (dom_use) == bb))
1232 {
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");
1236
1237 gsi_next (&i);
1238 }
1239 else
1240 {
1241 if (dom_bb)
1242 {
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);
1246 else
1247 gsi_move_after (&i, &last);
1248 }
1249 else
1250 {
1251 gimple_stmt_iterator gsi = gsi_for_stmt (dom_use);
1252 gsi_move_before (&i, &gsi);
1253 }
1254
1255 update_stmt (stmt);
1256 }
1257 }
1258 else
1259 gsi_next (&i);
1260 }
1261}
1262
1263/* Initilize checker optimization pass. */
1264static void
1265chkp_opt_init (void)
1266{
1267 check_infos.create (0);
1268
1269 calculate_dominance_info (CDI_DOMINATORS);
1270 calculate_dominance_info (CDI_POST_DOMINATORS);
1271
1272 /* With LTO constant bounds vars may be not initialized by now.
1273 Get constant bounds vars to handle their assignments during
1274 optimizations. */
1275 chkp_get_zero_bounds_var ();
1276 chkp_get_none_bounds_var ();
1277}
1278
1279/* Finalise checker optimization pass. */
1280static void
1281chkp_opt_fini (void)
1282{
1283 chkp_fix_cfg ();
1284}
1285
1286/* Checker optimization pass function. */
1287static unsigned int
1288chkp_opt_execute (void)
1289{
1290 chkp_opt_init();
1291
e4727812
IE
1292 /* This optimization may introduce new checks
1293 and thus we put it before checks search. */
1294 chkp_optimize_string_function_calls ();
1295
d5e254e1
IE
1296 chkp_gather_checks_info ();
1297
1298 chkp_remove_excess_intersections ();
1299
1300 chkp_remove_constant_checks ();
1301
1302 chkp_reduce_bounds_lifetime ();
1303
1304 chkp_release_check_info ();
1305
1306 chkp_opt_fini ();
1307
1308 return 0;
1309}
1310
1311/* Pass gate. */
1312static bool
1313chkp_opt_gate (void)
1314{
1315 return chkp_function_instrumented_p (cfun->decl)
1316 && (flag_chkp_optimize > 0
1317 || (flag_chkp_optimize == -1 && optimize > 0));
1318}
1319
1320namespace {
1321
1322const pass_data pass_data_chkp_opt =
1323{
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 */
1332 TODO_verify_il
1333 | TODO_update_ssa /* todo_flags_finish */
1334};
1335
1336class pass_chkp_opt : public gimple_opt_pass
1337{
1338public:
1339 pass_chkp_opt (gcc::context *ctxt)
1340 : gimple_opt_pass (pass_data_chkp_opt, ctxt)
1341 {}
1342
1343 /* opt_pass methods: */
1344 virtual opt_pass * clone ()
1345 {
1346 return new pass_chkp_opt (m_ctxt);
1347 }
1348
1349 virtual bool gate (function *)
1350 {
1351 return chkp_opt_gate ();
1352 }
1353
1354 virtual unsigned int execute (function *)
1355 {
1356 return chkp_opt_execute ();
1357 }
1358
1359}; // class pass_chkp_opt
1360
1361} // anon namespace
1362
1363gimple_opt_pass *
1364make_pass_chkp_opt (gcc::context *ctxt)
1365{
1366 return new pass_chkp_opt (ctxt);
1367}