Index: llvm/trunk/include/llvm/Transforms/Utils/CodeExtractor.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Utils/CodeExtractor.h +++ llvm/trunk/include/llvm/Transforms/Utils/CodeExtractor.h @@ -106,6 +106,11 @@ /// returns false. Function *extractCodeRegion(); + /// Verify that assumption cache isn't stale after a region is extracted. + /// Returns false when verifier finds errors. AssumptionCache is passed as + /// parameter to make this function stateless. + static bool verifyAssumptionCache(const Function& F, AssumptionCache *AC); + /// Test whether this code extractor is eligible. /// /// Based on the blocks used when constructing the code extractor, Index: llvm/trunk/lib/Transforms/IPO/HotColdSplitting.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/HotColdSplitting.cpp +++ llvm/trunk/lib/Transforms/IPO/HotColdSplitting.cpp @@ -628,11 +628,6 @@ } while (!Region.empty()); } - // We need to explicitly clear the assumption cache since the value tracking - // may now be invalid as part of the function has changed. - if (Changed) - if (AssumptionCache *AC = LookupAC(F)) - AC->clear(); return Changed; } Index: llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp @@ -1301,13 +1301,6 @@ // Insert this basic block into the new function newBlocks.push_back(Block); - - // Remove @llvm.assume calls that were moved to the new function from the - // old function's assumption cache. - if (AC) - for (auto &I : *Block) - if (match(&I, m_Intrinsic())) - AC->unregisterAssumption(cast(&I)); } } @@ -1378,6 +1371,15 @@ } } + if (AC) { + // Remove @llvm.assume calls that were moved to the new function from the + // old function's assumption cache. + for (BasicBlock *Block : Blocks) + for (auto &I : *Block) + if (match(&I, m_Intrinsic())) + AC->unregisterAssumption(cast(&I)); + } + // If we have any return instructions in the region, split those blocks so // that the return is not in the region. splitReturnBlocks(); @@ -1568,5 +1570,17 @@ }); LLVM_DEBUG(if (verifyFunction(*oldFunction)) report_fatal_error("verification of oldFunction failed!")); + LLVM_DEBUG(if (AC && verifyAssumptionCache(*oldFunction, AC)) + report_fatal_error("Stale Asumption cache for old Function!")); return newFunction; } + +bool CodeExtractor::verifyAssumptionCache(const Function& F, + AssumptionCache *AC) { + for (auto AssumeVH : AC->assumptions()) { + CallInst *I = cast(AssumeVH); + if (I->getFunction() != &F) + return true; + } + return false; +} Index: llvm/trunk/test/Transforms/HotColdSplit/assumption-cache-invalidation.ll =================================================================== --- llvm/trunk/test/Transforms/HotColdSplit/assumption-cache-invalidation.ll +++ llvm/trunk/test/Transforms/HotColdSplit/assumption-cache-invalidation.ll @@ -1,3 +1,5 @@ +; REQUIRES: asserts +; RUN: opt -S -instsimplify -hotcoldsplit -debug < %s 2>&1 | FileCheck %s ; RUN: opt -instcombine -hotcoldsplit -instsimplify %s -o /dev/null target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" @@ -6,6 +8,16 @@ %a = type { i64, i64 } %b = type { i64 } +; CHECK: @f +; CHECK-LABEL: codeRepl: +; CHECK-NOT: @llvm.assume +; CHECK: } +; CHECK: declare {{.*}}@llvm.assume +; CHECK: define {{.*}}@f.cold.1(i64 %0) +; CHECK-LABEL: newFuncRoot: +; CHECK: %1 = icmp eq i64 %0, 0 +; CHECK: call void @llvm.assume(i1 %1) + define void @f() { entry: %0 = getelementptr inbounds %a, %a* null, i64 0, i32 1