public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-420] Avoid visiting newly-created blocks in harden-conditionals
@ 2022-05-13 10:49 Alexandre Oliva
0 siblings, 0 replies; only message in thread
From: Alexandre Oliva @ 2022-05-13 10:49 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:04c0a88aabe8f73f87d6b756aaa0925e58229c99
commit r13-420-g04c0a88aabe8f73f87d6b756aaa0925e58229c99
Author: Alexandre Oliva <oliva@adacore.com>
Date: Fri May 13 07:48:51 2022 -0300
Avoid visiting newly-created blocks in harden-conditionals
Reverse iteration over blocks, in gimple-harden-conditionals.cc, was
supposed to avoid visiting blocks introduced by hardening and
introducing further reversed conditionals and traps for them, but
newly-created blocks may be inserted before the current block, as
shown by the PR105455 testcase.
Use an auto_sbitmap to gather preexisting blocks that need visiting.
for gcc/ChangeLog
* gimple-harden-conditionals.cc: Include sbitmap.h.
(pass_harden_conditional_branches::execute): Skip new blocks.
(pass_harden_compares::execute): Likewise.
Diff:
---
gcc/gimple-harden-conditionals.cc | 417 ++++++++++++++++++++------------------
1 file changed, 220 insertions(+), 197 deletions(-)
diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc
index 19ceb8a4bd6..79c0a5784ba 100644
--- a/gcc/gimple-harden-conditionals.cc
+++ b/gcc/gimple-harden-conditionals.cc
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfghooks.h"
#include "cfgloop.h"
#include "tree-eh.h"
+#include "sbitmap.h"
#include "diagnostic.h"
#include "intl.h"
@@ -303,9 +304,21 @@ insert_edge_check_and_trap (location_t loc, edge e,
unsigned int
pass_harden_conditional_branches::execute (function *fun)
{
+ /* Record the preexisting blocks, to avoid visiting newly-created
+ blocks. */
+ auto_sbitmap to_visit (last_basic_block_for_fn (fun));
+ bitmap_clear (to_visit);
+
basic_block bb;
- FOR_EACH_BB_REVERSE_FN (bb, fun)
+ FOR_EACH_BB_FN (bb, fun)
+ bitmap_set_bit (to_visit, bb->index);
+
+ sbitmap_iterator it;
+ unsigned i;
+ EXECUTE_IF_SET_IN_BITMAP (to_visit, 0, i, it)
{
+ bb = BASIC_BLOCK_FOR_FN (fun, i);
+
gimple_stmt_iterator gsi = gsi_last_bb (bb);
if (gsi_end_p (gsi))
@@ -385,205 +398,215 @@ non_eh_succ_edge (basic_block bb, edge *ehp = NULL)
unsigned int
pass_harden_compares::execute (function *fun)
{
+ /* Record the preexisting blocks, to avoid visiting newly-created
+ blocks. */
+ auto_sbitmap to_visit (last_basic_block_for_fn (fun));
+ bitmap_clear (to_visit);
+
basic_block bb;
- /* Go backwards over BBs and stmts, so that, even if we split the
- block multiple times to insert a cond_expr after each compare we
- find, we remain in the same block, visiting every preexisting
- stmt exactly once, and not visiting newly-added blocks or
- stmts. */
- FOR_EACH_BB_REVERSE_FN (bb, fun)
- for (gimple_stmt_iterator gsi = gsi_last_bb (bb);
- !gsi_end_p (gsi); gsi_prev (&gsi))
- {
- gassign *asgn = dyn_cast <gassign *> (gsi_stmt (gsi));
- if (!asgn)
- continue;
-
- /* Turn:
-
- z = x op y;
-
- into:
-
- z = x op y;
- z' = x' cop y';
- if (z == z') __builtin_trap ();
-
- where cop is a complementary boolean operation to op; and x'
- and y' hold the same value as x and y, but in a way that does
- not enable the compiler to optimize the redundant compare
- away.
- */
-
- enum tree_code op = gimple_assign_rhs_code (asgn);
-
- enum tree_code cop;
-
- switch (op)
- {
- case EQ_EXPR:
- case NE_EXPR:
- case GT_EXPR:
- case GE_EXPR:
- case LT_EXPR:
- case LE_EXPR:
- case LTGT_EXPR:
- case UNEQ_EXPR:
- case UNGT_EXPR:
- case UNGE_EXPR:
- case UNLT_EXPR:
- case UNLE_EXPR:
- case ORDERED_EXPR:
- case UNORDERED_EXPR:
- cop = invert_tree_comparison (op,
- HONOR_NANS
- (gimple_assign_rhs1 (asgn)));
-
- if (cop == ERROR_MARK)
- /* ??? Can we do better? */
- continue;
+ FOR_EACH_BB_FN (bb, fun)
+ bitmap_set_bit (to_visit, bb->index);
+
+ sbitmap_iterator it;
+ unsigned i;
+ EXECUTE_IF_SET_IN_BITMAP (to_visit, 0, i, it)
+ {
+ bb = BASIC_BLOCK_FOR_FN (fun, i);
- break;
-
- /* ??? Maybe handle these too? */
- case TRUTH_NOT_EXPR:
- /* ??? The code below assumes binary ops, it would have to
- be adjusted for TRUTH_NOT_EXPR, since it's unary. */
- case TRUTH_ANDIF_EXPR:
- case TRUTH_ORIF_EXPR:
- case TRUTH_AND_EXPR:
- case TRUTH_OR_EXPR:
- case TRUTH_XOR_EXPR:
- default:
+ for (gimple_stmt_iterator gsi = gsi_last_bb (bb);
+ !gsi_end_p (gsi); gsi_prev (&gsi))
+ {
+ gassign *asgn = dyn_cast <gassign *> (gsi_stmt (gsi));
+ if (!asgn)
+ continue;
+
+ /* Turn:
+
+ z = x op y;
+
+ into:
+
+ z = x op y;
+ z' = x' cop y';
+ if (z == z') __builtin_trap ();
+
+ where cop is a complementary boolean operation to op; and x'
+ and y' hold the same value as x and y, but in a way that does
+ not enable the compiler to optimize the redundant compare
+ away.
+ */
+
+ enum tree_code op = gimple_assign_rhs_code (asgn);
+
+ enum tree_code cop;
+
+ switch (op)
+ {
+ case EQ_EXPR:
+ case NE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ case LTGT_EXPR:
+ case UNEQ_EXPR:
+ case UNGT_EXPR:
+ case UNGE_EXPR:
+ case UNLT_EXPR:
+ case UNLE_EXPR:
+ case ORDERED_EXPR:
+ case UNORDERED_EXPR:
+ cop = invert_tree_comparison (op,
+ HONOR_NANS
+ (gimple_assign_rhs1 (asgn)));
+
+ if (cop == ERROR_MARK)
+ /* ??? Can we do better? */
+ continue;
+
+ break;
+
+ /* ??? Maybe handle these too? */
+ case TRUTH_NOT_EXPR:
+ /* ??? The code below assumes binary ops, it would have to
+ be adjusted for TRUTH_NOT_EXPR, since it's unary. */
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ default:
+ continue;
+ }
+
+ /* These are the operands for the verification. */
+ tree lhs = gimple_assign_lhs (asgn);
+ tree op1 = gimple_assign_rhs1 (asgn);
+ tree op2 = gimple_assign_rhs2 (asgn);
+ location_t loc = gimple_location (asgn);
+
+ /* Vector booleans can't be used in conditional branches. ???
+ Can we do better? How to reduce compare and
+ reversed-compare result vectors to a single boolean? */
+ if (VECTOR_TYPE_P (TREE_TYPE (op1)))
continue;
- }
-
- /* These are the operands for the verification. */
- tree lhs = gimple_assign_lhs (asgn);
- tree op1 = gimple_assign_rhs1 (asgn);
- tree op2 = gimple_assign_rhs2 (asgn);
- location_t loc = gimple_location (asgn);
-
- /* Vector booleans can't be used in conditional branches. ???
- Can we do better? How to reduce compare and
- reversed-compare result vectors to a single boolean? */
- if (VECTOR_TYPE_P (TREE_TYPE (op1)))
- continue;
-
- /* useless_type_conversion_p enables conversions from 1-bit
- integer types to boolean to be discarded. */
- gcc_checking_assert (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE
- || (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
- && TYPE_PRECISION (TREE_TYPE (lhs)) == 1));
-
- tree rhs = copy_ssa_name (lhs);
-
- gimple_stmt_iterator gsi_split = gsi;
- /* Don't separate the original assignment from debug stmts
- that might be associated with it, and arrange to split the
- block after debug stmts, so as to make sure the split block
- won't be debug stmts only. */
- gsi_next_nondebug (&gsi_split);
-
- bool throwing_compare_p = stmt_ends_bb_p (asgn);
- if (throwing_compare_p)
- {
- basic_block nbb = split_edge (non_eh_succ_edge
- (gimple_bb (asgn)));
- gsi_split = gsi_start_bb (nbb);
-
- if (dump_file)
- fprintf (dump_file,
- "Splitting non-EH edge from block %i into %i"
- " after a throwing compare\n",
- gimple_bb (asgn)->index, nbb->index);
- }
-
- bool same_p = (op1 == op2);
- op1 = detach_value (loc, &gsi_split, op1);
- op2 = same_p ? op1 : detach_value (loc, &gsi_split, op2);
-
- gassign *asgnck = gimple_build_assign (rhs, cop, op1, op2);
- gimple_set_location (asgnck, loc);
- gsi_insert_before (&gsi_split, asgnck, GSI_SAME_STMT);
-
- /* We wish to insert a cond_expr after the compare, so arrange
- for it to be at the end of a block if it isn't, and for it
- to have a single successor in case there's more than
- one, as in PR104975. */
- if (!gsi_end_p (gsi_split)
- || !single_succ_p (gsi_bb (gsi_split)))
- {
- if (!gsi_end_p (gsi_split))
- gsi_prev (&gsi_split);
- else
- gsi_split = gsi_last_bb (gsi_bb (gsi_split));
- basic_block obb = gsi_bb (gsi_split);
- basic_block nbb = split_block (obb, gsi_stmt (gsi_split))->dest;
- gsi_next (&gsi_split);
- gcc_checking_assert (gsi_end_p (gsi_split));
-
- single_succ_edge (bb)->goto_locus = loc;
-
- if (dump_file)
- fprintf (dump_file,
- "Splitting block %i into %i"
- " before the conditional trap branch\n",
- obb->index, nbb->index);
- }
-
- /* If the check assignment must end a basic block, we can't
- insert the conditional branch in the same block, so split
- the block again, and prepare to insert the conditional
- branch in the new block.
-
- Also assign an EH region to the compare. Even though it's
- unlikely that the hardening compare will throw after the
- original compare didn't, the compiler won't even know that
- it's the same compare operands, so add the EH edge anyway. */
- if (throwing_compare_p)
- {
- add_stmt_to_eh_lp (asgnck, lookup_stmt_eh_lp (asgn));
- make_eh_edges (asgnck);
-
- edge ckeh;
- basic_block nbb = split_edge (non_eh_succ_edge
- (gimple_bb (asgnck), &ckeh));
- gsi_split = gsi_start_bb (nbb);
-
- if (dump_file)
- fprintf (dump_file,
- "Splitting non-EH edge from block %i into %i after"
- " the newly-inserted reversed throwing compare\n",
- gimple_bb (asgnck)->index, nbb->index);
-
- if (!gimple_seq_empty_p (phi_nodes (ckeh->dest)))
- {
- edge aseh;
- non_eh_succ_edge (gimple_bb (asgn), &aseh);
-
- gcc_checking_assert (aseh->dest == ckeh->dest);
-
- for (gphi_iterator psi = gsi_start_phis (ckeh->dest);
- !gsi_end_p (psi); gsi_next (&psi))
- {
- gphi *phi = psi.phi ();
- add_phi_arg (phi, PHI_ARG_DEF_FROM_EDGE (phi, aseh), ckeh,
- gimple_phi_arg_location_from_edge (phi, aseh));
- }
-
- if (dump_file)
- fprintf (dump_file,
- "Copying PHI args in EH block %i from %i to %i\n",
- aseh->dest->index, aseh->src->index, ckeh->src->index);
- }
- }
-
- gcc_checking_assert (single_succ_p (gsi_bb (gsi_split)));
-
- insert_check_and_trap (loc, &gsi_split, EDGE_TRUE_VALUE,
- EQ_EXPR, lhs, rhs);
- }
+
+ /* useless_type_conversion_p enables conversions from 1-bit
+ integer types to boolean to be discarded. */
+ gcc_checking_assert (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE
+ || (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ && TYPE_PRECISION (TREE_TYPE (lhs)) == 1));
+
+ tree rhs = copy_ssa_name (lhs);
+
+ gimple_stmt_iterator gsi_split = gsi;
+ /* Don't separate the original assignment from debug stmts
+ that might be associated with it, and arrange to split the
+ block after debug stmts, so as to make sure the split block
+ won't be debug stmts only. */
+ gsi_next_nondebug (&gsi_split);
+
+ bool throwing_compare_p = stmt_ends_bb_p (asgn);
+ if (throwing_compare_p)
+ {
+ basic_block nbb = split_edge (non_eh_succ_edge
+ (gimple_bb (asgn)));
+ gsi_split = gsi_start_bb (nbb);
+
+ if (dump_file)
+ fprintf (dump_file,
+ "Splitting non-EH edge from block %i into %i"
+ " after a throwing compare\n",
+ gimple_bb (asgn)->index, nbb->index);
+ }
+
+ bool same_p = (op1 == op2);
+ op1 = detach_value (loc, &gsi_split, op1);
+ op2 = same_p ? op1 : detach_value (loc, &gsi_split, op2);
+
+ gassign *asgnck = gimple_build_assign (rhs, cop, op1, op2);
+ gimple_set_location (asgnck, loc);
+ gsi_insert_before (&gsi_split, asgnck, GSI_SAME_STMT);
+
+ /* We wish to insert a cond_expr after the compare, so arrange
+ for it to be at the end of a block if it isn't, and for it
+ to have a single successor in case there's more than
+ one, as in PR104975. */
+ if (!gsi_end_p (gsi_split)
+ || !single_succ_p (gsi_bb (gsi_split)))
+ {
+ if (!gsi_end_p (gsi_split))
+ gsi_prev (&gsi_split);
+ else
+ gsi_split = gsi_last_bb (gsi_bb (gsi_split));
+ basic_block obb = gsi_bb (gsi_split);
+ basic_block nbb = split_block (obb, gsi_stmt (gsi_split))->dest;
+ gsi_next (&gsi_split);
+ gcc_checking_assert (gsi_end_p (gsi_split));
+
+ single_succ_edge (bb)->goto_locus = loc;
+
+ if (dump_file)
+ fprintf (dump_file,
+ "Splitting block %i into %i"
+ " before the conditional trap branch\n",
+ obb->index, nbb->index);
+ }
+
+ /* If the check assignment must end a basic block, we can't
+ insert the conditional branch in the same block, so split
+ the block again, and prepare to insert the conditional
+ branch in the new block.
+
+ Also assign an EH region to the compare. Even though it's
+ unlikely that the hardening compare will throw after the
+ original compare didn't, the compiler won't even know that
+ it's the same compare operands, so add the EH edge anyway. */
+ if (throwing_compare_p)
+ {
+ add_stmt_to_eh_lp (asgnck, lookup_stmt_eh_lp (asgn));
+ make_eh_edges (asgnck);
+
+ edge ckeh;
+ basic_block nbb = split_edge (non_eh_succ_edge
+ (gimple_bb (asgnck), &ckeh));
+ gsi_split = gsi_start_bb (nbb);
+
+ if (dump_file)
+ fprintf (dump_file,
+ "Splitting non-EH edge from block %i into %i after"
+ " the newly-inserted reversed throwing compare\n",
+ gimple_bb (asgnck)->index, nbb->index);
+
+ if (!gimple_seq_empty_p (phi_nodes (ckeh->dest)))
+ {
+ edge aseh;
+ non_eh_succ_edge (gimple_bb (asgn), &aseh);
+
+ gcc_checking_assert (aseh->dest == ckeh->dest);
+
+ for (gphi_iterator psi = gsi_start_phis (ckeh->dest);
+ !gsi_end_p (psi); gsi_next (&psi))
+ {
+ gphi *phi = psi.phi ();
+ add_phi_arg (phi, PHI_ARG_DEF_FROM_EDGE (phi, aseh), ckeh,
+ gimple_phi_arg_location_from_edge (phi, aseh));
+ }
+
+ if (dump_file)
+ fprintf (dump_file,
+ "Copying PHI args in EH block %i from %i to %i\n",
+ aseh->dest->index, aseh->src->index,
+ ckeh->src->index);
+ }
+ }
+
+ gcc_checking_assert (single_succ_p (gsi_bb (gsi_split)));
+
+ insert_check_and_trap (loc, &gsi_split, EDGE_TRUE_VALUE,
+ EQ_EXPR, lhs, rhs);
+ }
+ }
return 0;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-05-13 10:49 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-13 10:49 [gcc r13-420] Avoid visiting newly-created blocks in harden-conditionals Alexandre Oliva
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).