[Transforms] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC).
llvm-svn: 316241
This commit is contained in:
parent
12fd3da9d1
commit
99241d75c1
|
@ -1,4 +1,4 @@
|
|||
//===----- NewGVN.h - Global Value Numbering Pass ---------------*- C++ -*-===//
|
||||
//===- NewGVN.h - Global Value Numbering Pass -------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -6,9 +6,10 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// This file provides the interface for LLVM's Global Value Numbering pass.
|
||||
///
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_SCALAR_NEWGVN_H
|
||||
|
@ -17,12 +18,16 @@
|
|||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
|
||||
class NewGVNPass : public PassInfoMixin<NewGVNPass> {
|
||||
public:
|
||||
/// \brief Run the pass over the function.
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_TRANSFORMS_SCALAR_NEWGVN_H
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
//
|
||||
// \file
|
||||
// This file implements sparse conditional constant propagation and merging:
|
||||
//
|
||||
// Specifically, this:
|
||||
|
@ -15,22 +16,23 @@
|
|||
// * Proves values to be constant, and replaces them with constants
|
||||
// * Proves conditional branches to be unconditional
|
||||
//
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_SCALAR_SCCP_H
|
||||
#define LLVM_TRANSFORMS_SCALAR_SCCP_H
|
||||
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
|
||||
/// This pass performs function-level constant propagation and merging.
|
||||
class SCCPPass : public PassInfoMixin<SCCPPass> {
|
||||
public:
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_TRANSFORMS_SCALAR_SCCP_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===---- NewGVN.cpp - Global Value Numbering Pass --------------*- C++ -*-===//
|
||||
//===- NewGVN.cpp - Global Value Numbering Pass ---------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -6,6 +6,7 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// This file implements the new LLVM's Global Value Numbering pass.
|
||||
/// GVN partitions values computed by a function into congruence classes.
|
||||
|
@ -48,39 +49,81 @@
|
|||
/// published algorithms are O(Instructions). Instead, we use a technique that
|
||||
/// is O(number of operations with the same value number), enabling us to skip
|
||||
/// trying to eliminate things that have unique value numbers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Scalar/NewGVN.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SparseBitVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/Analysis/CFG.h"
|
||||
#include "llvm/Analysis/CFGPrinter.h"
|
||||
#include "llvm/Analysis/ConstantFolding.h"
|
||||
#include "llvm/Analysis/GlobalsModRef.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||
#include "llvm/Analysis/MemorySSA.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Use.h"
|
||||
#include "llvm/IR/User.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/ArrayRecycler.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/DebugCounter.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Scalar/GVNExpression.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/PredicateInfo.h"
|
||||
#include "llvm/Transforms/Utils/VNCoercion.h"
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace PatternMatch;
|
||||
using namespace llvm::GVNExpression;
|
||||
using namespace llvm::VNCoercion;
|
||||
|
||||
#define DEBUG_TYPE "newgvn"
|
||||
|
||||
STATISTIC(NumGVNInstrDeleted, "Number of instructions deleted");
|
||||
|
@ -118,6 +161,7 @@ static cl::opt<bool> EnablePhiOfOps("enable-phi-of-ops", cl::init(true),
|
|||
// Anchor methods.
|
||||
namespace llvm {
|
||||
namespace GVNExpression {
|
||||
|
||||
Expression::~Expression() = default;
|
||||
BasicExpression::~BasicExpression() = default;
|
||||
CallExpression::~CallExpression() = default;
|
||||
|
@ -125,10 +169,12 @@ LoadExpression::~LoadExpression() = default;
|
|||
StoreExpression::~StoreExpression() = default;
|
||||
AggregateValueExpression::~AggregateValueExpression() = default;
|
||||
PHIExpression::~PHIExpression() = default;
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace GVNExpression
|
||||
} // end namespace llvm
|
||||
|
||||
namespace {
|
||||
|
||||
// Tarjan's SCC finding algorithm with Nuutila's improvements
|
||||
// SCCIterator is actually fairly complex for the simple thing we want.
|
||||
// It also wants to hand us SCC's that are unrelated to the phi node we ask
|
||||
|
@ -138,7 +184,6 @@ namespace {
|
|||
// instructions,
|
||||
// not generic values (arguments, etc).
|
||||
struct TarjanSCC {
|
||||
|
||||
TarjanSCC() : Components(1) {}
|
||||
|
||||
void Start(const Instruction *Start) {
|
||||
|
@ -193,15 +238,19 @@ private:
|
|||
Stack.push_back(I);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int DFSNum = 1;
|
||||
SmallPtrSet<const Value *, 8> InComponent;
|
||||
DenseMap<const Value *, unsigned int> Root;
|
||||
SmallVector<const Value *, 8> Stack;
|
||||
|
||||
// Store the components as vector of ptr sets, because we need the topo order
|
||||
// of SCC's, but not individual member order
|
||||
SmallVector<SmallPtrSet<const Value *, 8>, 8> Components;
|
||||
|
||||
DenseMap<const Value *, unsigned> ValueToComponent;
|
||||
};
|
||||
|
||||
// Congruence classes represent the set of expressions/instructions
|
||||
// that are all the same *during some scope in the function*.
|
||||
// That is, because of the way we perform equality propagation, and
|
||||
|
@ -250,7 +299,9 @@ public:
|
|||
explicit CongruenceClass(unsigned ID) : ID(ID) {}
|
||||
CongruenceClass(unsigned ID, Value *Leader, const Expression *E)
|
||||
: ID(ID), RepLeader(Leader), DefiningExpr(E) {}
|
||||
|
||||
unsigned getID() const { return ID; }
|
||||
|
||||
// True if this class has no members left. This is mainly used for assertion
|
||||
// purposes, and for skipping empty classes.
|
||||
bool isDead() const {
|
||||
|
@ -258,6 +309,7 @@ public:
|
|||
// perspective, it's really dead.
|
||||
return empty() && memory_empty();
|
||||
}
|
||||
|
||||
// Leader functions
|
||||
Value *getLeader() const { return RepLeader; }
|
||||
void setLeader(Value *Leader) { RepLeader = Leader; }
|
||||
|
@ -265,7 +317,6 @@ public:
|
|||
return NextLeader;
|
||||
}
|
||||
void resetNextLeader() { NextLeader = {nullptr, ~0}; }
|
||||
|
||||
void addPossibleNextLeader(std::pair<Value *, unsigned int> LeaderPair) {
|
||||
if (LeaderPair.second < NextLeader.second)
|
||||
NextLeader = LeaderPair;
|
||||
|
@ -300,6 +351,7 @@ public:
|
|||
iterator_range<MemoryMemberSet::const_iterator> memory() const {
|
||||
return make_range(memory_begin(), memory_end());
|
||||
}
|
||||
|
||||
void memory_insert(const MemoryMemberType *M) { MemoryMembers.insert(M); }
|
||||
void memory_erase(const MemoryMemberType *M) { MemoryMembers.erase(M); }
|
||||
|
||||
|
@ -339,35 +391,48 @@ public:
|
|||
|
||||
private:
|
||||
unsigned ID;
|
||||
|
||||
// Representative leader.
|
||||
Value *RepLeader = nullptr;
|
||||
|
||||
// The most dominating leader after our current leader, because the member set
|
||||
// is not sorted and is expensive to keep sorted all the time.
|
||||
std::pair<Value *, unsigned int> NextLeader = {nullptr, ~0U};
|
||||
|
||||
// If this is represented by a store, the value of the store.
|
||||
Value *RepStoredValue = nullptr;
|
||||
|
||||
// If this class contains MemoryDefs or MemoryPhis, this is the leading memory
|
||||
// access.
|
||||
const MemoryAccess *RepMemoryAccess = nullptr;
|
||||
|
||||
// Defining Expression.
|
||||
const Expression *DefiningExpr = nullptr;
|
||||
|
||||
// Actual members of this class.
|
||||
MemberSet Members;
|
||||
|
||||
// This is the set of MemoryPhis that exist in the class. MemoryDefs and
|
||||
// MemoryUses have real instructions representing them, so we only need to
|
||||
// track MemoryPhis here.
|
||||
MemoryMemberSet MemoryMembers;
|
||||
|
||||
// Number of stores in this congruence class.
|
||||
// This is used so we can detect store equivalence changes properly.
|
||||
int StoreCount = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct ExactEqualsExpression {
|
||||
const Expression &E;
|
||||
|
||||
explicit ExactEqualsExpression(const Expression &E) : E(E) {}
|
||||
|
||||
hash_code getComputedHash() const { return E.getComputedHash(); }
|
||||
|
||||
bool operator==(const Expression &Other) const {
|
||||
return E.exactlyEquals(Other);
|
||||
}
|
||||
|
@ -379,17 +444,21 @@ template <> struct DenseMapInfo<const Expression *> {
|
|||
Val <<= PointerLikeTypeTraits<const Expression *>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<const Expression *>(Val);
|
||||
}
|
||||
|
||||
static const Expression *getTombstoneKey() {
|
||||
auto Val = static_cast<uintptr_t>(~1U);
|
||||
Val <<= PointerLikeTypeTraits<const Expression *>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<const Expression *>(Val);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const Expression *E) {
|
||||
return E->getComputedHash();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const ExactEqualsExpression &E) {
|
||||
return E.getComputedHash();
|
||||
}
|
||||
|
||||
static bool isEqual(const ExactEqualsExpression &LHS, const Expression *RHS) {
|
||||
if (RHS == getTombstoneKey() || RHS == getEmptyKey())
|
||||
return false;
|
||||
|
@ -411,9 +480,11 @@ template <> struct DenseMapInfo<const Expression *> {
|
|||
return *LHS == *RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
namespace {
|
||||
|
||||
class NewGVN {
|
||||
Function &F;
|
||||
DominatorTree *DT;
|
||||
|
@ -450,6 +521,7 @@ class NewGVN {
|
|||
// Value Mappings.
|
||||
DenseMap<Value *, CongruenceClass *> ValueToClass;
|
||||
DenseMap<Value *, const Expression *> ValueToExpression;
|
||||
|
||||
// Value PHI handling, used to make equivalence between phi(op, op) and
|
||||
// op(phi, phi).
|
||||
// These mappings just store various data that would normally be part of the
|
||||
|
@ -457,11 +529,14 @@ class NewGVN {
|
|||
SmallPtrSet<const Instruction *, 8> PHINodeUses;
|
||||
|
||||
DenseMap<const Value *, bool> OpSafeForPHIOfOps;
|
||||
|
||||
// Map a temporary instruction we created to a parent block.
|
||||
DenseMap<const Value *, BasicBlock *> TempToBlock;
|
||||
|
||||
// Map between the already in-program instructions and the temporary phis we
|
||||
// created that they are known equivalent to.
|
||||
DenseMap<const Value *, PHINode *> RealToTemp;
|
||||
|
||||
// In order to know when we should re-process instructions that have
|
||||
// phi-of-ops, we track the set of expressions that they needed as
|
||||
// leaders. When we discover new leaders for those expressions, we process the
|
||||
|
@ -473,13 +548,14 @@ class NewGVN {
|
|||
mutable DenseMap<const Value *, SmallPtrSet<Value *, 2>> AdditionalUsers;
|
||||
DenseMap<const Expression *, SmallPtrSet<Instruction *, 2>>
|
||||
ExpressionToPhiOfOps;
|
||||
|
||||
// Map from temporary operation to MemoryAccess.
|
||||
DenseMap<const Instruction *, MemoryUseOrDef *> TempToMemory;
|
||||
|
||||
// Set of all temporary instructions we created.
|
||||
// Note: This will include instructions that were just created during value
|
||||
// numbering. The way to test if something is using them is to check
|
||||
// RealToTemp.
|
||||
|
||||
DenseSet<Instruction *> AllTempInstructions;
|
||||
|
||||
// This is the set of instructions to revisit on a reachability change. At
|
||||
|
@ -497,6 +573,7 @@ class NewGVN {
|
|||
// propagate the information to the places we used the comparison.
|
||||
mutable DenseMap<const Value *, SmallPtrSet<Instruction *, 2>>
|
||||
PredicateToUsers;
|
||||
|
||||
// the same reasoning as PredicateToUsers. When we skip MemoryAccesses for
|
||||
// stores, we no longer can rely solely on the def-use chains of MemorySSA.
|
||||
mutable DenseMap<const MemoryAccess *, SmallPtrSet<MemoryAccess *, 2>>
|
||||
|
@ -524,6 +601,7 @@ class NewGVN {
|
|||
|
||||
enum InstCycleState { ICS_Unknown, ICS_CycleFree, ICS_Cycle };
|
||||
mutable DenseMap<const Instruction *, InstCycleState> InstCycleState;
|
||||
|
||||
// Expression to class mapping.
|
||||
using ExpressionClassMap = DenseMap<const Expression *, CongruenceClass *>;
|
||||
ExpressionClassMap ExpressionToClass;
|
||||
|
@ -580,6 +658,7 @@ public:
|
|||
: F(F), DT(DT), TLI(TLI), AA(AA), MSSA(MSSA), DL(DL),
|
||||
PredInfo(make_unique<PredicateInfo>(F, *DT, *AC)), SQ(DL, TLI, DT, AC) {
|
||||
}
|
||||
|
||||
bool runGVN();
|
||||
|
||||
private:
|
||||
|
@ -587,9 +666,11 @@ private:
|
|||
const Expression *createExpression(Instruction *) const;
|
||||
const Expression *createBinaryExpression(unsigned, Type *, Value *, Value *,
|
||||
Instruction *) const;
|
||||
|
||||
// Our canonical form for phi arguments is a pair of incoming value, incoming
|
||||
// basic block.
|
||||
typedef std::pair<Value *, BasicBlock *> ValPair;
|
||||
using ValPair = std::pair<Value *, BasicBlock *>;
|
||||
|
||||
PHIExpression *createPHIExpression(ArrayRef<ValPair>, const Instruction *,
|
||||
BasicBlock *, bool &HasBackEdge,
|
||||
bool &OriginalOpsConstant) const;
|
||||
|
@ -620,6 +701,7 @@ private:
|
|||
CC->setMemoryLeader(MA);
|
||||
return CC;
|
||||
}
|
||||
|
||||
CongruenceClass *ensureLeaderOfMemoryClass(MemoryAccess *MA) {
|
||||
auto *CC = getMemoryClass(MA);
|
||||
if (CC->getMemoryLeader() != MA)
|
||||
|
@ -633,6 +715,7 @@ private:
|
|||
ValueToClass[Member] = CClass;
|
||||
return CClass;
|
||||
}
|
||||
|
||||
void initializeCongruenceClasses(Function &F);
|
||||
const Expression *makePossiblePHIOfOps(Instruction *,
|
||||
SmallPtrSetImpl<Value *> &);
|
||||
|
@ -713,7 +796,7 @@ private:
|
|||
const BasicBlock *) const;
|
||||
|
||||
// New instruction creation.
|
||||
void handleNewInstruction(Instruction *){};
|
||||
void handleNewInstruction(Instruction *) {}
|
||||
|
||||
// Various instruction touch utilities
|
||||
template <typename Map, typename KeyType, typename Func>
|
||||
|
@ -749,6 +832,7 @@ private:
|
|||
MemoryAccess *getDefiningAccess(const MemoryAccess *) const;
|
||||
MemoryPhi *getMemoryAccess(const BasicBlock *) const;
|
||||
template <class T, class Range> T *getMinDFSOfRange(const Range &) const;
|
||||
|
||||
unsigned InstrToDFSNum(const Value *V) const {
|
||||
assert(isa<Instruction>(V) && "This should not be used for MemoryAccesses");
|
||||
return InstrDFS.lookup(V);
|
||||
|
@ -757,7 +841,9 @@ private:
|
|||
unsigned InstrToDFSNum(const MemoryAccess *MA) const {
|
||||
return MemoryToDFSNum(MA);
|
||||
}
|
||||
|
||||
Value *InstrFromDFSNum(unsigned DFSNum) { return DFSToInstr[DFSNum]; }
|
||||
|
||||
// Given a MemoryAccess, return the relevant instruction DFS number. Note:
|
||||
// This deliberately takes a value so it can be used with Use's, which will
|
||||
// auto-convert to Value's but not to MemoryAccess's.
|
||||
|
@ -768,12 +854,15 @@ private:
|
|||
? InstrToDFSNum(cast<MemoryUseOrDef>(MA)->getMemoryInst())
|
||||
: InstrDFS.lookup(MA);
|
||||
}
|
||||
|
||||
bool isCycleFree(const Instruction *) const;
|
||||
bool isBackedge(BasicBlock *From, BasicBlock *To) const;
|
||||
|
||||
// Debug counter info. When verifying, we have to reset the value numbering
|
||||
// debug counter to the same state it started in to get the same results.
|
||||
std::pair<int, int> StartingVNCounter;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
template <typename T>
|
||||
|
@ -1338,7 +1427,6 @@ NewGVN::performSymbolicLoadCoercion(Type *LoadType, Value *LoadPtr,
|
|||
getConstantStoreValueForLoad(C, Offset, LoadType, DL));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (auto *DepLI = dyn_cast<LoadInst>(DepInst)) {
|
||||
// Can't forward from non-atomic to atomic without violating memory model.
|
||||
if (LI->isAtomic() > DepLI->isAtomic())
|
||||
|
@ -1354,7 +1442,6 @@ NewGVN::performSymbolicLoadCoercion(Type *LoadType, Value *LoadPtr,
|
|||
return createConstantExpression(PossibleConstant);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (auto *DepMI = dyn_cast<MemIntrinsic>(DepInst)) {
|
||||
int Offset = analyzeLoadFromClobberingMemInst(LoadType, LoadPtr, DepMI, DL);
|
||||
if (Offset >= 0) {
|
||||
|
@ -1554,7 +1641,6 @@ const Expression *NewGVN::performSymbolicCallEvaluation(Instruction *I) const {
|
|||
|
||||
// Retrieve the memory class for a given MemoryAccess.
|
||||
CongruenceClass *NewGVN::getMemoryClass(const MemoryAccess *MA) const {
|
||||
|
||||
auto *Result = MemoryAccessToClass.lookup(MA);
|
||||
assert(Result && "Should have found memory class");
|
||||
return Result;
|
||||
|
@ -1759,6 +1845,7 @@ NewGVN::performSymbolicAggrValueEvaluation(Instruction *I) const {
|
|||
|
||||
return createAggregateValueExpression(I);
|
||||
}
|
||||
|
||||
const Expression *NewGVN::performSymbolicCmpEvaluation(Instruction *I) const {
|
||||
assert(isa<CmpInst>(I) && "Expected a cmp instruction.");
|
||||
|
||||
|
@ -1856,7 +1943,6 @@ const Expression *NewGVN::performSymbolicCmpEvaluation(Instruction *I) const {
|
|||
return createConstantExpression(
|
||||
ConstantInt::getFalse(CI->getType()));
|
||||
}
|
||||
|
||||
} else {
|
||||
// Just handle the ne and eq cases, where if we have the same
|
||||
// operands, we may know something.
|
||||
|
@ -1917,13 +2003,13 @@ NewGVN::performSymbolicEvaluation(Value *V,
|
|||
case Instruction::Load:
|
||||
E = performSymbolicLoadEvaluation(I);
|
||||
break;
|
||||
case Instruction::BitCast: {
|
||||
case Instruction::BitCast:
|
||||
E = createExpression(I);
|
||||
} break;
|
||||
break;
|
||||
case Instruction::ICmp:
|
||||
case Instruction::FCmp: {
|
||||
case Instruction::FCmp:
|
||||
E = performSymbolicCmpEvaluation(I);
|
||||
} break;
|
||||
break;
|
||||
case Instruction::Add:
|
||||
case Instruction::FAdd:
|
||||
case Instruction::Sub:
|
||||
|
@ -2914,6 +3000,7 @@ void NewGVN::updateProcessedCount(const Value *V) {
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Evaluate MemoryPhi nodes symbolically, just like PHI nodes
|
||||
void NewGVN::valueNumberMemoryPhi(MemoryPhi *MP) {
|
||||
// If all the arguments are the same, the MemoryPhi has the same value as the
|
||||
|
@ -2991,7 +3078,6 @@ void NewGVN::valueNumberInstruction(Instruction *I) {
|
|||
removePhiOfOps(I, Op);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Mark the instruction as unused so we don't value number it again.
|
||||
InstrDFS[I] = 0;
|
||||
|
@ -3400,11 +3486,13 @@ struct NewGVN::ValueDFS {
|
|||
int DFSIn = 0;
|
||||
int DFSOut = 0;
|
||||
int LocalNum = 0;
|
||||
|
||||
// Only one of Def and U will be set.
|
||||
// The bool in the Def tells us whether the Def is the stored value of a
|
||||
// store.
|
||||
PointerIntPair<Value *, 1, bool> Def;
|
||||
Use *U = nullptr;
|
||||
|
||||
bool operator<(const ValueDFS &Other) const {
|
||||
// It's not enough that any given field be less than - we have sets
|
||||
// of fields that need to be evaluated together to give a proper ordering.
|
||||
|
@ -3639,7 +3727,6 @@ void NewGVN::markInstructionForDeletion(Instruction *I) {
|
|||
}
|
||||
|
||||
void NewGVN::replaceInstruction(Instruction *I, Value *V) {
|
||||
|
||||
DEBUG(dbgs() << "Replacing " << *I << " with " << *V << "\n");
|
||||
patchAndReplaceAllUsesWith(I, V);
|
||||
// We save the actual erasing to avoid invalidating memory
|
||||
|
@ -3660,7 +3747,9 @@ public:
|
|||
ValueStack.emplace_back(V);
|
||||
DFSStack.emplace_back(DFSIn, DFSOut);
|
||||
}
|
||||
|
||||
bool empty() const { return DFSStack.empty(); }
|
||||
|
||||
bool isInScope(int DFSIn, int DFSOut) const {
|
||||
if (empty())
|
||||
return false;
|
||||
|
@ -3684,7 +3773,8 @@ private:
|
|||
SmallVector<Value *, 8> ValueStack;
|
||||
SmallVector<std::pair<int, int>, 8> DFSStack;
|
||||
};
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
// Given an expression, get the congruence class for it.
|
||||
CongruenceClass *NewGVN::getClassForExpression(const Expression *E) const {
|
||||
|
@ -4087,12 +4177,16 @@ bool NewGVN::shouldSwapOperands(const Value *A, const Value *B) const {
|
|||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class NewGVNLegacyPass : public FunctionPass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid.
|
||||
// Pass identification, replacement for typeid.
|
||||
static char ID;
|
||||
|
||||
NewGVNLegacyPass() : FunctionPass(ID) {
|
||||
initializeNewGVNLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
private:
|
||||
|
@ -4106,7 +4200,8 @@ private:
|
|||
AU.addPreserved<GlobalsAAWrapperPass>();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
bool NewGVNLegacyPass::runOnFunction(Function &F) {
|
||||
if (skipFunction(F))
|
||||
|
@ -4120,6 +4215,8 @@ bool NewGVNLegacyPass::runOnFunction(Function &F) {
|
|||
.runGVN();
|
||||
}
|
||||
|
||||
char NewGVNLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS_BEGIN(NewGVNLegacyPass, "newgvn", "Global Value Numbering",
|
||||
false, false)
|
||||
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
||||
|
@ -4131,8 +4228,6 @@ INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass)
|
|||
INITIALIZE_PASS_END(NewGVNLegacyPass, "newgvn", "Global Value Numbering", false,
|
||||
false)
|
||||
|
||||
char NewGVNLegacyPass::ID = 0;
|
||||
|
||||
// createGVNPass - The public interface to this file.
|
||||
FunctionPass *llvm::createNewGVNPass() { return new NewGVNLegacyPass(); }
|
||||
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/IPO/SCCP.h"
|
||||
#include "llvm/Transforms/Scalar/SCCP.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
|
@ -28,21 +31,35 @@
|
|||
#include "llvm/Analysis/GlobalsModRef.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/ValueLatticeUtils.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/User.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Scalar/SCCP.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "sccp"
|
||||
|
@ -55,6 +72,7 @@ STATISTIC(IPNumArgsElimed ,"Number of arguments constant propagated by IPSCCP");
|
|||
STATISTIC(IPNumGlobalConst, "Number of globals found to be constant by IPSCCP");
|
||||
|
||||
namespace {
|
||||
|
||||
/// LatticeVal class - This class represents the different lattice values that
|
||||
/// an LLVM value may occupy. It is a simple class with value semantics.
|
||||
///
|
||||
|
@ -89,9 +107,11 @@ public:
|
|||
LatticeVal() : Val(nullptr, unknown) {}
|
||||
|
||||
bool isUnknown() const { return getLatticeValue() == unknown; }
|
||||
|
||||
bool isConstant() const {
|
||||
return getLatticeValue() == constant || getLatticeValue() == forcedconstant;
|
||||
}
|
||||
|
||||
bool isOverdefined() const { return getLatticeValue() == overdefined; }
|
||||
|
||||
Constant *getConstant() const {
|
||||
|
@ -155,10 +175,6 @@ public:
|
|||
Val.setPointer(V);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
@ -168,37 +184,36 @@ namespace {
|
|||
class SCCPSolver : public InstVisitor<SCCPSolver> {
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
SmallPtrSet<BasicBlock*, 8> BBExecutable; // The BBs that are executable.
|
||||
DenseMap<Value*, LatticeVal> ValueState; // The state each value is in.
|
||||
SmallPtrSet<BasicBlock *, 8> BBExecutable; // The BBs that are executable.
|
||||
DenseMap<Value *, LatticeVal> ValueState; // The state each value is in.
|
||||
|
||||
/// StructValueState - This maintains ValueState for values that have
|
||||
/// StructType, for example for formal arguments, calls, insertelement, etc.
|
||||
///
|
||||
DenseMap<std::pair<Value*, unsigned>, LatticeVal> StructValueState;
|
||||
DenseMap<std::pair<Value *, unsigned>, LatticeVal> StructValueState;
|
||||
|
||||
/// GlobalValue - If we are tracking any values for the contents of a global
|
||||
/// variable, we keep a mapping from the constant accessor to the element of
|
||||
/// the global, to the currently known value. If the value becomes
|
||||
/// overdefined, it's entry is simply removed from this map.
|
||||
DenseMap<GlobalVariable*, LatticeVal> TrackedGlobals;
|
||||
DenseMap<GlobalVariable *, LatticeVal> TrackedGlobals;
|
||||
|
||||
/// TrackedRetVals - If we are tracking arguments into and the return
|
||||
/// value out of a function, it will have an entry in this map, indicating
|
||||
/// what the known return value for the function is.
|
||||
DenseMap<Function*, LatticeVal> TrackedRetVals;
|
||||
DenseMap<Function *, LatticeVal> TrackedRetVals;
|
||||
|
||||
/// TrackedMultipleRetVals - Same as TrackedRetVals, but used for functions
|
||||
/// that return multiple values.
|
||||
DenseMap<std::pair<Function*, unsigned>, LatticeVal> TrackedMultipleRetVals;
|
||||
DenseMap<std::pair<Function *, unsigned>, LatticeVal> TrackedMultipleRetVals;
|
||||
|
||||
/// MRVFunctionsTracked - Each function in TrackedMultipleRetVals is
|
||||
/// represented here for efficient lookup.
|
||||
SmallPtrSet<Function*, 16> MRVFunctionsTracked;
|
||||
SmallPtrSet<Function *, 16> MRVFunctionsTracked;
|
||||
|
||||
/// TrackingIncomingArguments - This is the set of functions for whose
|
||||
/// arguments we make optimistic assumptions about and try to prove as
|
||||
/// constants.
|
||||
SmallPtrSet<Function*, 16> TrackingIncomingArguments;
|
||||
SmallPtrSet<Function *, 16> TrackingIncomingArguments;
|
||||
|
||||
/// The reason for two worklists is that overdefined is the lowest state
|
||||
/// on the lattice, and moving things to overdefined as fast as possible
|
||||
|
@ -207,16 +222,17 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
|
|||
/// By having a separate worklist, we accomplish this because everything
|
||||
/// possibly overdefined will become overdefined at the soonest possible
|
||||
/// point.
|
||||
SmallVector<Value*, 64> OverdefinedInstWorkList;
|
||||
SmallVector<Value*, 64> InstWorkList;
|
||||
SmallVector<Value *, 64> OverdefinedInstWorkList;
|
||||
SmallVector<Value *, 64> InstWorkList;
|
||||
|
||||
|
||||
SmallVector<BasicBlock*, 64> BBWorkList; // The BasicBlock work list
|
||||
// The BasicBlock work list
|
||||
SmallVector<BasicBlock *, 64> BBWorkList;
|
||||
|
||||
/// KnownFeasibleEdges - Entries in this set are edges which have already had
|
||||
/// PHI nodes retriggered.
|
||||
typedef std::pair<BasicBlock*, BasicBlock*> Edge;
|
||||
using Edge = std::pair<BasicBlock *, BasicBlock *>;
|
||||
DenseSet<Edge> KnownFeasibleEdges;
|
||||
|
||||
public:
|
||||
SCCPSolver(const DataLayout &DL, const TargetLibraryInfo *tli)
|
||||
: DL(DL), TLI(tli) {}
|
||||
|
@ -271,7 +287,6 @@ public:
|
|||
}
|
||||
|
||||
/// Solve - Solve for constants and executable blocks.
|
||||
///
|
||||
void Solve();
|
||||
|
||||
/// ResolvedUndefsIn - While solving the dataflow for a function, we assume
|
||||
|
@ -304,7 +319,6 @@ public:
|
|||
}
|
||||
|
||||
/// getTrackedRetVals - Get the inferred return value map.
|
||||
///
|
||||
const DenseMap<Function*, LatticeVal> &getTrackedRetVals() {
|
||||
return TrackedRetVals;
|
||||
}
|
||||
|
@ -356,7 +370,6 @@ private:
|
|||
// markConstant - Make a value be marked as "constant". If the value
|
||||
// is not already a constant, add it to the instruction work list so that
|
||||
// the users of the instruction are updated later.
|
||||
//
|
||||
void markConstant(LatticeVal &IV, Value *V, Constant *C) {
|
||||
if (!IV.markConstant(C)) return;
|
||||
DEBUG(dbgs() << "markConstant: " << *C << ": " << *V << '\n');
|
||||
|
@ -376,7 +389,6 @@ private:
|
|||
pushToWorkList(IV, V);
|
||||
}
|
||||
|
||||
|
||||
// markOverdefined - Make a value be marked as "overdefined". If the
|
||||
// value is not already overdefined, add it to the overdefined instruction
|
||||
// work list so that the users of the instruction are updated later.
|
||||
|
@ -409,7 +421,6 @@ private:
|
|||
mergeInValue(ValueState[V], V, MergeWithV);
|
||||
}
|
||||
|
||||
|
||||
/// getValueState - Return the LatticeVal object that corresponds to the
|
||||
/// value. This function handles the case when the value hasn't been seen yet
|
||||
/// by properly seeding constants etc.
|
||||
|
@ -464,7 +475,6 @@ private:
|
|||
return LV;
|
||||
}
|
||||
|
||||
|
||||
/// markEdgeExecutable - Mark a basic block as executable, adding it to the BB
|
||||
/// work list if it is not already executable.
|
||||
void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest) {
|
||||
|
@ -487,18 +497,15 @@ private:
|
|||
|
||||
// getFeasibleSuccessors - Return a vector of booleans to indicate which
|
||||
// successors are reachable from a given terminator instruction.
|
||||
//
|
||||
void getFeasibleSuccessors(TerminatorInst &TI, SmallVectorImpl<bool> &Succs);
|
||||
|
||||
// isEdgeFeasible - Return true if the control flow edge from the 'From' basic
|
||||
// block to the 'To' basic block is currently feasible.
|
||||
//
|
||||
bool isEdgeFeasible(BasicBlock *From, BasicBlock *To);
|
||||
|
||||
// OperandChangedState - This method is invoked on all of the users of an
|
||||
// instruction that was just changed state somehow. Based on this
|
||||
// information, we need to update the specified user of this instruction.
|
||||
//
|
||||
void OperandChangedState(Instruction *I) {
|
||||
if (BBExecutable.count(I->getParent())) // Inst is executable?
|
||||
visit(*I);
|
||||
|
@ -513,6 +520,7 @@ private:
|
|||
void visitPHINode(PHINode &I);
|
||||
|
||||
// Terminators
|
||||
|
||||
void visitReturnInst(ReturnInst &I);
|
||||
void visitTerminatorInst(TerminatorInst &TI);
|
||||
|
||||
|
@ -522,26 +530,32 @@ private:
|
|||
void visitCmpInst(CmpInst &I);
|
||||
void visitExtractValueInst(ExtractValueInst &EVI);
|
||||
void visitInsertValueInst(InsertValueInst &IVI);
|
||||
|
||||
void visitCatchSwitchInst(CatchSwitchInst &CPI) {
|
||||
markOverdefined(&CPI);
|
||||
visitTerminatorInst(CPI);
|
||||
}
|
||||
|
||||
// Instructions that cannot be folded away.
|
||||
|
||||
void visitStoreInst (StoreInst &I);
|
||||
void visitLoadInst (LoadInst &I);
|
||||
void visitGetElementPtrInst(GetElementPtrInst &I);
|
||||
|
||||
void visitCallInst (CallInst &I) {
|
||||
visitCallSite(&I);
|
||||
}
|
||||
|
||||
void visitInvokeInst (InvokeInst &II) {
|
||||
visitCallSite(&II);
|
||||
visitTerminatorInst(II);
|
||||
}
|
||||
|
||||
void visitCallSite (CallSite CS);
|
||||
void visitResumeInst (TerminatorInst &I) { /*returns void*/ }
|
||||
void visitUnreachableInst(TerminatorInst &I) { /*returns void*/ }
|
||||
void visitFenceInst (FenceInst &I) { /*returns void*/ }
|
||||
|
||||
void visitInstruction(Instruction &I) {
|
||||
// All the instructions we don't do any special handling for just
|
||||
// go to overdefined.
|
||||
|
@ -552,10 +566,8 @@ private:
|
|||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
// getFeasibleSuccessors - Return a vector of booleans to indicate which
|
||||
// successors are reachable from a given terminator instruction.
|
||||
//
|
||||
void SCCPSolver::getFeasibleSuccessors(TerminatorInst &TI,
|
||||
SmallVectorImpl<bool> &Succs) {
|
||||
Succs.resize(TI.getNumSuccessors());
|
||||
|
@ -638,10 +650,8 @@ void SCCPSolver::getFeasibleSuccessors(TerminatorInst &TI,
|
|||
llvm_unreachable("SCCP: Don't know how to handle this terminator!");
|
||||
}
|
||||
|
||||
|
||||
// isEdgeFeasible - Return true if the control flow edge from the 'From' basic
|
||||
// block to the 'To' basic block is currently feasible.
|
||||
//
|
||||
bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) {
|
||||
assert(BBExecutable.count(To) && "Dest should always be alive!");
|
||||
|
||||
|
@ -717,7 +727,6 @@ bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) {
|
|||
// destination executable
|
||||
// 7. If a conditional branch has a value that is overdefined, make all
|
||||
// successors executable.
|
||||
//
|
||||
void SCCPSolver::visitPHINode(PHINode &PN) {
|
||||
// If this PN returns a struct, just mark the result overdefined.
|
||||
// TODO: We could do a lot better than this if code actually uses this.
|
||||
|
@ -737,7 +746,6 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
|
|||
// constant, and they agree with each other, the PHI becomes the identical
|
||||
// constant. If they are constant and don't agree, the PHI is overdefined.
|
||||
// If there are no executable operands, the PHI remains unknown.
|
||||
//
|
||||
Constant *OperandVal = nullptr;
|
||||
for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) {
|
||||
LatticeVal IV = getValueState(PN.getIncomingValue(i));
|
||||
|
@ -768,7 +776,6 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
|
|||
// arguments that agree with each other(and OperandVal is the constant) or
|
||||
// OperandVal is null because there are no defined incoming arguments. If
|
||||
// this is the case, the PHI remains unknown.
|
||||
//
|
||||
if (OperandVal)
|
||||
markConstant(&PN, OperandVal); // Acquire operand value
|
||||
}
|
||||
|
@ -796,7 +803,6 @@ void SCCPSolver::visitReturnInst(ReturnInst &I) {
|
|||
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
|
||||
mergeInValue(TrackedMultipleRetVals[std::make_pair(F, i)], F,
|
||||
getStructValueState(ResultOp, i));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -827,7 +833,6 @@ void SCCPSolver::visitCastInst(CastInst &I) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) {
|
||||
// If this returns a struct, mark all elements over defined, we don't track
|
||||
// structs in structs.
|
||||
|
@ -976,7 +981,6 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
markOverdefined(&I);
|
||||
}
|
||||
|
||||
|
@ -1005,7 +1009,6 @@ void SCCPSolver::visitCmpInst(CmpInst &I) {
|
|||
|
||||
// Handle getelementptr instructions. If all operands are constants then we
|
||||
// can turn this into a getelementptr ConstantExpr.
|
||||
//
|
||||
void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) {
|
||||
if (ValueState[&I].isOverdefined()) return;
|
||||
|
||||
|
@ -1051,7 +1054,6 @@ void SCCPSolver::visitStoreInst(StoreInst &SI) {
|
|||
TrackedGlobals.erase(I); // No need to keep tracking this!
|
||||
}
|
||||
|
||||
|
||||
// Handle load instructions. If the operand is a constant pointer to a constant
|
||||
// global, we can replace the load with the loaded constant value!
|
||||
void SCCPSolver::visitLoadInst(LoadInst &I) {
|
||||
|
@ -1115,7 +1117,6 @@ CallOverdefined:
|
|||
// a declaration, maybe we can constant fold it.
|
||||
if (F && F->isDeclaration() && !I->getType()->isStructTy() &&
|
||||
canConstantFoldCallTo(CS, F)) {
|
||||
|
||||
SmallVector<Constant*, 8> Operands;
|
||||
for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
|
||||
AI != E; ++AI) {
|
||||
|
@ -1367,7 +1368,6 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
|||
// undef & X -> 0. X could be zero.
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
|
||||
case Instruction::Or:
|
||||
// Both operands undef -> undef
|
||||
if (Op0LV.isUnknown() && Op1LV.isUnknown())
|
||||
|
@ -1375,7 +1375,6 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
|||
// undef | X -> -1. X could be -1.
|
||||
markForcedConstant(&I, Constant::getAllOnesValue(ITy));
|
||||
return true;
|
||||
|
||||
case Instruction::Xor:
|
||||
// undef ^ undef -> 0; strictly speaking, this is not strictly
|
||||
// necessary, but we try to be nice to people who expect this
|
||||
|
@ -1386,7 +1385,6 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
|||
}
|
||||
// undef ^ X -> undef
|
||||
break;
|
||||
|
||||
case Instruction::SDiv:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SRem:
|
||||
|
@ -1404,7 +1402,6 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
|||
// undef % X -> 0. X could be 1.
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
|
||||
case Instruction::AShr:
|
||||
// X >>a undef -> undef.
|
||||
if (Op1LV.isUnknown()) break;
|
||||
|
@ -1471,7 +1468,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
|||
markOverdefined(&I);
|
||||
return true;
|
||||
case Instruction::Call:
|
||||
case Instruction::Invoke: {
|
||||
case Instruction::Invoke:
|
||||
// There are two reasons a call can have an undef result
|
||||
// 1. It could be tracked.
|
||||
// 2. It could be constant-foldable.
|
||||
|
@ -1485,7 +1482,6 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
|||
// we do not know what return values are valid.
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
// If we don't know what should happen here, conservatively mark it
|
||||
// overdefined.
|
||||
|
@ -1568,7 +1564,8 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
|
|||
Constant *Const = nullptr;
|
||||
if (V->getType()->isStructTy()) {
|
||||
std::vector<LatticeVal> IVs = Solver.getStructLatticeValueFor(V);
|
||||
if (any_of(IVs, [](const LatticeVal &LV) { return LV.isOverdefined(); }))
|
||||
if (llvm::any_of(IVs,
|
||||
[](const LatticeVal &LV) { return LV.isOverdefined(); }))
|
||||
return false;
|
||||
std::vector<Constant *> ConstVals;
|
||||
auto *ST = dyn_cast<StructType>(V->getType());
|
||||
|
@ -1595,7 +1592,6 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
|
|||
|
||||
// runSCCP() - Run the Sparse Conditional Constant Propagation algorithm,
|
||||
// and return true if the function was modified.
|
||||
//
|
||||
static bool runSCCP(Function &F, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI) {
|
||||
DEBUG(dbgs() << "SCCP on function '" << F.getName() << "'\n");
|
||||
|
@ -1635,7 +1631,6 @@ static bool runSCCP(Function &F, const DataLayout &DL,
|
|||
|
||||
// Iterate over all of the instructions in a function, replacing them with
|
||||
// constants if we have found them to be of constant values.
|
||||
//
|
||||
for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) {
|
||||
Instruction *Inst = &*BI++;
|
||||
if (Inst->getType()->isVoidTy() || isa<TerminatorInst>(Inst))
|
||||
|
@ -1666,6 +1661,7 @@ PreservedAnalyses SCCPPass::run(Function &F, FunctionAnalysisManager &AM) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
/// SCCP Class - This class uses the SCCPSolver to implement a per-function
|
||||
|
@ -1673,18 +1669,20 @@ namespace {
|
|||
///
|
||||
class SCCPLegacyPass : public FunctionPass {
|
||||
public:
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||||
AU.addPreserved<GlobalsAAWrapperPass>();
|
||||
}
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
// Pass identification, replacement for typeid
|
||||
static char ID;
|
||||
|
||||
SCCPLegacyPass() : FunctionPass(ID) {
|
||||
initializeSCCPLegacyPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||||
AU.addPreserved<GlobalsAAWrapperPass>();
|
||||
}
|
||||
|
||||
// runOnFunction - Run the Sparse Conditional Constant Propagation
|
||||
// algorithm, and return true if the function was modified.
|
||||
//
|
||||
bool runOnFunction(Function &F) override {
|
||||
if (skipFunction(F))
|
||||
return false;
|
||||
|
@ -1694,9 +1692,11 @@ public:
|
|||
return runSCCP(F, DL, TLI);
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char SCCPLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS_BEGIN(SCCPLegacyPass, "sccp",
|
||||
"Sparse Conditional Constant Propagation", false, false)
|
||||
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
||||
|
@ -1725,7 +1725,6 @@ static bool runIPSCCP(Module &M, const DataLayout &DL,
|
|||
|
||||
// Loop over all functions, marking arguments to those with their addresses
|
||||
// taken or that are external as overdefined.
|
||||
//
|
||||
for (Function &F : M) {
|
||||
if (F.isDeclaration())
|
||||
continue;
|
||||
|
@ -1774,7 +1773,6 @@ static bool runIPSCCP(Module &M, const DataLayout &DL,
|
|||
|
||||
// Iterate over all of the instructions in the module, replacing them with
|
||||
// constants if we have found them to be of constant values.
|
||||
//
|
||||
SmallVector<BasicBlock*, 512> BlocksToErase;
|
||||
|
||||
for (Function &F : M) {
|
||||
|
@ -1908,6 +1906,7 @@ PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
/// IPSCCP Class - This class implements interprocedural Sparse Conditional
|
||||
|
@ -1934,9 +1933,11 @@ public:
|
|||
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char IPSCCPLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS_BEGIN(IPSCCPLegacyPass, "ipsccp",
|
||||
"Interprocedural Sparse Conditional Constant Propagation",
|
||||
false, false)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===--- Scalarizer.cpp - Scalarize vector operations ---------------------===//
|
||||
//===- Scalarizer.cpp - Scalarize vector operations -----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -14,36 +14,59 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Analysis/VectorUtils.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/InstVisitor.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/Options.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "scalarizer"
|
||||
|
||||
namespace {
|
||||
|
||||
// Used to store the scattered form of a vector.
|
||||
typedef SmallVector<Value *, 8> ValueVector;
|
||||
using ValueVector = SmallVector<Value *, 8>;
|
||||
|
||||
// Used to map a vector Value to its scattered form. We use std::map
|
||||
// because we want iterators to persist across insertion and because the
|
||||
// values are relatively large.
|
||||
typedef std::map<Value *, ValueVector> ScatterMap;
|
||||
using ScatterMap = std::map<Value *, ValueVector>;
|
||||
|
||||
// Lists Instructions that have been replaced with scalar implementations,
|
||||
// along with a pointer to their scattered forms.
|
||||
typedef SmallVector<std::pair<Instruction *, ValueVector *>, 16> GatherList;
|
||||
using GatherList = SmallVector<std::pair<Instruction *, ValueVector *>, 16>;
|
||||
|
||||
// Provides a very limited vector-like interface for lazily accessing one
|
||||
// component of a scattered vector or vector pointer.
|
||||
class Scatterer {
|
||||
public:
|
||||
Scatterer() {}
|
||||
Scatterer() = default;
|
||||
|
||||
// Scatter V into Size components. If new instructions are needed,
|
||||
// insert them before BBI in BB. If Cache is nonnull, use it to cache
|
||||
|
@ -71,10 +94,12 @@ private:
|
|||
// called Name that compares X and Y in the same way as FCI.
|
||||
struct FCmpSplitter {
|
||||
FCmpSplitter(FCmpInst &fci) : FCI(fci) {}
|
||||
|
||||
Value *operator()(IRBuilder<> &Builder, Value *Op0, Value *Op1,
|
||||
const Twine &Name) const {
|
||||
return Builder.CreateFCmp(FCI.getPredicate(), Op0, Op1, Name);
|
||||
}
|
||||
|
||||
FCmpInst &FCI;
|
||||
};
|
||||
|
||||
|
@ -82,10 +107,12 @@ struct FCmpSplitter {
|
|||
// called Name that compares X and Y in the same way as ICI.
|
||||
struct ICmpSplitter {
|
||||
ICmpSplitter(ICmpInst &ici) : ICI(ici) {}
|
||||
|
||||
Value *operator()(IRBuilder<> &Builder, Value *Op0, Value *Op1,
|
||||
const Twine &Name) const {
|
||||
return Builder.CreateICmp(ICI.getPredicate(), Op0, Op1, Name);
|
||||
}
|
||||
|
||||
ICmpInst &ICI;
|
||||
};
|
||||
|
||||
|
@ -93,16 +120,18 @@ struct ICmpSplitter {
|
|||
// a binary operator like BO called Name with operands X and Y.
|
||||
struct BinarySplitter {
|
||||
BinarySplitter(BinaryOperator &bo) : BO(bo) {}
|
||||
|
||||
Value *operator()(IRBuilder<> &Builder, Value *Op0, Value *Op1,
|
||||
const Twine &Name) const {
|
||||
return Builder.CreateBinOp(BO.getOpcode(), Op0, Op1, Name);
|
||||
}
|
||||
|
||||
BinaryOperator &BO;
|
||||
};
|
||||
|
||||
// Information about a load or store that we're scalarizing.
|
||||
struct VectorLayout {
|
||||
VectorLayout() : VecTy(nullptr), ElemTy(nullptr), VecAlign(0), ElemSize(0) {}
|
||||
VectorLayout() = default;
|
||||
|
||||
// Return the alignment of element I.
|
||||
uint64_t getElemAlign(unsigned I) {
|
||||
|
@ -110,16 +139,16 @@ struct VectorLayout {
|
|||
}
|
||||
|
||||
// The type of the vector.
|
||||
VectorType *VecTy;
|
||||
VectorType *VecTy = nullptr;
|
||||
|
||||
// The type of each element.
|
||||
Type *ElemTy;
|
||||
Type *ElemTy = nullptr;
|
||||
|
||||
// The alignment of the vector.
|
||||
uint64_t VecAlign;
|
||||
uint64_t VecAlign = 0;
|
||||
|
||||
// The size of each element.
|
||||
uint64_t ElemSize;
|
||||
uint64_t ElemSize = 0;
|
||||
};
|
||||
|
||||
class Scalarizer : public FunctionPass,
|
||||
|
@ -127,8 +156,7 @@ class Scalarizer : public FunctionPass,
|
|||
public:
|
||||
static char ID;
|
||||
|
||||
Scalarizer() :
|
||||
FunctionPass(ID) {
|
||||
Scalarizer() : FunctionPass(ID) {
|
||||
initializeScalarizerPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
|
@ -137,19 +165,19 @@ public:
|
|||
|
||||
// InstVisitor methods. They return true if the instruction was scalarized,
|
||||
// false if nothing changed.
|
||||
bool visitInstruction(Instruction &) { return false; }
|
||||
bool visitInstruction(Instruction &I) { return false; }
|
||||
bool visitSelectInst(SelectInst &SI);
|
||||
bool visitICmpInst(ICmpInst &);
|
||||
bool visitFCmpInst(FCmpInst &);
|
||||
bool visitBinaryOperator(BinaryOperator &);
|
||||
bool visitGetElementPtrInst(GetElementPtrInst &);
|
||||
bool visitCastInst(CastInst &);
|
||||
bool visitBitCastInst(BitCastInst &);
|
||||
bool visitShuffleVectorInst(ShuffleVectorInst &);
|
||||
bool visitPHINode(PHINode &);
|
||||
bool visitLoadInst(LoadInst &);
|
||||
bool visitStoreInst(StoreInst &);
|
||||
bool visitCallInst(CallInst &I);
|
||||
bool visitICmpInst(ICmpInst &ICI);
|
||||
bool visitFCmpInst(FCmpInst &FCI);
|
||||
bool visitBinaryOperator(BinaryOperator &BO);
|
||||
bool visitGetElementPtrInst(GetElementPtrInst &GEPI);
|
||||
bool visitCastInst(CastInst &CI);
|
||||
bool visitBitCastInst(BitCastInst &BCI);
|
||||
bool visitShuffleVectorInst(ShuffleVectorInst &SVI);
|
||||
bool visitPHINode(PHINode &PHI);
|
||||
bool visitLoadInst(LoadInst &LI);
|
||||
bool visitStoreInst(StoreInst &SI);
|
||||
bool visitCallInst(CallInst &ICI);
|
||||
|
||||
static void registerOptions() {
|
||||
// This is disabled by default because having separate loads and stores
|
||||
|
@ -162,11 +190,12 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
Scatterer scatter(Instruction *, Value *);
|
||||
void gather(Instruction *, const ValueVector &);
|
||||
Scatterer scatter(Instruction *Point, Value *V);
|
||||
void gather(Instruction *Op, const ValueVector &CV);
|
||||
bool canTransferMetadata(unsigned Kind);
|
||||
void transferMetadata(Instruction *, const ValueVector &);
|
||||
bool getVectorLayout(Type *, unsigned, VectorLayout &, const DataLayout &);
|
||||
void transferMetadata(Instruction *Op, const ValueVector &CV);
|
||||
bool getVectorLayout(Type *Ty, unsigned Alignment, VectorLayout &Layout,
|
||||
const DataLayout &DL);
|
||||
bool finish();
|
||||
|
||||
template<typename T> bool splitBinary(Instruction &, const T &);
|
||||
|
@ -179,9 +208,10 @@ private:
|
|||
bool ScalarizeLoadStore;
|
||||
};
|
||||
|
||||
char Scalarizer::ID = 0;
|
||||
} // end anonymous namespace
|
||||
|
||||
char Scalarizer::ID = 0;
|
||||
|
||||
INITIALIZE_PASS_WITH_OPTIONS(Scalarizer, "scalarizer",
|
||||
"Scalarize vector operations", false, false)
|
||||
|
||||
|
@ -222,7 +252,7 @@ Value *Scatterer::operator[](unsigned I) {
|
|||
// Search through a chain of InsertElementInsts looking for element I.
|
||||
// Record other elements in the cache. The new V is still suitable
|
||||
// for all uncached indices.
|
||||
for (;;) {
|
||||
while (true) {
|
||||
InsertElementInst *Insert = dyn_cast<InsertElementInst>(V);
|
||||
if (!Insert)
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===-- StructurizeCFG.cpp ------------------------------------------------===//
|
||||
//===- StructurizeCFG.cpp -------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -7,49 +7,72 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/SCCIterator.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/DivergenceAnalysis.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/RegionInfo.h"
|
||||
#include "llvm/Analysis/RegionIterator.h"
|
||||
#include "llvm/Analysis/RegionPass.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Use.h"
|
||||
#include "llvm/IR/User.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::PatternMatch;
|
||||
|
||||
#define DEBUG_TYPE "structurizecfg"
|
||||
|
||||
// The name for newly created blocks.
|
||||
static const char *const FlowBlockName = "Flow";
|
||||
|
||||
namespace {
|
||||
|
||||
// Definition of the complex types used in this pass.
|
||||
|
||||
typedef std::pair<BasicBlock *, Value *> BBValuePair;
|
||||
using BBValuePair = std::pair<BasicBlock *, Value *>;
|
||||
|
||||
typedef SmallVector<RegionNode*, 8> RNVector;
|
||||
typedef SmallVector<BasicBlock*, 8> BBVector;
|
||||
typedef SmallVector<BranchInst*, 8> BranchVector;
|
||||
typedef SmallVector<BBValuePair, 2> BBValueVector;
|
||||
using RNVector = SmallVector<RegionNode *, 8>;
|
||||
using BBVector = SmallVector<BasicBlock *, 8>;
|
||||
using BranchVector = SmallVector<BranchInst *, 8>;
|
||||
using BBValueVector = SmallVector<BBValuePair, 2>;
|
||||
|
||||
typedef SmallPtrSet<BasicBlock *, 8> BBSet;
|
||||
using BBSet = SmallPtrSet<BasicBlock *, 8>;
|
||||
|
||||
typedef MapVector<PHINode *, BBValueVector> PhiMap;
|
||||
typedef MapVector<BasicBlock *, BBVector> BB2BBVecMap;
|
||||
using PhiMap = MapVector<PHINode *, BBValueVector>;
|
||||
using BB2BBVecMap = MapVector<BasicBlock *, BBVector>;
|
||||
|
||||
typedef DenseMap<BasicBlock *, PhiMap> BBPhiMap;
|
||||
typedef DenseMap<BasicBlock *, Value *> BBPredicates;
|
||||
typedef DenseMap<BasicBlock *, BBPredicates> PredMap;
|
||||
typedef DenseMap<BasicBlock *, BasicBlock*> BB2BBMap;
|
||||
|
||||
// The name for newly created blocks.
|
||||
static const char *const FlowBlockName = "Flow";
|
||||
using BBPhiMap = DenseMap<BasicBlock *, PhiMap>;
|
||||
using BBPredicates = DenseMap<BasicBlock *, Value *>;
|
||||
using PredMap = DenseMap<BasicBlock *, BBPredicates>;
|
||||
using BB2BBMap = DenseMap<BasicBlock *, BasicBlock *>;
|
||||
|
||||
/// Finds the nearest common dominator of a set of BasicBlocks.
|
||||
///
|
||||
|
@ -736,7 +759,6 @@ void StructurizeCFG::wireFlow(bool ExitUseAllowed,
|
|||
changeExit(PrevNode, Node->getEntry(), true);
|
||||
}
|
||||
PrevNode = Node;
|
||||
|
||||
} else {
|
||||
// Insert extra prefix node (or reuse last one)
|
||||
BasicBlock *Flow = needPrefix(false);
|
||||
|
|
Loading…
Reference in New Issue