1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

[GVN] Update BlockRPONumber prior to use.

Summary:
The original patch addressed the use of BlockRPONumber by forcing a sequence point when accessing that map in a conditional.  In short we found cases where that map was being accessed with blocks that had not yet been added to that structure.  For context, I've kept the wall of text below,  to what we are trying to fix, by always ensuring a updated BlockRPONumber.

== Backstory ==

I was investigating an ICE (segfault accessing a DenseMap item).  This failure happened non-deterministically, with no apparent reason and only on a Windows build of LLVM (from October 2018).

After looking into the crashes (multiple core files) and running DynamoRio, the cores and DynamoRio (DR) log pointed to the same code in `GVN::performScalarPRE()`. The values in the map are unsigned integers, the keys are `llvm::BasicBlock*`.  Our test case that triggered this warning and periodic crash is rather involved.  But the problematic line looks to be:

GVN.cpp: Line 2197

```
     if (BlockRPONumber[P] >= BlockRPONumber[CurrentBlock] &&
```

To test things out, I cooked up a patch that accessed the items in the map outside of the condition, by forcing a sequence point between accesses. DynamoRio stopped warning of the issue, and the test didn't seem to crash after 1000+ runs.

My investigation was on an older version of LLVM, (source from October this year). What it looks like was occurring is the following, and the assembly from the latest pull of llvm in December seems to confirm this might still be an issue; however, I have not witnessed the crash on more recent builds. Of course the asm in question is generated from the host compiler on that Windows box (not clang), but it hints that we might want to consider how we access the BlockRPONumber map in this conditional (line 2197, listed above).  In any case, I don't think the host compiler is wrong, rather I think it is pointing out a possibly latent bug in llvm.

1) There is no sequence point for the `>=` operation.

2) A call to a `DenseMapBase::operator[]` can have the side effect of the map reallocating a larger store (more Buckets, via a call to `DenseMap::grow`).

