mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-03-01 08:47:42 +00:00
[CodeExtractor] Remove stale llvm.assume calls from extracted region
During extraction, stale llvm.assume handles may be retained in the original function. The setup is: 1) CodeExtractor unregisters assumptions in the blocks that are to be extracted. 2) Extraction happens. There are now two functions: f1 and f1.extracted. 3) Leftover assumptions in f1 (/not/ removed as they were not in the set of blocks to be extracted) now have affected-value llvm.assume handles in f1.extracted. When assumptions for a value used in f1 are looked up, ValueTracking can assert as some of the handles are in the wrong function. To fix this, simply erase the llvm.assume calls in the extracted function. Alternatives include flushing the assumption cache in the original function, or walking all values used in the original function to prune stale affected-value handles. Both seem more expensive. Testing: check-llvm, LNT run with -mllvm -hot-cold-split enabled rdar://58460728
This commit is contained in:
parent
9b427c8e8d
commit
7bbbffcf9e
@ -140,9 +140,11 @@ public:
|
|||||||
Function *extractCodeRegion(const CodeExtractorAnalysisCache &CEAC);
|
Function *extractCodeRegion(const CodeExtractorAnalysisCache &CEAC);
|
||||||
|
|
||||||
/// Verify that assumption cache isn't stale after a region is extracted.
|
/// Verify that assumption cache isn't stale after a region is extracted.
|
||||||
/// Returns false when verifier finds errors. AssumptionCache is passed as
|
/// Returns true when verifier finds errors. AssumptionCache is passed as
|
||||||
/// parameter to make this function stateless.
|
/// parameter to make this function stateless.
|
||||||
static bool verifyAssumptionCache(const Function& F, AssumptionCache *AC);
|
static bool verifyAssumptionCache(const Function &OldFunc,
|
||||||
|
const Function &NewFunc,
|
||||||
|
AssumptionCache *AC);
|
||||||
|
|
||||||
/// Test whether this code extractor is eligible.
|
/// Test whether this code extractor is eligible.
|
||||||
///
|
///
|
||||||
|
@ -1531,13 +1531,19 @@ CodeExtractor::extractCodeRegion(const CodeExtractorAnalysisCache &CEAC) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AC) {
|
// Remove @llvm.assume calls that will be moved to the new function from the
|
||||||
// Remove @llvm.assume calls that were moved to the new function from the
|
// old function's assumption cache.
|
||||||
// old function's assumption cache.
|
for (BasicBlock *Block : Blocks) {
|
||||||
for (BasicBlock *Block : Blocks)
|
for (auto It = Block->begin(), End = Block->end(); It != End;) {
|
||||||
for (auto &I : *Block)
|
Instruction *I = &*It;
|
||||||
if (match(&I, m_Intrinsic<Intrinsic::assume>()))
|
++It;
|
||||||
AC->unregisterAssumption(cast<CallInst>(&I));
|
|
||||||
|
if (match(I, m_Intrinsic<Intrinsic::assume>())) {
|
||||||
|
if (AC)
|
||||||
|
AC->unregisterAssumption(cast<CallInst>(I));
|
||||||
|
I->eraseFromParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have any return instructions in the region, split those blocks so
|
// If we have any return instructions in the region, split those blocks so
|
||||||
@ -1711,17 +1717,36 @@ CodeExtractor::extractCodeRegion(const CodeExtractorAnalysisCache &CEAC) {
|
|||||||
});
|
});
|
||||||
LLVM_DEBUG(if (verifyFunction(*oldFunction))
|
LLVM_DEBUG(if (verifyFunction(*oldFunction))
|
||||||
report_fatal_error("verification of oldFunction failed!"));
|
report_fatal_error("verification of oldFunction failed!"));
|
||||||
LLVM_DEBUG(if (AC && verifyAssumptionCache(*oldFunction, AC))
|
LLVM_DEBUG(if (AC && verifyAssumptionCache(*oldFunction, *newFunction, AC))
|
||||||
report_fatal_error("Stale Asumption cache for old Function!"));
|
report_fatal_error("Stale Asumption cache for old Function!"));
|
||||||
return newFunction;
|
return newFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeExtractor::verifyAssumptionCache(const Function& F,
|
bool CodeExtractor::verifyAssumptionCache(const Function &OldFunc,
|
||||||
|
const Function &NewFunc,
|
||||||
AssumptionCache *AC) {
|
AssumptionCache *AC) {
|
||||||
for (auto AssumeVH : AC->assumptions()) {
|
for (auto AssumeVH : AC->assumptions()) {
|
||||||
CallInst *I = cast<CallInst>(AssumeVH);
|
CallInst *I = dyn_cast_or_null<CallInst>(AssumeVH);
|
||||||
if (I->getFunction() != &F)
|
if (!I)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// There shouldn't be any llvm.assume intrinsics in the new function.
|
||||||
|
if (I->getFunction() != &OldFunc)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// There shouldn't be any stale affected values in the assumption cache
|
||||||
|
// that were previously in the old function, but that have now been moved
|
||||||
|
// to the new function.
|
||||||
|
for (auto AffectedValVH : AC->assumptionsFor(I->getOperand(0))) {
|
||||||
|
CallInst *AffectedCI = dyn_cast_or_null<CallInst>(AffectedValVH);
|
||||||
|
if (!AffectedCI)
|
||||||
|
continue;
|
||||||
|
if (AffectedCI->getFunction() != &OldFunc)
|
||||||
|
return true;
|
||||||
|
auto *AssumedInst = dyn_cast<Instruction>(AffectedCI->getOperand(0));
|
||||||
|
if (AssumedInst->getFunction() != &OldFunc)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
; Make sure this compiles. Check that function assumption cache is refreshed
|
; Make sure this compiles. Check that function assumption cache is refreshed
|
||||||
; after extracting blocks with assume calls from the function.
|
; after extracting blocks with assume calls from the function.
|
||||||
|
|
||||||
; CHECK: Cached assumptions for function: fun
|
; CHECK: Cached assumptions for function: fun
|
||||||
; CHECK-NEXT: Cached assumptions for function: fun.cold
|
; CHECK-NEXT: Cached assumptions for function: fun.cold
|
||||||
; CHECK-NEXT: %cmp = icmp uge i32 %x, 64
|
; CHECK-NOT: icmp uge
|
||||||
|
|
||||||
declare void @fun2(i32) #0
|
declare void @fun2(i32) #0
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ target triple = "aarch64"
|
|||||||
; CHECK: define {{.*}}@f.cold.1(i64 %0)
|
; CHECK: define {{.*}}@f.cold.1(i64 %0)
|
||||||
; CHECK-LABEL: newFuncRoot:
|
; CHECK-LABEL: newFuncRoot:
|
||||||
; CHECK: %1 = icmp eq i64 %0, 0
|
; CHECK: %1 = icmp eq i64 %0, 0
|
||||||
; CHECK: call void @llvm.assume(i1 %1)
|
; CHECK-NOT: call void @llvm.assume
|
||||||
|
|
||||||
define void @f() {
|
define void @f() {
|
||||||
entry:
|
entry:
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
; RUN: opt -S -hotcoldsplit -hotcoldsplit-threshold=-1 < %s 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK-LABEL: define {{.*}} @foo(
|
||||||
|
; CHECK-NOT: llvm.assume
|
||||||
|
; CHECK: call void @foo.cold.1()
|
||||||
|
; CHECK: llvm.assume
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
|
||||||
|
; CHECK-LABEL: define {{.*}} @foo.cold.1(
|
||||||
|
; CHECK-NOT: llvm.assume
|
||||||
|
; CHECK: call void @cold()
|
||||||
|
; CHECK-NOT: llvm.assume
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
define void @foo(i1 %cond) {
|
||||||
|
entry:
|
||||||
|
br i1 %cond, label %cold, label %cont
|
||||||
|
|
||||||
|
cold:
|
||||||
|
call void @llvm.assume(i1 %cond)
|
||||||
|
call void @cold()
|
||||||
|
br label %cont
|
||||||
|
|
||||||
|
cont:
|
||||||
|
%cmp = icmp eq i1 %cond, true
|
||||||
|
br i1 %cmp, label %exit1, label %exit2
|
||||||
|
|
||||||
|
exit1:
|
||||||
|
call void @llvm.assume(i1 %cond)
|
||||||
|
ret void
|
||||||
|
|
||||||
|
exit2:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @llvm.assume(i1)
|
||||||
|
|
||||||
|
declare void @cold() cold
|
@ -280,6 +280,6 @@ TEST(CodeExtractor, ExtractAndInvalidateAssumptionCache) {
|
|||||||
EXPECT_TRUE(Outlined);
|
EXPECT_TRUE(Outlined);
|
||||||
EXPECT_FALSE(verifyFunction(*Outlined));
|
EXPECT_FALSE(verifyFunction(*Outlined));
|
||||||
EXPECT_FALSE(verifyFunction(*Func));
|
EXPECT_FALSE(verifyFunction(*Func));
|
||||||
EXPECT_FALSE(CE.verifyAssumptionCache(*Func, &AC));
|
EXPECT_FALSE(CE.verifyAssumptionCache(*Func, *Outlined, &AC));
|
||||||
}
|
}
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user