Index: include/llvm/Transforms/Scalar/GVN.h =================================================================== --- include/llvm/Transforms/Scalar/GVN.h +++ include/llvm/Transforms/Scalar/GVN.h @@ -274,7 +274,9 @@ BasicBlock *Curr, unsigned int ValNo); Value *findLeader(const BasicBlock *BB, uint32_t num); void cleanupGlobalSets(); - void fillImplicitControlFlowInfo(ReversePostOrderTraversal &RPOT); + void fillImplicitControlFlowInfo(BasicBlock *BB); + bool isFirstImplicitControlFlowInstruction(Instruction *I); + void eraseFromParent(Instruction *I); void verifyRemoved(const Instruction *I) const; bool splitCriticalEdges(); BasicBlock *splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ); Index: lib/Transforms/Scalar/GVN.cpp =================================================================== --- lib/Transforms/Scalar/GVN.cpp +++ lib/Transforms/Scalar/GVN.cpp @@ -1199,7 +1199,7 @@ while (!NewInsts.empty()) { Instruction *I = NewInsts.pop_back_val(); if (MD) MD->removeInstruction(I); - I->eraseFromParent(); + eraseFromParent(I); } // HINT: Don't revert the edge-splitting as following transformation may // also need to split these critical edges. @@ -2103,11 +2103,9 @@ DEBUG(dbgs() << "GVN removed: " << **I << '\n'); if (MD) MD->removeInstruction(*I); DEBUG(verifyRemoved(*I)); - (*I)->eraseFromParent(); + eraseFromParent(*I); } - if (!InstrsToErase.empty()) - OI->invalidateBlock(BB); InstrsToErase.clear(); if (AtStart) @@ -2302,8 +2300,7 @@ if (MD) MD->removeInstruction(CurInst); DEBUG(verifyRemoved(CurInst)); - CurInst->eraseFromParent(); - OI->invalidateBlock(CurrentBlock); + eraseFromParent(CurInst); ++NumGVNInstr; return true; @@ -2370,7 +2367,9 @@ // RPOT walks the graph in its constructor and will not be invalidated during // processBlock. ReversePostOrderTraversal RPOT(&F); - fillImplicitControlFlowInfo(RPOT); + + for (BasicBlock *BB : RPOT) + fillImplicitControlFlowInfo(BB); for (BasicBlock *BB : RPOT) Changed |= processBlock(BB); @@ -2386,7 +2385,7 @@ } void -GVN::fillImplicitControlFlowInfo(ReversePostOrderTraversal &RPOT) { +GVN::fillImplicitControlFlowInfo(BasicBlock *BB) { auto MayNotTransferExecutionToSuccessor = [&](const Instruction *I) { // If a block's instruction doesn't always pass the control to its successor // instruction, mark the block as having implicit control flow. We use them @@ -2414,13 +2413,33 @@ } return true; }; + FirstImplicitControlFlowInsts.erase(BB); - for (BasicBlock *BB : RPOT) - for (auto &I : *BB) - if (MayNotTransferExecutionToSuccessor(&I)) { - FirstImplicitControlFlowInsts[BB] = &I; - break; - } + for (auto &I : *BB) + if (MayNotTransferExecutionToSuccessor(&I)) { + FirstImplicitControlFlowInsts[BB] = &I; + break; + } +} + +bool GVN::isFirstImplicitControlFlowInstruction(Instruction *I) { + auto It = FirstImplicitControlFlowInsts.find(I->getParent()); + if (It == FirstImplicitControlFlowInsts.end()) + return false; + return It->second == I; +} + +void GVN::eraseFromParent(Instruction *I) { + BasicBlock *BB = I->getParent(); + assert(BB && "Instruction has already been erased?"); + // Pay respect to the fact that if we remove the first instruction with + // implicit control flow, we should update FirstImplicitControlFlowInsts + // accordingly. + bool IsFirstImplicitCF = isFirstImplicitControlFlowInstruction(I); + I->eraseFromParent(); + if (IsFirstImplicitCF) + fillImplicitControlFlowInfo(BB); + OI->invalidateBlock(BB); } /// Verify that the specified instruction does not occur in our Index: test/Transforms/GVN/PRE/2017-10-16-LoadPRECrash.ll =================================================================== --- test/Transforms/GVN/PRE/2017-10-16-LoadPRECrash.ll +++ test/Transforms/GVN/PRE/2017-10-16-LoadPRECrash.ll @@ -0,0 +1,31 @@ +; RUN: opt -S -gvn -enable-load-pre < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%ArrayImpl = type { i64, i64 addrspace(100)*, [1 x i64], [1 x i64], [1 x i64], i64, i64, double addrspace(100)*, double addrspace(100)*, i8, i64 } + +; Function Attrs: readnone +declare %ArrayImpl* @getaddr_ArrayImpl(%ArrayImpl addrspace(100)*) #0 + +; Function Attrs: readnone +declare i64* @getaddr_i64(i64 addrspace(100)*) #0 + +; Make sure that the test compiles without a crash. + +define hidden void @wrapon_fn173() { + +; CHECK-LABEL: @wrapon_fn173 + +entry: + %0 = call %ArrayImpl* @getaddr_ArrayImpl(%ArrayImpl addrspace(100)* undef) + br label %loop + +loop: + %1 = call %ArrayImpl* @getaddr_ArrayImpl(%ArrayImpl addrspace(100)* undef) + %2 = load i64 addrspace(100)*, i64 addrspace(100)** null, align 8 + %3 = call i64* @getaddr_i64(i64 addrspace(100)* %2) + br label %loop +} + +attributes #0 = { readnone }