This adds a new pass for dropping assumes that are unlikely to be useful for further optimization. It works by discarding any assumes whose affected values are one-use (which implies that they are only used by the assume, i.e. ephemeral). This pass currently runs at the start of the module optimization pipeline, that is post-inline and post-link. Before that point, it is more likely for previously "useless" assumes to become useful again, e.g. because an additional user of the value is introduced after inlining + CSE.
63 lines
2.1 KiB
C++
63 lines
2.1 KiB
C++
//===------------------------------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Transforms/Scalar/DropUnnecessaryAssumes.h"
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
#include "llvm/Analysis/ValueTracking.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/PatternMatch.h"
|
|
#include "llvm/Transforms/Utils/Local.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::PatternMatch;
|
|
|
|
PreservedAnalyses
|
|
DropUnnecessaryAssumesPass::run(Function &F, FunctionAnalysisManager &FAM) {
|
|
AssumptionCache &AC = FAM.getResult<AssumptionAnalysis>(F);
|
|
bool Changed = false;
|
|
|
|
for (AssumptionCache::ResultElem &Elem : AC.assumptions()) {
|
|
auto *Assume = cast_or_null<AssumeInst>(Elem.Assume);
|
|
if (!Assume)
|
|
continue;
|
|
|
|
// TODO: Handle assumes with operand bundles.
|
|
if (Assume->hasOperandBundles())
|
|
continue;
|
|
|
|
Value *Cond = Assume->getArgOperand(0);
|
|
// Don't drop type tests, which have special semantics.
|
|
if (match(Cond, m_Intrinsic<Intrinsic::type_test>()))
|
|
continue;
|
|
|
|
SmallPtrSet<Value *, 8> Affected;
|
|
findValuesAffectedByCondition(Cond, /*IsAssume=*/true,
|
|
[&](Value *A) { Affected.insert(A); });
|
|
|
|
// If all the affected uses have only one use (part of the assume), then
|
|
// the assume does not provide useful information. Note that additional
|
|
// users may appear as a result of inlining and CSE, so we should only
|
|
// make this assumption late in the optimization pipeline.
|
|
// TODO: Handle dead cyclic usages.
|
|
// TODO: Handle multiple dead assumes on the same value.
|
|
if (!all_of(Affected, match_fn(m_OneUse(m_Value()))))
|
|
continue;
|
|
|
|
Assume->eraseFromParent();
|
|
RecursivelyDeleteTriviallyDeadInstructions(Cond);
|
|
Changed = true;
|
|
}
|
|
|
|
if (Changed) {
|
|
PreservedAnalyses PA;
|
|
PA.preserveSet<CFGAnalyses>();
|
|
return PA;
|
|
}
|
|
return PreservedAnalyses::all();
|
|
}
|