|
@@ -22,9 +22,11 @@
|
|
#include "llvm/IR/Dominators.h"
|
|
#include "llvm/IR/Dominators.h"
|
|
#include "llvm/Transforms/Scalar.h"
|
|
#include "llvm/Transforms/Scalar.h"
|
|
#include "llvm/Analysis/InstructionSimplify.h"
|
|
#include "llvm/Analysis/InstructionSimplify.h"
|
|
|
|
+#include "llvm/Analysis/ConstantFolding.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
|
|
#include "dxc/HLSL/DxilValueCache.h"
|
|
#include "dxc/HLSL/DxilValueCache.h"
|
|
|
|
+
|
|
#include <unordered_set>
|
|
#include <unordered_set>
|
|
|
|
|
|
#define DEBUG_TYPE "dxil-value-cache"
|
|
#define DEBUG_TYPE "dxil-value-cache"
|
|
@@ -52,7 +54,7 @@ bool IsEntryBlock(const BasicBlock *BB) {
|
|
void DxilValueCache::MarkAlwaysReachable(BasicBlock *BB) {
|
|
void DxilValueCache::MarkAlwaysReachable(BasicBlock *BB) {
|
|
ValueMap.Set(BB, ConstantInt::get(Type::getInt1Ty(BB->getContext()), 1));
|
|
ValueMap.Set(BB, ConstantInt::get(Type::getInt1Ty(BB->getContext()), 1));
|
|
}
|
|
}
|
|
-void DxilValueCache::MarkNeverReachable(BasicBlock *BB) {
|
|
|
|
|
|
+void DxilValueCache::MarkUnreachable(BasicBlock *BB) {
|
|
ValueMap.Set(BB, ConstantInt::get(Type::getInt1Ty(BB->getContext()), 0));
|
|
ValueMap.Set(BB, ConstantInt::get(Type::getInt1Ty(BB->getContext()), 0));
|
|
}
|
|
}
|
|
|
|
|
|
@@ -63,7 +65,21 @@ bool DxilValueCache::IsAlwaysReachable_(BasicBlock *BB) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-bool DxilValueCache::IsNeverReachable_(BasicBlock *BB) {
|
|
|
|
|
|
+bool DxilValueCache::MayBranchTo(BasicBlock *A, BasicBlock *B) {
|
|
|
|
+ BranchInst *Br = dyn_cast<BranchInst>(A->getTerminator());
|
|
|
|
+ if (!Br) return false;
|
|
|
|
+
|
|
|
|
+ if (Br->isUnconditional() && Br->getSuccessor(0) == B)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ if (ConstantInt *C = dyn_cast<ConstantInt>(TryGetCachedValue(Br->getCondition()))) {
|
|
|
|
+ unsigned SuccIndex = C->getLimitedValue() != 0 ? 0 : 1;
|
|
|
|
+ return Br->getSuccessor(SuccIndex) == B;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool DxilValueCache::IsUnreachable_(BasicBlock *BB) {
|
|
if (Value *V = ValueMap.Get(BB))
|
|
if (Value *V = ValueMap.Get(BB))
|
|
if (IsConstantFalse(V))
|
|
if (IsConstantFalse(V))
|
|
return true;
|
|
return true;
|
|
@@ -74,14 +90,16 @@ Value *DxilValueCache::ProcessAndSimplify_PHI(Instruction *I, DominatorTree *DT)
|
|
PHINode *PN = cast<PHINode>(I);
|
|
PHINode *PN = cast<PHINode>(I);
|
|
BasicBlock *SoleIncoming = nullptr;
|
|
BasicBlock *SoleIncoming = nullptr;
|
|
|
|
|
|
|
|
+ bool Unreachable = true;
|
|
Value *Simplified = nullptr;
|
|
Value *Simplified = nullptr;
|
|
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
|
|
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
|
|
BasicBlock *PredBB = PN->getIncomingBlock(i);
|
|
BasicBlock *PredBB = PN->getIncomingBlock(i);
|
|
- if (IsAlwaysReachable_(PredBB)) {
|
|
|
|
- SoleIncoming = PredBB;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- else if (!IsNeverReachable_(PredBB)) {
|
|
|
|
|
|
+ if (IsUnreachable_(PredBB))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ Unreachable = false;
|
|
|
|
+
|
|
|
|
+ if (MayBranchTo(PredBB, PN->getParent())) {
|
|
if (SoleIncoming) {
|
|
if (SoleIncoming) {
|
|
SoleIncoming = nullptr;
|
|
SoleIncoming = nullptr;
|
|
break;
|
|
break;
|
|
@@ -90,8 +108,12 @@ Value *DxilValueCache::ProcessAndSimplify_PHI(Instruction *I, DominatorTree *DT)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (Unreachable) {
|
|
|
|
+ return UndefValue::get(I->getType());
|
|
|
|
+ }
|
|
|
|
+
|
|
if (SoleIncoming) {
|
|
if (SoleIncoming) {
|
|
- Value *V = OptionallyGetValue(PN->getIncomingValueForBlock(SoleIncoming));
|
|
|
|
|
|
+ Value *V = TryGetCachedValue(PN->getIncomingValueForBlock(SoleIncoming));
|
|
if (isa<Constant>(V))
|
|
if (isa<Constant>(V))
|
|
Simplified = V;
|
|
Simplified = V;
|
|
else if (Instruction *I = dyn_cast<Instruction>(V)) {
|
|
else if (Instruction *I = dyn_cast<Instruction>(V)) {
|
|
@@ -119,7 +141,7 @@ Value *DxilValueCache::ProcessAndSimplify_PHI(Instruction *I, DominatorTree *DT)
|
|
// One last step, to check if we have anything cached for whatever we
|
|
// One last step, to check if we have anything cached for whatever we
|
|
// simplified to.
|
|
// simplified to.
|
|
if (Simplified)
|
|
if (Simplified)
|
|
- Simplified = OptionallyGetValue(Simplified);
|
|
|
|
|
|
+ Simplified = TryGetCachedValue(Simplified);
|
|
|
|
|
|
return Simplified;
|
|
return Simplified;
|
|
}
|
|
}
|
|
@@ -138,39 +160,47 @@ Value *DxilValueCache::ProcessAndSimpilfy_Br(Instruction *I, DominatorTree *DT)
|
|
BasicBlock *TrueSucc = Br->getSuccessor(0);
|
|
BasicBlock *TrueSucc = Br->getSuccessor(0);
|
|
BasicBlock *FalseSucc = Br->getSuccessor(1);
|
|
BasicBlock *FalseSucc = Br->getSuccessor(1);
|
|
|
|
|
|
- Value *Cond = OptionallyGetValue(Br->getCondition());
|
|
|
|
|
|
+ Value *Cond = TryGetCachedValue(Br->getCondition());
|
|
|
|
|
|
- if (IsNeverReachable_(BB)) {
|
|
|
|
- MarkNeverReachable(FalseSucc);
|
|
|
|
- MarkNeverReachable(TrueSucc);
|
|
|
|
|
|
+ if (IsUnreachable_(BB)) {
|
|
|
|
+ MarkUnreachable(FalseSucc);
|
|
|
|
+ MarkUnreachable(TrueSucc);
|
|
}
|
|
}
|
|
else if (IsConstantTrue(Cond)) {
|
|
else if (IsConstantTrue(Cond)) {
|
|
if (IsAlwaysReachable_(BB)) {
|
|
if (IsAlwaysReachable_(BB)) {
|
|
MarkAlwaysReachable(TrueSucc);
|
|
MarkAlwaysReachable(TrueSucc);
|
|
}
|
|
}
|
|
if (FalseSucc->getSinglePredecessor())
|
|
if (FalseSucc->getSinglePredecessor())
|
|
- MarkNeverReachable(FalseSucc);
|
|
|
|
|
|
+ MarkUnreachable(FalseSucc);
|
|
}
|
|
}
|
|
else if (IsConstantFalse(Cond)) {
|
|
else if (IsConstantFalse(Cond)) {
|
|
if (IsAlwaysReachable_(BB)) {
|
|
if (IsAlwaysReachable_(BB)) {
|
|
MarkAlwaysReachable(FalseSucc);
|
|
MarkAlwaysReachable(FalseSucc);
|
|
}
|
|
}
|
|
if (TrueSucc->getSinglePredecessor())
|
|
if (TrueSucc->getSinglePredecessor())
|
|
- MarkNeverReachable(TrueSucc);
|
|
|
|
|
|
+ MarkUnreachable(TrueSucc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
BasicBlock *Succ = Br->getSuccessor(0);
|
|
BasicBlock *Succ = Br->getSuccessor(0);
|
|
if (IsAlwaysReachable_(BB))
|
|
if (IsAlwaysReachable_(BB))
|
|
MarkAlwaysReachable(Succ);
|
|
MarkAlwaysReachable(Succ);
|
|
- else if (Succ->getSinglePredecessor() && IsNeverReachable_(BB))
|
|
|
|
- MarkNeverReachable(Succ);
|
|
|
|
|
|
+ else if (Succ->getSinglePredecessor() && IsUnreachable_(BB))
|
|
|
|
+ MarkUnreachable(Succ);
|
|
}
|
|
}
|
|
|
|
|
|
return nullptr;
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
|
|
+Value *DxilValueCache::ProcessAndSimpilfy_Load(Instruction *I, DominatorTree *DT) {
|
|
|
|
+ LoadInst *LI = cast<LoadInst>(I);
|
|
|
|
+ Value *V = TryGetCachedValue(LI->getPointerOperand());
|
|
|
|
+ if (Constant *ConstPtr = dyn_cast<Constant>(V)) {
|
|
|
|
+ const DataLayout &DL = I->getModule()->getDataLayout();
|
|
|
|
+ return llvm::ConstantFoldLoadFromConstPtr(ConstPtr, DL);
|
|
|
|
+ }
|
|
|
|
+ return nullptr;
|
|
|
|
+}
|
|
|
|
|
|
Value *DxilValueCache::SimplifyAndCacheResult(Instruction *I, DominatorTree *DT) {
|
|
Value *DxilValueCache::SimplifyAndCacheResult(Instruction *I, DominatorTree *DT) {
|
|
|
|
|
|
@@ -183,43 +213,54 @@ Value *DxilValueCache::SimplifyAndCacheResult(Instruction *I, DominatorTree *DT)
|
|
else if (Instruction::PHI == I->getOpcode()) {
|
|
else if (Instruction::PHI == I->getOpcode()) {
|
|
Simplified = ProcessAndSimplify_PHI(I, DT);
|
|
Simplified = ProcessAndSimplify_PHI(I, DT);
|
|
}
|
|
}
|
|
|
|
+ else if (Instruction::Load == I->getOpcode()) {
|
|
|
|
+ Simplified = ProcessAndSimpilfy_Load(I, DT);
|
|
|
|
+ }
|
|
// The rest of the checks use LLVM stock simplifications
|
|
// The rest of the checks use LLVM stock simplifications
|
|
else if (I->isBinaryOp()) {
|
|
else if (I->isBinaryOp()) {
|
|
Simplified =
|
|
Simplified =
|
|
llvm::SimplifyBinOp(
|
|
llvm::SimplifyBinOp(
|
|
I->getOpcode(),
|
|
I->getOpcode(),
|
|
- OptionallyGetValue(I->getOperand(0)),
|
|
|
|
- OptionallyGetValue(I->getOperand(1)),
|
|
|
|
|
|
+ TryGetCachedValue(I->getOperand(0)),
|
|
|
|
+ TryGetCachedValue(I->getOperand(1)),
|
|
DL);
|
|
DL);
|
|
}
|
|
}
|
|
|
|
+ else if (GetElementPtrInst *Gep = dyn_cast<GetElementPtrInst>(I)) {
|
|
|
|
+ SmallVector<Value *, 4> Values;
|
|
|
|
+ for (Value *V : Gep->operand_values()) {
|
|
|
|
+ Values.push_back(TryGetCachedValue(V));
|
|
|
|
+ }
|
|
|
|
+ Simplified =
|
|
|
|
+ llvm::SimplifyGEPInst(Values, DL, nullptr, DT, nullptr, nullptr);
|
|
|
|
+ }
|
|
else if (CmpInst *Cmp = dyn_cast<CmpInst>(I)) {
|
|
else if (CmpInst *Cmp = dyn_cast<CmpInst>(I)) {
|
|
Simplified =
|
|
Simplified =
|
|
llvm::SimplifyCmpInst(Cmp->getPredicate(),
|
|
llvm::SimplifyCmpInst(Cmp->getPredicate(),
|
|
- OptionallyGetValue(I->getOperand(0)),
|
|
|
|
- OptionallyGetValue(I->getOperand(1)),
|
|
|
|
|
|
+ TryGetCachedValue(I->getOperand(0)),
|
|
|
|
+ TryGetCachedValue(I->getOperand(1)),
|
|
DL);
|
|
DL);
|
|
}
|
|
}
|
|
else if (SelectInst *Select = dyn_cast<SelectInst>(I)) {
|
|
else if (SelectInst *Select = dyn_cast<SelectInst>(I)) {
|
|
Simplified =
|
|
Simplified =
|
|
llvm::SimplifySelectInst(
|
|
llvm::SimplifySelectInst(
|
|
- OptionallyGetValue(Select->getCondition()),
|
|
|
|
- OptionallyGetValue(Select->getTrueValue()),
|
|
|
|
- OptionallyGetValue(Select->getFalseValue()),
|
|
|
|
|
|
+ TryGetCachedValue(Select->getCondition()),
|
|
|
|
+ TryGetCachedValue(Select->getTrueValue()),
|
|
|
|
+ TryGetCachedValue(Select->getFalseValue()),
|
|
DL
|
|
DL
|
|
);
|
|
);
|
|
}
|
|
}
|
|
else if (ExtractElementInst *IE = dyn_cast<ExtractElementInst>(I)) {
|
|
else if (ExtractElementInst *IE = dyn_cast<ExtractElementInst>(I)) {
|
|
Simplified =
|
|
Simplified =
|
|
llvm::SimplifyExtractElementInst(
|
|
llvm::SimplifyExtractElementInst(
|
|
- OptionallyGetValue(IE->getVectorOperand()),
|
|
|
|
- OptionallyGetValue(IE->getIndexOperand()),
|
|
|
|
|
|
+ TryGetCachedValue(IE->getVectorOperand()),
|
|
|
|
+ TryGetCachedValue(IE->getIndexOperand()),
|
|
DL, nullptr, DT);
|
|
DL, nullptr, DT);
|
|
}
|
|
}
|
|
else if (CastInst *Cast = dyn_cast<CastInst>(I)) {
|
|
else if (CastInst *Cast = dyn_cast<CastInst>(I)) {
|
|
Simplified =
|
|
Simplified =
|
|
llvm::SimplifyCastInst(
|
|
llvm::SimplifyCastInst(
|
|
Cast->getOpcode(),
|
|
Cast->getOpcode(),
|
|
- OptionallyGetValue(Cast->getOperand(0)),
|
|
|
|
|
|
+ TryGetCachedValue(Cast->getOperand(0)),
|
|
Cast->getType(), DL);
|
|
Cast->getType(), DL);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -269,6 +310,15 @@ Value *DxilValueCache::WeakValueMap::GetSentinel(LLVMContext &Ctx) {
|
|
return Sentinel.get();
|
|
return Sentinel.get();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void DxilValueCache::WeakValueMap::ResetUnknowns() {
|
|
|
|
+ if (!Sentinel)
|
|
|
|
+ return;
|
|
|
|
+ for (auto it = Map.begin(); it != Map.end(); it++) {
|
|
|
|
+ if (it->second.Value == Sentinel.get())
|
|
|
|
+ it->second.Value = nullptr;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
LLVM_DUMP_METHOD
|
|
LLVM_DUMP_METHOD
|
|
void DxilValueCache::WeakValueMap::dump() const {
|
|
void DxilValueCache::WeakValueMap::dump() const {
|
|
for (auto It = Map.begin(), E = Map.end(); It != E; It++) {
|
|
for (auto It = Map.begin(), E = Map.end(); It != E; It++) {
|
|
@@ -305,13 +355,13 @@ void DxilValueCache::WeakValueMap::Set(Value *Key, Value *V) {
|
|
|
|
|
|
// If there's a cached value, return it. Otherwise, return
|
|
// If there's a cached value, return it. Otherwise, return
|
|
// the value itself.
|
|
// the value itself.
|
|
-Value *DxilValueCache::OptionallyGetValue(Value *V) {
|
|
|
|
|
|
+Value *DxilValueCache::TryGetCachedValue(Value *V) {
|
|
if (Value *Simplified = ValueMap.Get(V))
|
|
if (Value *Simplified = ValueMap.Get(V))
|
|
return Simplified;
|
|
return Simplified;
|
|
return V;
|
|
return V;
|
|
}
|
|
}
|
|
|
|
|
|
-DxilValueCache::DxilValueCache() : ModulePass(ID) {
|
|
|
|
|
|
+DxilValueCache::DxilValueCache() : ImmutablePass(ID) {
|
|
initializeDxilValueCachePass(*PassRegistry::getPassRegistry());
|
|
initializeDxilValueCachePass(*PassRegistry::getPassRegistry());
|
|
}
|
|
}
|
|
|
|
|
|
@@ -330,9 +380,9 @@ bool DxilValueCache::IsAlwaysReachable(BasicBlock *BB, DominatorTree *DT) {
|
|
return IsAlwaysReachable_(BB);
|
|
return IsAlwaysReachable_(BB);
|
|
}
|
|
}
|
|
|
|
|
|
-bool DxilValueCache::IsNeverReachable(BasicBlock *BB, DominatorTree *DT) {
|
|
|
|
|
|
+bool DxilValueCache::IsUnreachable(BasicBlock *BB, DominatorTree *DT) {
|
|
ProcessValue(BB, DT);
|
|
ProcessValue(BB, DT);
|
|
- return IsNeverReachable_(BB);
|
|
|
|
|
|
+ return IsUnreachable_(BB);
|
|
}
|
|
}
|
|
|
|
|
|
LLVM_DUMP_METHOD
|
|
LLVM_DUMP_METHOD
|
|
@@ -340,6 +390,10 @@ void DxilValueCache::dump() const {
|
|
ValueMap.dump();
|
|
ValueMap.dump();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void DxilValueCache::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
+ AU.setPreservesAll();
|
|
|
|
+}
|
|
|
|
+
|
|
Value *DxilValueCache::ProcessValue(Value *NewV, DominatorTree *DT) {
|
|
Value *DxilValueCache::ProcessValue(Value *NewV, DominatorTree *DT) {
|
|
|
|
|
|
Value *Result = nullptr;
|
|
Value *Result = nullptr;
|
|
@@ -425,13 +479,13 @@ Value *DxilValueCache::ProcessValue(Value *NewV, DominatorTree *DT) {
|
|
if (!IsEntryBlock(BB)) {
|
|
if (!IsEntryBlock(BB)) {
|
|
bool AllNeverReachable = true;
|
|
bool AllNeverReachable = true;
|
|
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; PI++) {
|
|
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; PI++) {
|
|
- if (!IsNeverReachable_(BB)) {
|
|
|
|
|
|
+ if (!IsUnreachable_(BB)) {
|
|
AllNeverReachable = false;
|
|
AllNeverReachable = false;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (AllNeverReachable)
|
|
if (AllNeverReachable)
|
|
- MarkNeverReachable(BB);
|
|
|
|
|
|
+ MarkUnreachable(BB);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
@@ -443,7 +497,7 @@ Value *DxilValueCache::ProcessValue(Value *NewV, DominatorTree *DT) {
|
|
|
|
|
|
char DxilValueCache::ID;
|
|
char DxilValueCache::ID;
|
|
|
|
|
|
-ModulePass *llvm::createDxilValueCachePass() {
|
|
|
|
|
|
+Pass *llvm::createDxilValueCachePass() {
|
|
return new DxilValueCache();
|
|
return new DxilValueCache();
|
|
}
|
|
}
|
|
|
|
|