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