[RFC] Isolate & simplify paths with undefined behaviour
Richard Biener
richard.guenther@gmail.com
Wed Oct 23 13:55:00 GMT 2013
On Mon, Oct 21, 2013 at 7:27 PM, Jeff Law <law@redhat.com> wrote:
> On 10/21/13 06:19, Richard Biener wrote:
>
>>
>> I wonder why this isn't part of the regular jump-threading code - after
>> all the opportunity is to thead to __builtin_unreachable () ;) Otherwise
>> the question is always where you'd place this pass and whether it
>> enables jump threading or CSE opportunities (that at least it does).
>
> In theory one could do this as part of jump threading. Doing it in jump
> threading would have the advantage that we could use a NULL generated in a
> different block than the dereference. Of course, we'd have a full path to
> duplicate at that point.
>
> The downside is complexity. This pass is amazingly simple and effective.
> The jump threading code is considerably more complex and bolting this on the
> side would just make it worse.
>
> From a pipeline location, if kept as a separate pass, it probably needs to
> be between DOM1 & phi-only cprop. DOM1 does a reasonable job at propagating
> the NULL values into the PHI nodes to expose the optimization. And the pass
> tends to expose precisely the kinds of PHI nodes that phi-only cprop can
> optimize. VRP2/PRE/DOM2 do a good job at finding the newly exposed CSEs and
> jump threading opportunities.
>
> I haven't looked to see if there's anything left to optimize after DOM2, but
> I can certainly speculate that there would be cases exposed by the various
> passes that currently exist between DOM1 & DOM2. That's certainly worth
> exploring.
>
> As you know, phase ordering will always be a concern. We already have
> acknowledged that we're punting some of those issues once we stopped
> iterating DOM.
True ...
Btw, -ftree-isolate-paths sounds a bit generic for isolating paths leading
to undefined behavior, maybe -fisolate-errorneous-paths? (please drop
'tree-' from new options, 'tree' isn't meaningful to GCC users)
The file should be named gimple-ssa-isolate-paths.c, too.
+ for (si = gsi_start_nondebug_bb (bb), si2 = gsi_start_nondebug_bb
(duplicate);
+ !gsi_end_p (si) && !gsi_end_p (si2);
+ gsi_next_nondebug (&si), gsi_next_nondebug (&si2))
+ {
+ while (gimple_code (gsi_stmt (si)) == GIMPLE_LABEL)
+ gsi_next_nondebug (&si);
gsi_after_labels (bb);
if (is_gimple_debug (gsi_stmt (gsi)))
gsi_next_nondebug (&gsi);
warrants a new gsi_nondebug_after_labels ()
+ /* SI2 is the iterator in the duplicate block and it now points
+ to our victim statement. */
+ gimple_seq seq = NULL;
+ tree t = build_call_expr_loc (0,
+ builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ gimplify_and_add (t, &seq);
+ gsi_insert_before (&si2, seq, GSI_SAME_STMT);
please build a gimple call stmt directly instead of going through the
gimplifier.
+ if (operand_equal_p (op, integer_zero_node, 0))
integer_zerop ()
+ /* We've got a NULL PHI argument. Now see if the
+ PHI's result is dereferenced within BB. */
+ FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+ {
+ unsigned int j;
+ bool removed_edge = false;
+
+ /* We only care about uses in BB which are assignements
+ with memory operands.
+
+ We could see if any uses are as function arguments
+ when the callee has marked the argument as being
+ non-null. */
+ if (gimple_bb (use_stmt) != bb
+ || !gimple_has_mem_ops (use_stmt)
+ || gimple_code (use_stmt) != GIMPLE_ASSIGN)
!is_gimple_assign (), you can drop the has_mem_ops check, but ...
+ continue;
+
+ /* Look at each operand for a memory reference using
+ LHS. */
... you want to use walk_stmt_load_store_ops () which handles all kinds
of stmts fine.
+ for (j = 0; j < gimple_num_ops (use_stmt); j++)
+ {
+ tree op = gimple_op (use_stmt, j);
+
+ if (op == NULL)
+ continue;
+
+ while (handled_component_p (op))
+ op = TREE_OPERAND (op, 0);
+
+ if ((TREE_CODE (op) == MEM_REF
+ || TREE_CODE (op) == INDIRECT_REF)
no more INDIRECT_REFs are in the IL.
Richard.
+ && TREE_OPERAND (op, 0) == lhs)
+ {
+ edge e = gimple_phi_arg_edge (phi, i);
+ duplicate = isolate_path (bb, duplicate,
+ e, use_stmt);
+
+ /* When we remove an incoming edge, we need to
+ reprocess the Ith element. */
+ next_i = i;
+
+ removed_edge = true;
+ cfg_altered = true;
+ break;
+ }
+ }
> Jeff
More information about the Gcc-patches
mailing list