1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

[LCSSA] Doc for special treatment of PHIs

Differential Revision: https://reviews.llvm.org/D89739
This commit is contained in:
Stefanos Baziotis 2020-10-29 22:50:07 +02:00
parent 92d6409564
commit d9f0b9e2f4
3 changed files with 65 additions and 11 deletions

View File

@ -291,10 +291,11 @@ Loop Closed SSA (LCSSA)
A program is in Loop Closed SSA Form if it is in SSA form
and all values that are defined in a loop are used only inside
this loop.
Programs written in LLVM IR are always in SSA form but not necessarily
in LCSSA. To achieve the latter, single entry PHI nodes are inserted
at the end of the loops for all values that are live
across the loop boundary [#lcssa-construction]_.
in LCSSA. To achieve the latter, for each value that is live across the
loop boundary, single entry PHI nodes are inserted to each of the exit blocks
[#lcssa-construction]_ in order to "close" these values inside the loop.
In particular, consider the following loop:
.. code-block:: C
@ -336,8 +337,23 @@ scheduling a LoopPass.
After the loop optimizations are done, these extra phi nodes
will be deleted by :ref:`-instcombine <passes-instcombine>`.
The major benefit of this transformation is that it makes many other
loop optimizations simpler.
Note that an exit block is outside of a loop, so how can such a phi "close"
the value inside the loop since it uses it outside of it ? First of all,
for phi nodes, as
`mentioned in the LangRef <https://llvm.org/docs/LangRef.html#id311>`_:
"the use of each incoming value is deemed to occur on the edge from the
corresponding predecessor block to the current block". Now, an
edge to an exit block is considered outside of the loop because
if we take that edge, it leads us clearly out of the loop.
However, an edge doesn't actually contain any IR, so in source code,
we have to choose a convention of whether the use happens in
the current block or in the respective predecessor. For LCSSA's purpose,
we consider the use happens in the latter (so as to consider the
use inside) [#point-of-use-phis]_.
The major benefit of LCSSA is that it makes many other loop optimizations
simpler.
First of all, a simple observation is that if one needs to see all
the outside users, they can just iterate over all the (loop closing)
@ -436,6 +452,27 @@ the context / scope / relative loop.
.. [#lcssa-construction] To insert these loop-closing PHI nodes, one has to
(re-)compute dominance frontiers (if the loop has multiple exits).
.. [#point-of-use-phis] Considering the point of use of a PHI entry value
to be in the respective predecessor is a convention across the whole LLVM.
The reason is mostly practical; for example it preserves the dominance
property of SSA. It is also just an overapproximation of the actual
number of uses; the incoming block could branch to another block in which
case the value is not actually used but there are no side-effects (it might
increase its live range which is not relevant in LCSSA though).
Furthermore, we can gain some intuition if we consider liveness:
A PHI is *usually* inserted in the current block because the value can't
be used from this point and onwards (i.e. the current block is a dominance
frontier). It doesn't make sense to consider that the value is used in
the current block (because of the PHI) since the value stops being live
before the PHI. In some sense the PHI definition just "replaces" the original
value definition and doesn't actually use it. It should be stressed that
this analogy is only used as an example and does not pose any strict
requirements. For example, the value might dominate the current block
but we can still insert a PHI (as we do with LCSSA PHI nodes) *and*
use the original value afterwards (in which case the two live ranges overlap,
although in LCSSA (the whole point is that) we never do that).
.. [#def-use-chain] A property of SSA is that there exists a def-use chain
for each definition, which is a list of all the uses of this definition.
LLVM implements this property by keeping a list of all the uses of a Value

View File

@ -431,6 +431,10 @@ static bool isBlockInLCSSAForm(const Loop &L, const BasicBlock &BB,
for (const Use &U : I.uses()) {
const Instruction *UI = cast<Instruction>(U.getUser());
const BasicBlock *UserBB = UI->getParent();
// For practical purposes, we consider that the use in a PHI
// occurs in the respective predecessor block. For more info,
// see the `phi` doc in LangRef and the LCSSA doc.
if (const PHINode *P = dyn_cast<PHINode>(UI))
UserBB = P->getIncomingBlock(U);

View File

@ -111,6 +111,10 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist,
for (Use &U : I->uses()) {
Instruction *User = cast<Instruction>(U.getUser());
BasicBlock *UserBB = User->getParent();
// For practical purposes, we consider that the use in a PHI
// occurs in the respective predecessor block. For more info,
// see the `phi` doc in LangRef and the LCSSA doc.
if (auto *PN = dyn_cast<PHINode>(User))
UserBB = PN->getIncomingBlock(U);
@ -160,7 +164,12 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist,
I->getName() + ".lcssa");
// Get the debug location from the original instruction.
PN->setDebugLoc(I->getDebugLoc());
// Add inputs from inside the loop for this PHI.
// Add inputs from inside the loop for this PHI. This is valid
// because `I` dominates `ExitBB` (checked above). This implies
// that every incoming block/edge is dominated by `I` as well,
// i.e. we can add uses of `I` to those incoming edges/append to the incoming
// blocks without violating the SSA dominance property.
for (BasicBlock *Pred : PredCache.get(ExitBB)) {
PN->addIncoming(I, Pred);
@ -194,15 +203,19 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist,
// Rewrite all uses outside the loop in terms of the new PHIs we just
// inserted.
for (Use *UseToRewrite : UsesToRewrite) {
Instruction *User = cast<Instruction>(UseToRewrite->getUser());
BasicBlock *UserBB = User->getParent();
// For practical purposes, we consider that the use in a PHI
// occurs in the respective predecessor block. For more info,
// see the `phi` doc in LangRef and the LCSSA doc.
if (auto *PN = dyn_cast<PHINode>(User))
UserBB = PN->getIncomingBlock(*UseToRewrite);
// If this use is in an exit block, rewrite to use the newly inserted PHI.
// This is required for correctness because SSAUpdate doesn't handle uses
// in the same block. It assumes the PHI we inserted is at the end of the
// block.
Instruction *User = cast<Instruction>(UseToRewrite->getUser());
BasicBlock *UserBB = User->getParent();
if (auto *PN = dyn_cast<PHINode>(User))
UserBB = PN->getIncomingBlock(*UseToRewrite);
if (isa<PHINode>(UserBB->begin()) && isExitBlock(UserBB, ExitBlocks)) {
UseToRewrite->set(&UserBB->front());
continue;