Skip to content

Commit

Permalink
Recommit r333268: [IPSCCP] Use PredicateInfo to propagate facts from …
Browse files Browse the repository at this point in the history
…cmp instructions.

This version of the patch fixes cleaning up ssa_copy intrinsics, so it does not
crash for instructions in blocks that have been marked unreachable.

This patch updates IPSCCP to use PredicateInfo to propagate
facts to true branches predicated by EQ and to false branches
predicated by NE.

As a follow up, we should be able to extend it to also propagate additional
facts about nonnull.

Reviewers: davide, mssimpso, dberlin, efriedma

Reviewed By: davide, dberlin

Differential Revision: https://reviews.llvm.org/D45330

llvm-svn: 340525
  • Loading branch information
fhahn committed Aug 23, 2018
1 parent 9f356dd commit 3052290
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 15 deletions.
6 changes: 5 additions & 1 deletion llvm/include/llvm/Transforms/Scalar/SCCP.h
Expand Up @@ -21,11 +21,13 @@
#ifndef LLVM_TRANSFORMS_SCALAR_SCCP_H
#define LLVM_TRANSFORMS_SCALAR_SCCP_H

#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Transforms/Utils/PredicateInfo.h"

namespace llvm {

Expand All @@ -37,7 +39,9 @@ class SCCPPass : public PassInfoMixin<SCCPPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};

bool runIPSCCP(Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI);
bool runIPSCCP(
Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo);
} // end namespace llvm

