Index: include/llvm/Transforms/Scalar/GVN.h =================================================================== --- include/llvm/Transforms/Scalar/GVN.h +++ include/llvm/Transforms/Scalar/GVN.h @@ -274,7 +274,8 @@ 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 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,11 @@ while (!NewInsts.empty()) { Instruction *I = NewInsts.pop_back_val(); if (MD) MD->removeInstruction(I); + BasicBlock *IBB = I->getParent(); + bool IsFirstImplicitCF = isFirstImplicitControlFlowInstruction(I); I->eraseFromParent(); + if (IsFirstImplicitCF) + fillImplicitControlFlowInfo(IBB); } // HINT: Don't revert the edge-splitting as following transformation may // also need to split these critical edges. @@ -2099,7 +2103,11 @@ DEBUG(dbgs() << "GVN removed: " << **I << '\n'); if (MD) MD->removeInstruction(*I); DEBUG(verifyRemoved(*I)); + BasicBlock *IBB = (*I)->getParent(); + bool IsFirstImplicitCF = isFirstImplicitControlFlowInstruction(*I); (*I)->eraseFromParent(); + if (IsFirstImplicitCF) + fillImplicitControlFlowInfo(IBB); } if (!InstrsToErase.empty()) @@ -2298,7 +2306,11 @@ if (MD) MD->removeInstruction(CurInst); DEBUG(verifyRemoved(CurInst)); + + bool IsFirstImplicitCF = isFirstImplicitControlFlowInstruction(CurInst); CurInst->eraseFromParent(); + if (IsFirstImplicitCF) + fillImplicitControlFlowInfo(CurrentBlock); OI->invalidateBlock(CurrentBlock); ++NumGVNInstr; @@ -2366,7 +2378,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); @@ -2382,7 +2396,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 @@ -2410,13 +2424,21 @@ } 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) { + assert(I->getParent() && "Instruction already erased?"); + auto It = FirstImplicitControlFlowInsts.find(I->getParent()); + if (It == FirstImplicitControlFlowInsts.end()) + return false; + return It->second == I; } /// 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 }