GCC Middle and Back End API Reference
|
Public Types | |
typedef same_succ_def | value_type |
typedef same_succ_def | compare_type |
Static Public Member Functions | |
static hashval_t | hash (const value_type *) |
static int | equal (const value_type *, const compare_type *) |
static void | remove (value_type *) |
Data Fields | |
bitmap | bbs |
bitmap | succs |
bitmap | inverse |
vec< int > | succ_flags |
bool | in_worklist |
hashval_t | hashval |
Tail merging for gimple. Copyright (C) 2011-2013 Free Software Foundation, Inc. Contributed by Tom de Vries (tom@c) odes ource ry.c om
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see http://www.gnu.org/licenses/. Pass overview.
MOTIVATIONAL EXAMPLE
gimple representation of gcc/testsuite/gcc.dg/pr43864.c at
hprofStartupp (charD.1 * outputFileNameD.2600, charD.1 * ctxD.2601) { struct FILED.1638 * fpD.2605; charD.1 fileNameD.2604[1000]; intD.0 D.3915; const charD.1 * restrict outputFileName.0D.3914;
outputFileName.0D.3914_3 = (const charD.1 * restrict) outputFileNameD.2600_2(D);
sprintfD.759 (&fileNameD.2604, outputFileName.0D.3914_3);
D.3915_4 = accessD.2606 (&fileNameD.2604, 1); if (D.3915_4 == 0) goto <bb 3>; else goto <bb 4>;
freeD.898 (ctxD.2601_5(D)); goto <bb 7>;
fpD.2605_8 = fopenD.1805 (&fileNameD.2604[0], 0B); if (fpD.2605_8 == 0B) goto <bb 5>; else goto <bb 6>;
freeD.898 (ctxD.2601_5(D)); goto <bb 7>;
fooD.2599 (outputFileNameD.2600_2(D), fpD.2605_8);
6 [100.0%] (fallthru,exec)
.MEMD.3923_18(6)>
return ctxD.2601_1;
}
bb 3 and bb 5 can be merged. The blocks have different predecessors, but the same successors, and the same operations.
CONTEXT
A technique called tail merging (or cross jumping) can fix the example above. For a block, we look for common code at the end (the tail) of the predecessor blocks, and insert jumps from one block to the other. The example is a special case for tail merging, in that 2 whole blocks can be merged, rather than just the end parts of it. We currently only focus on whole block merging, so in that sense calling this pass tail merge is a bit of a misnomer.
We distinguish 2 kinds of situations in which blocks can be merged:
For efficient implementation, we would like to value numbers the blocks, and have a comparison operator that tells us whether the blocks are equal. Besides being runtime efficient, block value numbering should also abstract from irrelevant differences in order of operations, much like normal value numbering abstracts from irrelevant order of operations.
For the first situation (same_operations, same predecessors), normal value numbering fits well. We can calculate a block value number based on the value numbers of the defs and vdefs.
For the second situation (same operations, same successors), this approach doesn't work so well. We can illustrate this using the example. The calls to free use different vdefs: MEMD.3923_16 and MEMD.3923_14, and these will remain different in value numbering, since they represent different memory states. So the resulting vdefs of the frees will be different in value numbering, so the block value numbers will be different.
The reason why we call the blocks equal is not because they define the same values, but because uses in the blocks use (possibly different) defs in the same way. To be able to detect this efficiently, we need to do some kind of reverse value numbering, meaning number the uses rather than the defs, and calculate a block value number based on the value number of the uses. Ideally, a block comparison operator will also indicate which phis are needed to merge the blocks.
For the moment, we don't do block value numbering, but we do insn-by-insn matching, using scc value numbers to match operations with results, and structural comparison otherwise, while ignoring vop mismatches.
IMPLEMENTATION
LIMITATIONS/TODO
PASS PLACEMENT This 'pass' is not a stand-alone gimple pass, but runs as part of pass_pre, in order to share the value numbering.
SWITCHES
hash_table support.
|
static |
Compares SAME_SUCCs E1 and E2.
References gimple_call_same_target_p(), gsi_advance_fw_nondebug_nonlocal(), gsi_next_nondebug(), gsi_stmt(), and is_gimple_call().
|
inlinestatic |
hash routine for hash_table support, returns hashval of E.
|
static |
Delete same_succ E.
bitmap same_succ_def::bbs |
The bbs that have the same successor bbs.
hashval_t same_succ_def::hashval |
The hash value of the struct.
bool same_succ_def::in_worklist |
Indicates whether the struct is currently in the worklist.
bitmap same_succ_def::inverse |
Indicates whether the EDGE_TRUE/FALSE_VALUEs of succ_flags are swapped for bb.
vec<int> same_succ_def::succ_flags |
The edge flags for each of the successor bbs.
bitmap same_succ_def::succs |
The successor bbs.
Referenced by print_worklist().