#endif // LLVM_TRANSFORMS_SCALAR_SCCP_H
24 changes: 22 additions & 2 deletions llvm/lib/Transforms/IPO/SCCP.cpp
@@ -1,4 +1,5 @@
#include "llvm/Transforms/IPO/SCCP.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar/SCCP.h"
Expand All @@ -8,7 +9,15 @@ using namespace llvm;
PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) {
const DataLayout &DL = M.getDataLayout();
auto &TLI = AM.getResult<TargetLibraryAnalysis>(M);
if (!runIPSCCP(M, DL, &TLI))
auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto getPredicateInfo =
[&FAM](Function &F) -> std::unique_ptr<PredicateInfo> {
return make_unique<PredicateInfo>(F,
FAM.getResult<DominatorTreeAnalysis>(F),
FAM.getResult<AssumptionAnalysis>(F));
};

if (!runIPSCCP(M, DL, &TLI, getPredicateInfo))
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
Expand All @@ -34,10 +43,20 @@ class IPSCCPLegacyPass : public ModulePass {
const DataLayout &DL = M.getDataLayout();
const TargetLibraryInfo *TLI =
&getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
return runIPSCCP(M, DL, TLI);

auto getPredicateInfo =
[this](Function &F) -> std::unique_ptr<PredicateInfo> {
return make_unique<PredicateInfo>(
F, this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(),
this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F));
};

return runIPSCCP(M, DL, TLI, getPredicateInfo);
}

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
}
};
Expand All @@ -49,6 +68,7 @@ char IPSCCPLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(IPSCCPLegacyPass, "ipsccp",
"Interprocedural Sparse Conditional Constant Propagation",
false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(IPSCCPLegacyPass, "ipsccp",
"Interprocedural Sparse Conditional Constant Propagation",
Expand Down
123 changes: 115 additions & 8 deletions llvm/lib/Transforms/Scalar/SCCP.cpp
Expand Up @@ -55,6 +55,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/PredicateInfo.h"
#include <cassert>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -246,7 +247,21 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
using Edge = std::pair<BasicBlock *, BasicBlock *>;
DenseSet<Edge> KnownFeasibleEdges;

DenseMap<Function *, std::unique_ptr<PredicateInfo>> PredInfos;
DenseMap<Value *, SmallPtrSet<User *, 2>> AdditionalUsers;

public:
void addPredInfo(Function &F, std::unique_ptr<PredicateInfo> PI) {
PredInfos[&F] = std::move(PI);
}

const PredicateBase *getPredicateInfoFor(Instruction *I) {
auto PI = PredInfos.find(I->getFunction());
if (PI == PredInfos.end())
return nullptr;
return PI->second->getPredicateInfoFor(I);
}

SCCPSolver(const DataLayout &DL, const TargetLibraryInfo *tli)
: DL(DL), TLI(tli) {}

Expand Down Expand Up @@ -558,6 +573,26 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
visit(*I);
}

// Add U as additional user of V.
void addAdditionalUser(Value *V, User *U) {
auto Iter = AdditionalUsers.insert({V, {}});
Iter.first->second.insert(U);
}

// Mark I's users as changed, including AdditionalUsers.
void markUsersAsChanged(Value *I) {
for (User *U : I->users())
if (auto *UI = dyn_cast<Instruction>(U))
OperandChangedState(UI);

auto Iter = AdditionalUsers.find(I);
if (Iter != AdditionalUsers.end()) {
for (User *U : Iter->second)
if (auto *UI = dyn_cast<Instruction>(U))
OperandChangedState(UI);
}
}

private:
friend class InstVisitor<SCCPSolver>;

Expand Down Expand Up @@ -1119,6 +1154,65 @@ void SCCPSolver::visitCallSite(CallSite CS) {
Function *F = CS.getCalledFunction();
Instruction *I = CS.getInstruction();

if (auto *II = dyn_cast<IntrinsicInst>(I)) {
if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
if (ValueState[I].isOverdefined())
return;

auto *PI = getPredicateInfoFor(I);
if (!PI)
return;

auto *PBranch = dyn_cast<PredicateBranch>(getPredicateInfoFor(I));
if (!PBranch) {
mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
return;
}

Value *CopyOf = I->getOperand(0);
Value *Cond = PBranch->Condition;

// Everything below relies on the condition being a comparison.
auto *Cmp = dyn_cast<CmpInst>(Cond);
if (!Cmp) {
mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
return;
}

Value *CmpOp0 = Cmp->getOperand(0);
Value *CmpOp1 = Cmp->getOperand(1);
if (CopyOf != CmpOp0 && CopyOf != CmpOp1) {
mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
return;
}

if (CmpOp0 != CopyOf)
std::swap(CmpOp0, CmpOp1);

LatticeVal OriginalVal = getValueState(CopyOf);
LatticeVal EqVal = getValueState(CmpOp1);
LatticeVal &IV = ValueState[I];
if (PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_EQ) {
addAdditionalUser(CmpOp1, I);
if (OriginalVal.isConstant())
mergeInValue(IV, I, OriginalVal);
else
mergeInValue(IV, I, EqVal);
return;
}
if (!PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_NE) {
addAdditionalUser(CmpOp1, I);
if (OriginalVal.isConstant())
mergeInValue(IV, I, OriginalVal);
else
mergeInValue(IV, I, EqVal);
return;
}

return (void)mergeInValue(IV, I, getValueState(PBranch->OriginalOp));
}
}

// The common case is that we aren't tracking the callee, either because we
// are not doing interprocedural analysis or the callee is indirect, or is
// external. Handle these cases first.
Expand Down Expand Up @@ -1238,9 +1332,7 @@ void SCCPSolver::Solve() {
// since all of its users will have already been marked as overdefined
// Update all of the users of this instruction's value.
//
for (User *U : I->users())
if (auto *UI = dyn_cast<Instruction>(U))
OperandChangedState(UI);
markUsersAsChanged(I);
}

// Process the instruction work list.
Expand All @@ -1257,9 +1349,7 @@ void SCCPSolver::Solve() {
// Update all of the users of this instruction's value.
//
if (I->getType()->isStructTy() || !getValueState(I).isOverdefined())
for (User *U : I->users())
if (auto *UI = dyn_cast<Instruction>(U))
OperandChangedState(UI);
markUsersAsChanged(I);
}

// Process the basic block work list.
Expand Down Expand Up @@ -1798,8 +1888,9 @@ static void findReturnsToZap(Function &F,
}
}