3) It seems perfectly legal for a host compiler to generate assembly that stores the result of a call to `operator[]` on the stack (that's what my host compile of GVN.cpp is doing) .  A second call to `operator[]` //might// encourage the map to 'grow' thus making any pointers to the map's store invalid.  The `>=` compares the first and second values. If the first happens to be a pointer produced from operator[], it could be invalid when dereferenced at the time of comparison.

The assembly generated from the Window's host compiler does show the result of the first access to the map via `operator[]` produces a pointer to an unsigned int.  And that pointer is being stored on  the stack.  If a second call to the map (which does occur) causes the map to grow, that address (on the stack) is now invalid. 

Reviewers: t.p.northover, efriedma

Reviewed By: efriedma

Subscribers: efriedma, llvm-commits

Differential Revision: https://reviews.llvm.org/D55974

llvm-svn: 350880
This commit is contained in:
Matt Davis 2019-01-10 19:56:03 +00:00
parent dec3dec827
commit 6ec1969254
2 changed files with 19 additions and 2 deletions

View File

@ -27,6 +27,7 @@
#include "llvm/IR/Dominators.h" #include "llvm/IR/Dominators.h"
#include "llvm/IR/InstrTypes.h" #include "llvm/IR/InstrTypes.h"
#include "llvm/IR/PassManager.h" #include "llvm/IR/PassManager.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Allocator.h" #include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
#include <cstdint> #include <cstdint>
@ -180,7 +181,12 @@ private:
// Map the block to reversed postorder traversal number. It is used to // Map the block to reversed postorder traversal number. It is used to
// find back edge easily. // find back edge easily.
DenseMap<const BasicBlock *, uint32_t> BlockRPONumber; DenseMap<AssertingVH<BasicBlock>, uint32_t> BlockRPONumber;
// This is set 'true' initially and also when new blocks have been added to
// the function being analyzed. This boolean is used to control the updating
// of BlockRPONumber prior to accessing the contents of BlockRPONumber.
bool InvalidBlockRPONumbers = true;
using LoadDepVect = SmallVector<NonLocalDepResult, 64>; using LoadDepVect = SmallVector<NonLocalDepResult, 64>;
using AvailValInBlkVect = SmallVector<gvn::AvailableValueInBlock, 64>; using AvailValInBlkVect = SmallVector<gvn::AvailableValueInBlock, 64>;

View File

@ -1645,10 +1645,12 @@ static bool isOnlyReachableViaThisEdge(const BasicBlockEdge &E,
} }
void GVN::assignBlockRPONumber(Function &F) { void GVN::assignBlockRPONumber(Function &F) {
BlockRPONumber.clear();
uint32_t NextBlockNumber = 1; uint32_t NextBlockNumber = 1;
ReversePostOrderTraversal<Function *> RPOT(&F); ReversePostOrderTraversal<Function *> RPOT(&F);
for (BasicBlock *BB : RPOT) for (BasicBlock *BB : RPOT)
BlockRPONumber[BB] = NextBlockNumber++; BlockRPONumber[BB] = NextBlockNumber++;
InvalidBlockRPONumbers = false;
} }
// Tries to replace instruction with const, using information from // Tries to replace instruction with const, using information from
@ -1992,6 +1994,7 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
ICF = &ImplicitCFT; ICF = &ImplicitCFT;
VN.setMemDep(MD); VN.setMemDep(MD);
ORE = RunORE; ORE = RunORE;
InvalidBlockRPONumbers = true;
bool Changed = false; bool Changed = false;
bool ShouldContinue = true; bool ShouldContinue = true;
@ -2021,7 +2024,6 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
// Fabricate val-num for dead-code in order to suppress assertion in // Fabricate val-num for dead-code in order to suppress assertion in
// performPRE(). // performPRE().
assignValNumForDeadCode(); assignValNumForDeadCode();
assignBlockRPONumber(F);
bool PREChanged = true; bool PREChanged = true;
while (PREChanged) { while (PREChanged) {
PREChanged = performPRE(F); PREChanged = performPRE(F);
@ -2183,6 +2185,10 @@ bool GVN::performScalarPRE(Instruction *CurInst) {
BasicBlock *PREPred = nullptr; BasicBlock *PREPred = nullptr;
BasicBlock *CurrentBlock = CurInst->getParent(); BasicBlock *CurrentBlock = CurInst->getParent();
// Update the RPO numbers for this function.
if (InvalidBlockRPONumbers)
assignBlockRPONumber(*CurrentBlock->getParent());
SmallVector<std::pair<Value *, BasicBlock *>, 8> predMap; SmallVector<std::pair<Value *, BasicBlock *>, 8> predMap;
for (BasicBlock *P : predecessors(CurrentBlock)) { for (BasicBlock *P : predecessors(CurrentBlock)) {
// We're not interested in PRE where blocks with predecessors that are // We're not interested in PRE where blocks with predecessors that are
@ -2194,6 +2200,8 @@ bool GVN::performScalarPRE(Instruction *CurInst) {
// It is not safe to do PRE when P->CurrentBlock is a loop backedge, and // It is not safe to do PRE when P->CurrentBlock is a loop backedge, and
// when CurInst has operand defined in CurrentBlock (so it may be defined // when CurInst has operand defined in CurrentBlock (so it may be defined
// by phi in the loop header). // by phi in the loop header).
assert(BlockRPONumber.count(P) && BlockRPONumber.count(CurrentBlock) &&
"Invalid BlockRPONumber map.");
if (BlockRPONumber[P] >= BlockRPONumber[CurrentBlock] && if (BlockRPONumber[P] >= BlockRPONumber[CurrentBlock] &&
llvm::any_of(CurInst->operands(), [&](const Use &U) { llvm::any_of(CurInst->operands(), [&](const Use &U) {
if (auto *Inst = dyn_cast<Instruction>(U.get())) if (auto *Inst = dyn_cast<Instruction>(U.get()))
@ -2341,6 +2349,7 @@ BasicBlock *GVN::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) {
SplitCriticalEdge(Pred, Succ, CriticalEdgeSplittingOptions(DT)); SplitCriticalEdge(Pred, Succ, CriticalEdgeSplittingOptions(DT));
if (MD) if (MD)
MD->invalidateCachedPredecessors(); MD->invalidateCachedPredecessors();
InvalidBlockRPONumbers = true;
return BB; return BB;
} }
@ -2355,6 +2364,7 @@ bool GVN::splitCriticalEdges() {
CriticalEdgeSplittingOptions(DT)); CriticalEdgeSplittingOptions(DT));
} while (!toSplit.empty()); } while (!toSplit.empty());
if (MD) MD->invalidateCachedPredecessors(); if (MD) MD->invalidateCachedPredecessors();
InvalidBlockRPONumbers = true;
return true; return true;
} }
@ -2381,6 +2391,7 @@ void GVN::cleanupGlobalSets() {
BlockRPONumber.clear(); BlockRPONumber.clear();
TableAllocator.Reset(); TableAllocator.Reset();
ICF->clear(); ICF->clear();
InvalidBlockRPONumbers = true;
} }
/// Verify that the specified instruction does not occur in our /// Verify that the specified instruction does not occur in our