bool llvm::runIPSCCP(Module &M, const DataLayout &DL,
const TargetLibraryInfo *TLI) {
bool llvm::runIPSCCP(
Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo) {
SCCPSolver Solver(DL, TLI);

// Loop over all functions, marking arguments to those with their addresses
Expand All @@ -1808,6 +1899,7 @@ bool llvm::runIPSCCP(Module &M, const DataLayout &DL,
if (F.isDeclaration())
continue;

Solver.addPredInfo(F, getPredicateInfo(F));
// Determine if we can track the function's return values. If so, add the
// function to the solver's set of return-tracked functions.
if (canTrackReturnsInterprocedurally(&F))
Expand Down Expand Up @@ -1960,6 +2052,21 @@ bool llvm::runIPSCCP(Module &M, const DataLayout &DL,
F.getBasicBlockList().erase(DeadBB);
}
BlocksToErase.clear();

for (BasicBlock &BB : F) {
for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) {
Instruction *Inst = &*BI++;
if (const PredicateBase *PI = Solver.getPredicateInfoFor(Inst)) {
if (auto *II = dyn_cast<IntrinsicInst>(Inst)) {
if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
Value *Op = II->getOperand(0);
Inst->replaceAllUsesWith(Op);
Inst->eraseFromParent();
}
}
}
}
}
}

// If we inferred constant or undef return values for a function, we replaced
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Other/new-pm-lto-defaults.ll
Expand Up @@ -41,6 +41,8 @@
; CHECK-O2-NEXT: Running analysis: ProfileSummaryAnalysis
; CHECK-O2-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O2-NEXT: Running pass: IPSCCPPass
; CHECK-O2-DAG: Running analysis: AssumptionAnalysis on foo
; CHECK-O2-DAG: Running analysis: DominatorTreeAnalysis on foo
; CHECK-O2-NEXT: Running pass: CalledValuePropagationPass
; CHECK-O-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}PostOrderFunctionAttrsPass>
; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}SCC
Expand All @@ -57,8 +59,6 @@
; CHECK-O1-NEXT: Running pass: LowerTypeTestsPass
; CHECK-O2-NEXT: Running pass: GlobalOptPass
; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PromotePass>
; CHECK-O2-NEXT: Running analysis: DominatorTreeAnalysis
; CHECK-O2-NEXT: Running analysis: AssumptionAnalysis
; CHECK-O2-NEXT: Running pass: ConstantMergePass
; CHECK-O2-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}>
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Other/opt-O2-pipeline.ll
Expand Up @@ -28,6 +28,7 @@
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
Expand Down Expand Up @@ -277,6 +278,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Other/opt-O3-pipeline.ll
Expand Up @@ -30,6 +30,7 @@
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Call-site splitting
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
Expand Down Expand Up @@ -281,6 +282,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Other/opt-Os-pipeline.ll
Expand Up @@ -28,6 +28,7 @@
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
Expand Down Expand Up @@ -264,6 +265,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/IPConstantProp/musttail-call.ll
Expand Up @@ -9,7 +9,7 @@ define i8* @start(i8 %v) {
%c1 = icmp eq i8 %v, 0
br i1 %c1, label %true, label %false
true:
; CHECK: %ca = musttail call i8* @side_effects(i8 %v)
; CHECK: %ca = musttail call i8* @side_effects(i8 0)
; CHECK: ret i8* %ca
%ca = musttail call i8* @side_effects(i8 %v)
ret i8* %ca
Expand All @@ -34,7 +34,7 @@ define internal i8* @side_effects(i8 %v) {
; is always `null`.
; The call can't be removed due to `external` call above, though.

; CHECK: %ca = musttail call i8* @start(i8 %v)
; CHECK: %ca = musttail call i8* @start(i8 0)
%ca = musttail call i8* @start(i8 %v)

; Thus the result must be returned anyway
Expand Down

0 comments on commit 3052290

Please sign in to comment.