2019-11-14 03:16:46 +03:00
|
|
|
//===---------- DxilValueCache.cpp - Dxil Constant Value Cache ------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Utility to compute and cache constant values for instructions.
|
|
|
|
//
|
|
|
|
|
2020-04-10 10:40:14 +03:00
|
|
|
#include "dxc/DXIL/DxilConstants.h"
|
2023-09-19 15:49:22 +03:00
|
|
|
#include "dxc/Support/Global.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
#include "llvm/Analysis/ConstantFolding.h"
|
2020-10-15 08:41:03 +03:00
|
|
|
#include "llvm/Analysis/DxilSimplify.h"
|
2023-09-19 15:49:22 +03:00
|
|
|
#include "llvm/Analysis/InstructionSimplify.h"
|
|
|
|
#include "llvm/IR/CFG.h"
|
2019-11-14 03:16:46 +03:00
|
|
|
#include "llvm/IR/Constants.h"
|
2023-09-19 15:49:22 +03:00
|
|
|
#include "llvm/IR/Dominators.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
2019-11-14 03:16:46 +03:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2023-09-19 15:49:22 +03:00
|
|
|
#include "llvm/IR/Module.h"
|
2022-04-21 21:53:45 +03:00
|
|
|
#include "llvm/IR/ModuleSlotTracker.h"
|
2023-09-19 15:49:22 +03:00
|
|
|
#include "llvm/IR/Operator.h"
|
|
|
|
#include "llvm/Pass.h"
|
2019-11-14 03:16:46 +03:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
|
|
|
|
2020-02-14 02:46:00 +03:00
|
|
|
#include "llvm/Analysis/DxilValueCache.h"
|
2020-01-31 04:27:22 +03:00
|
|
|
|
2022-04-21 21:53:45 +03:00
|
|
|
#include <unordered_map>
|
2023-09-19 15:49:22 +03:00
|
|
|
#include <unordered_set>
|
2019-11-14 03:16:46 +03:00
|
|
|
|
|
|
|
#define DEBUG_TYPE "dxil-value-cache"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
static bool IsConstantTrue(const Value *V) {
|
2019-11-14 03:16:46 +03:00
|
|
|
if (const ConstantInt *C = dyn_cast<ConstantInt>(V))
|
|
|
|
return C->getLimitedValue() != 0;
|
|
|
|
return false;
|
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
static bool IsConstantFalse(const Value *V) {
|
2019-11-14 03:16:46 +03:00
|
|
|
if (const ConstantInt *C = dyn_cast<ConstantInt>(V))
|
|
|
|
return C->getLimitedValue() == 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
static bool IsEntryBlock(const BasicBlock *BB) {
|
2019-11-14 03:16:46 +03:00
|
|
|
return BB == &BB->getParent()->getEntryBlock();
|
|
|
|
}
|
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
void DxilValueCache::MarkUnreachable(BasicBlock *BB) {
|
2023-05-19 21:36:51 +03:00
|
|
|
Map.Set(BB, ConstantInt::get(Type::getInt1Ty(BB->getContext()), 0));
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
bool DxilValueCache::MayBranchTo(BasicBlock *A, BasicBlock *B) {
|
2022-03-02 20:42:26 +03:00
|
|
|
TerminatorInst *Term = A->getTerminator();
|
|
|
|
if (BranchInst *Br = dyn_cast<BranchInst>(Term)) {
|
|
|
|
if (Br->isUnconditional() && Br->getSuccessor(0) == B)
|
|
|
|
return true;
|
2020-01-31 04:27:22 +03:00
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
if (ConstantInt *C =
|
|
|
|
dyn_cast<ConstantInt>(TryGetCachedValue(Br->getCondition()))) {
|
2022-03-02 20:42:26 +03:00
|
|
|
unsigned SuccIndex = C->getLimitedValue() != 0 ? 0 : 1;
|
|
|
|
return Br->getSuccessor(SuccIndex) == B;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (SwitchInst *Sw = dyn_cast<SwitchInst>(Term)) {
|
|
|
|
if (ConstantInt *C =
|
|
|
|
dyn_cast<ConstantInt>(TryGetCachedValue(Sw->getCondition()))) {
|
|
|
|
for (auto Case : Sw->cases()) {
|
|
|
|
if (Case.getCaseValue() == C)
|
|
|
|
return Case.getCaseSuccessor() == B;
|
|
|
|
}
|
|
|
|
return Sw->getDefaultDest() == B;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (isa<ReturnInst>(Term) || isa<UnreachableInst>(Term)) {
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Should not see: IndirectBrInst, InvokeInst, ResumeInst
|
|
|
|
DXASSERT(false, "otherwise, unexpected terminator instruction.");
|
2020-01-31 04:27:22 +03:00
|
|
|
}
|
2022-03-02 20:42:26 +03:00
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DxilValueCache::IsUnreachable_(BasicBlock *BB) {
|
2023-05-19 21:36:51 +03:00
|
|
|
if (Value *V = Map.Get(BB))
|
2019-11-14 03:16:46 +03:00
|
|
|
if (IsConstantFalse(V))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
Value *DxilValueCache::ProcessAndSimplify_PHI(Instruction *I,
|
|
|
|
DominatorTree *DT) {
|
2019-11-14 03:16:46 +03:00
|
|
|
PHINode *PN = cast<PHINode>(I);
|
|
|
|
BasicBlock *SoleIncoming = nullptr;
|
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
bool Unreachable = true;
|
2019-11-14 03:16:46 +03:00
|
|
|
Value *Simplified = nullptr;
|
2021-10-05 13:28:21 +03:00
|
|
|
Value *SimplifiedNotDominating = nullptr;
|
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
|
|
|
|
BasicBlock *PredBB = PN->getIncomingBlock(i);
|
2020-01-31 04:27:22 +03:00
|
|
|
if (IsUnreachable_(PredBB))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Unreachable = false;
|
|
|
|
|
|
|
|
if (MayBranchTo(PredBB, PN->getParent())) {
|
2019-11-14 03:16:46 +03:00
|
|
|
if (SoleIncoming) {
|
|
|
|
SoleIncoming = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SoleIncoming = PredBB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
if (Unreachable) {
|
|
|
|
return UndefValue::get(I->getType());
|
|
|
|
}
|
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
if (SoleIncoming) {
|
2020-01-31 04:27:22 +03:00
|
|
|
Value *V = TryGetCachedValue(PN->getIncomingValueForBlock(SoleIncoming));
|
2019-11-14 03:16:46 +03:00
|
|
|
if (isa<Constant>(V))
|
|
|
|
Simplified = V;
|
|
|
|
else if (Instruction *I = dyn_cast<Instruction>(V)) {
|
|
|
|
// If this is an instruction, we have to make sure it
|
|
|
|
// dominates this PHI.
|
|
|
|
// There are several conditions that qualify:
|
|
|
|
// 1. There's only one predecessor
|
|
|
|
// 2. If the instruction is in the entry block, then it must dominate
|
|
|
|
// 3. If we are provided with a Dominator tree, and it decides that
|
|
|
|
// it dominates.
|
2023-09-19 15:49:22 +03:00
|
|
|
if (PN->getNumIncomingValues() == 1 || IsEntryBlock(I->getParent()) ||
|
|
|
|
(DT && DT->dominates(I, PN))) {
|
2019-11-14 03:16:46 +03:00
|
|
|
Simplified = I;
|
2023-09-19 15:49:22 +03:00
|
|
|
} else {
|
2021-10-05 13:28:21 +03:00
|
|
|
SimplifiedNotDominating = I;
|
|
|
|
}
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
// If we have a value but it's not dominating our PHI, see if it has a cached
|
|
|
|
// value that were computed previously.
|
2021-10-05 13:28:21 +03:00
|
|
|
if (!Simplified) {
|
|
|
|
if (SimplifiedNotDominating)
|
2023-05-19 21:36:51 +03:00
|
|
|
if (Value *CachedV = Map.Get(SimplifiedNotDominating))
|
2021-10-05 13:28:21 +03:00
|
|
|
Simplified = CachedV;
|
|
|
|
}
|
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
// If we coulnd't deduce it, run the LLVM stock simplification to see
|
|
|
|
// if we could do anything.
|
|
|
|
if (!Simplified)
|
|
|
|
Simplified = llvm::SimplifyInstruction(I, I->getModule()->getDataLayout());
|
|
|
|
|
|
|
|
// One last step, to check if we have anything cached for whatever we
|
|
|
|
// simplified to.
|
|
|
|
if (Simplified)
|
2020-01-31 04:27:22 +03:00
|
|
|
Simplified = TryGetCachedValue(Simplified);
|
2019-11-14 03:16:46 +03:00
|
|
|
|
|
|
|
return Simplified;
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
Value *DxilValueCache::ProcessAndSimplify_Switch(Instruction *I,
|
|
|
|
DominatorTree *DT) {
|
2022-04-21 21:53:45 +03:00
|
|
|
SwitchInst *Sw = cast<SwitchInst>(I);
|
|
|
|
BasicBlock *BB = Sw->getParent();
|
|
|
|
|
|
|
|
Value *Cond = TryGetCachedValue(Sw->getCondition());
|
|
|
|
if (IsUnreachable_(BB)) {
|
|
|
|
for (unsigned i = 0; i < Sw->getNumSuccessors(); i++) {
|
|
|
|
BasicBlock *Succ = Sw->getSuccessor(i);
|
|
|
|
if (Succ->getUniquePredecessor())
|
|
|
|
MarkUnreachable(Succ);
|
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (isa<Constant>(Cond)) {
|
2022-04-21 21:53:45 +03:00
|
|
|
BasicBlock *ConstDest = nullptr;
|
|
|
|
for (auto Case : Sw->cases()) {
|
|
|
|
BasicBlock *Succ = Case.getCaseSuccessor();
|
|
|
|
if (Case.getCaseValue() == Cond) {
|
|
|
|
ConstDest = Succ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ConstDest) {
|
|
|
|
ConstDest = Sw->getDefaultDest();
|
|
|
|
}
|
|
|
|
DXASSERT_NOMSG(ConstDest);
|
|
|
|
if (ConstDest) {
|
|
|
|
for (unsigned i = 0; i < Sw->getNumSuccessors(); i++) {
|
|
|
|
BasicBlock *Succ = Sw->getSuccessor(i);
|
|
|
|
if (Succ != ConstDest && Succ->getUniquePredecessor()) {
|
|
|
|
MarkUnreachable(Succ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
Value *DxilValueCache::ProcessAndSimplify_Br(Instruction *I,
|
|
|
|
DominatorTree *DT) {
|
2019-11-14 03:16:46 +03:00
|
|
|
|
|
|
|
// The *only* reason we're paying special attention to the
|
|
|
|
// branch inst, is to mark certain Basic Blocks as always
|
|
|
|
// reachable or unreachable.
|
|
|
|
|
|
|
|
BranchInst *Br = cast<BranchInst>(I);
|
|
|
|
BasicBlock *BB = Br->getParent();
|
|
|
|
if (Br->isConditional()) {
|
|
|
|
|
|
|
|
BasicBlock *TrueSucc = Br->getSuccessor(0);
|
|
|
|
BasicBlock *FalseSucc = Br->getSuccessor(1);
|
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
Value *Cond = TryGetCachedValue(Br->getCondition());
|
2019-11-14 03:16:46 +03:00
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
if (IsUnreachable_(BB)) {
|
2020-08-28 19:09:53 +03:00
|
|
|
if (FalseSucc->getSinglePredecessor())
|
|
|
|
MarkUnreachable(FalseSucc);
|
|
|
|
if (TrueSucc->getSinglePredecessor())
|
|
|
|
MarkUnreachable(TrueSucc);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (IsConstantTrue(Cond)) {
|
2019-11-14 03:16:46 +03:00
|
|
|
if (FalseSucc->getSinglePredecessor())
|
2020-01-31 04:27:22 +03:00
|
|
|
MarkUnreachable(FalseSucc);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (IsConstantFalse(Cond)) {
|
2019-11-14 03:16:46 +03:00
|
|
|
if (TrueSucc->getSinglePredecessor())
|
2020-01-31 04:27:22 +03:00
|
|
|
MarkUnreachable(TrueSucc);
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
} else {
|
2019-11-14 03:16:46 +03:00
|
|
|
BasicBlock *Succ = Br->getSuccessor(0);
|
2022-04-21 21:53:45 +03:00
|
|
|
if (Succ->getSinglePredecessor() && IsUnreachable_(BB))
|
2020-01-31 04:27:22 +03:00
|
|
|
MarkUnreachable(Succ);
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
Value *DxilValueCache::ProcessAndSimplify_Load(Instruction *I,
|
|
|
|
DominatorTree *DT) {
|
2020-01-31 04:27:22 +03:00
|
|
|
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;
|
|
|
|
}
|
2019-11-14 03:16:46 +03:00
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
Value *DxilValueCache::SimplifyAndCacheResult(Instruction *I,
|
|
|
|
DominatorTree *DT) {
|
2019-11-14 03:16:46 +03:00
|
|
|
|
2021-10-05 13:28:21 +03:00
|
|
|
if (ShouldSkipCallback && ShouldSkipCallback(I))
|
|
|
|
return nullptr;
|
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
const DataLayout &DL = I->getModule()->getDataLayout();
|
|
|
|
|
|
|
|
Value *Simplified = nullptr;
|
|
|
|
if (Instruction::Br == I->getOpcode()) {
|
2020-04-10 10:40:14 +03:00
|
|
|
Simplified = ProcessAndSimplify_Br(I, DT);
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
2022-04-21 21:53:45 +03:00
|
|
|
if (Instruction::Switch == I->getOpcode()) {
|
|
|
|
Simplified = ProcessAndSimplify_Switch(I, DT);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (Instruction::PHI == I->getOpcode()) {
|
2019-11-14 03:16:46 +03:00
|
|
|
Simplified = ProcessAndSimplify_PHI(I, DT);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (Instruction::Load == I->getOpcode()) {
|
2020-04-10 10:40:14 +03:00
|
|
|
Simplified = ProcessAndSimplify_Load(I, DT);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (Instruction::GetElementPtr == I->getOpcode()) {
|
2020-03-05 06:04:27 +03:00
|
|
|
SmallVector<Value *, 4> Ops;
|
|
|
|
for (unsigned i = 0; i < I->getNumOperands(); i++)
|
|
|
|
Ops.push_back(TryGetCachedValue(I->getOperand(i)));
|
|
|
|
Simplified = llvm::SimplifyGEPInst(Ops, DL, nullptr, DT);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (Instruction::Call == I->getOpcode()) {
|
2020-04-10 10:40:14 +03:00
|
|
|
Module *M = I->getModule();
|
|
|
|
CallInst *CI = cast<CallInst>(I);
|
2020-10-16 02:20:16 +03:00
|
|
|
Value *Callee = CI->getCalledValue();
|
|
|
|
Function *CalledFunction = dyn_cast<Function>(Callee);
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
if (CalledFunction &&
|
|
|
|
CalledFunction->getName() == hlsl::DXIL::kDxBreakFuncName) {
|
2020-04-10 10:40:14 +03:00
|
|
|
llvm::Type *i1Ty = llvm::Type::getInt1Ty(M->getContext());
|
|
|
|
Simplified = llvm::ConstantInt::get(i1Ty, 1);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else {
|
|
|
|
SmallVector<Value *, 16> Args;
|
2020-10-15 08:41:03 +03:00
|
|
|
for (unsigned i = 0; i < CI->getNumArgOperands(); i++) {
|
|
|
|
Args.push_back(TryGetCachedValue(CI->getArgOperand(i)));
|
|
|
|
}
|
|
|
|
|
2020-10-16 02:20:16 +03:00
|
|
|
if (CalledFunction && hlsl::CanSimplify(CalledFunction)) {
|
2023-09-19 15:49:22 +03:00
|
|
|
Simplified = hlsl::SimplifyDxilCall(CalledFunction, Args, CI,
|
|
|
|
/* MayInsert */ false);
|
|
|
|
} else {
|
2020-10-15 08:41:03 +03:00
|
|
|
Simplified = llvm::SimplifyCall(Callee, Args, DL, nullptr, DT);
|
|
|
|
}
|
|
|
|
}
|
2020-04-10 10:40:14 +03:00
|
|
|
}
|
2019-11-14 03:16:46 +03:00
|
|
|
// The rest of the checks use LLVM stock simplifications
|
|
|
|
else if (I->isBinaryOp()) {
|
2021-10-05 13:28:21 +03:00
|
|
|
if (FPMathOperator *FPOp = dyn_cast<FPMathOperator>(I)) {
|
2023-09-19 15:49:22 +03:00
|
|
|
Simplified = llvm::SimplifyFPBinOp(
|
|
|
|
I->getOpcode(), TryGetCachedValue(I->getOperand(0)),
|
|
|
|
TryGetCachedValue(I->getOperand(1)), FPOp->getFastMathFlags(), DL);
|
|
|
|
} else {
|
|
|
|
Simplified = llvm::SimplifyBinOp(I->getOpcode(),
|
|
|
|
TryGetCachedValue(I->getOperand(0)),
|
|
|
|
TryGetCachedValue(I->getOperand(1)), DL);
|
2021-10-05 13:28:21 +03:00
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (GetElementPtrInst *Gep = dyn_cast<GetElementPtrInst>(I)) {
|
2020-01-31 04:27:22 +03:00
|
|
|
SmallVector<Value *, 4> Values;
|
|
|
|
for (Value *V : Gep->operand_values()) {
|
|
|
|
Values.push_back(TryGetCachedValue(V));
|
|
|
|
}
|
|
|
|
Simplified =
|
2023-09-19 15:49:22 +03:00
|
|
|
llvm::SimplifyGEPInst(Values, DL, nullptr, DT, nullptr, nullptr);
|
|
|
|
} else if (CmpInst *Cmp = dyn_cast<CmpInst>(I)) {
|
2021-10-05 13:28:21 +03:00
|
|
|
if (FPMathOperator *FPOp = dyn_cast<FPMathOperator>(I)) {
|
2023-09-19 15:49:22 +03:00
|
|
|
Simplified = llvm::SimplifyFCmpInst(
|
|
|
|
Cmp->getPredicate(), TryGetCachedValue(I->getOperand(0)),
|
|
|
|
TryGetCachedValue(I->getOperand(1)), FPOp->getFastMathFlags(), DL);
|
|
|
|
} else {
|
|
|
|
Simplified = llvm::SimplifyCmpInst(
|
|
|
|
Cmp->getPredicate(), TryGetCachedValue(I->getOperand(0)),
|
|
|
|
TryGetCachedValue(I->getOperand(1)), DL);
|
2021-10-05 13:28:21 +03:00
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (SelectInst *Select = dyn_cast<SelectInst>(I)) {
|
|
|
|
Simplified = llvm::SimplifySelectInst(
|
2020-01-31 04:27:22 +03:00
|
|
|
TryGetCachedValue(Select->getCondition()),
|
|
|
|
TryGetCachedValue(Select->getTrueValue()),
|
2023-09-19 15:49:22 +03:00
|
|
|
TryGetCachedValue(Select->getFalseValue()), DL);
|
|
|
|
} else if (ExtractElementInst *IE = dyn_cast<ExtractElementInst>(I)) {
|
|
|
|
Simplified = llvm::SimplifyExtractElementInst(
|
2020-01-31 04:27:22 +03:00
|
|
|
TryGetCachedValue(IE->getVectorOperand()),
|
2023-09-19 15:49:22 +03:00
|
|
|
TryGetCachedValue(IE->getIndexOperand()), DL, nullptr, DT);
|
|
|
|
} else if (CastInst *Cast = dyn_cast<CastInst>(I)) {
|
|
|
|
Simplified = llvm::SimplifyCastInst(Cast->getOpcode(),
|
|
|
|
TryGetCachedValue(Cast->getOperand(0)),
|
|
|
|
Cast->getType(), DL);
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Simplified && isa<Constant>(Simplified))
|
2023-05-19 21:36:51 +03:00
|
|
|
Map.Set(I, Simplified);
|
2019-11-14 03:16:46 +03:00
|
|
|
|
|
|
|
return Simplified;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DxilValueCache::WeakValueMap::Seen(Value *V) {
|
|
|
|
auto FindIt = Map.find(V);
|
|
|
|
if (FindIt == Map.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
auto &Entry = FindIt->second;
|
|
|
|
if (Entry.IsStale())
|
|
|
|
return false;
|
|
|
|
return Entry.Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
Value *DxilValueCache::WeakValueMap::Get(Value *V) {
|
|
|
|
auto FindIt = Map.find(V);
|
|
|
|
if (FindIt == Map.end())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
auto &Entry = FindIt->second;
|
|
|
|
if (Entry.IsStale())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
Value *Result = Entry.Value;
|
|
|
|
if (Result == GetSentinel(V->getContext()))
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DxilValueCache::WeakValueMap::SetSentinel(Value *Key) {
|
|
|
|
Map[Key].Set(Key, GetSentinel(Key->getContext()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Value *DxilValueCache::WeakValueMap::GetSentinel(LLVMContext &Ctx) {
|
|
|
|
if (!Sentinel) {
|
2023-09-19 15:49:22 +03:00
|
|
|
Sentinel.reset(PHINode::Create(Type::getInt1Ty(Ctx), 0));
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
|
|
|
return Sentinel.get();
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
void DxilValueCache::WeakValueMap::ResetAll() { Map.clear(); }
|
2021-10-05 13:28:21 +03:00
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
void DxilValueCache::WeakValueMap::ResetUnknowns() {
|
|
|
|
if (!Sentinel)
|
|
|
|
return;
|
2022-04-21 21:53:45 +03:00
|
|
|
|
|
|
|
for (auto it = Map.begin(); it != Map.end();) {
|
|
|
|
auto nextIt = std::next(it);
|
2020-01-31 04:27:22 +03:00
|
|
|
if (it->second.Value == Sentinel.get())
|
2022-04-21 21:53:45 +03:00
|
|
|
Map.erase(it);
|
|
|
|
it = nextIt;
|
2020-01-31 04:27:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
LLVM_DUMP_METHOD
|
|
|
|
void DxilValueCache::WeakValueMap::dump() const {
|
2022-04-21 21:53:45 +03:00
|
|
|
std::unordered_map<const Module *, std::unique_ptr<ModuleSlotTracker>> MSTs;
|
2019-11-14 03:16:46 +03:00
|
|
|
for (auto It = Map.begin(), E = Map.end(); It != E; It++) {
|
|
|
|
const Value *Key = It->first;
|
2022-04-21 21:53:45 +03:00
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
if (It->second.IsStale())
|
|
|
|
continue;
|
2022-04-21 21:53:45 +03:00
|
|
|
|
|
|
|
if (!Key)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ModuleSlotTracker *MST = nullptr;
|
|
|
|
{
|
|
|
|
const Module *M = nullptr;
|
2023-09-19 15:49:22 +03:00
|
|
|
if (auto I = dyn_cast<Instruction>(Key))
|
|
|
|
M = I->getModule();
|
|
|
|
else if (auto BB = dyn_cast<BasicBlock>(Key))
|
|
|
|
M = BB->getModule();
|
2022-04-21 21:53:45 +03:00
|
|
|
else {
|
|
|
|
errs() << *Key;
|
|
|
|
llvm_unreachable("How can a key be neither an instruction or BB?");
|
|
|
|
}
|
|
|
|
std::unique_ptr<ModuleSlotTracker> &optMst = MSTs[M];
|
|
|
|
if (!optMst) {
|
|
|
|
optMst = llvm::make_unique<ModuleSlotTracker>(M);
|
|
|
|
}
|
|
|
|
MST = optMst.get();
|
|
|
|
}
|
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
const Value *V = It->second.Value;
|
|
|
|
bool IsSentinel = Sentinel && V == Sentinel.get();
|
2022-04-21 21:53:45 +03:00
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
if (const BasicBlock *BB = dyn_cast<BasicBlock>(Key)) {
|
2022-04-21 21:53:45 +03:00
|
|
|
dbgs() << "[BB]";
|
|
|
|
BB->printAsOperand(dbgs(), false, *MST);
|
|
|
|
dbgs() << " -> ";
|
2019-11-14 03:16:46 +03:00
|
|
|
if (IsSentinel)
|
|
|
|
dbgs() << "NO_VALUE";
|
|
|
|
else {
|
|
|
|
if (IsConstantTrue(V))
|
|
|
|
dbgs() << "Always Reachable!";
|
|
|
|
else if (IsConstantFalse(V))
|
|
|
|
dbgs() << "Never Reachable!";
|
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
} else {
|
2022-04-21 21:53:45 +03:00
|
|
|
dbgs() << *Key << " -> ";
|
2019-11-14 03:16:46 +03:00
|
|
|
if (IsSentinel)
|
|
|
|
dbgs() << "NO_VALUE";
|
|
|
|
else
|
|
|
|
dbgs() << *V;
|
|
|
|
}
|
|
|
|
dbgs() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DxilValueCache::WeakValueMap::Set(Value *Key, Value *V) {
|
|
|
|
Map[Key].Set(Key, V);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there's a cached value, return it. Otherwise, return
|
|
|
|
// the value itself.
|
2020-01-31 04:27:22 +03:00
|
|
|
Value *DxilValueCache::TryGetCachedValue(Value *V) {
|
2023-05-19 21:36:51 +03:00
|
|
|
if (Value *Simplified = Map.Get(V))
|
2019-11-14 03:16:46 +03:00
|
|
|
return Simplified;
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
DxilValueCache::DxilValueCache() : ImmutablePass(ID) {
|
2019-11-14 03:16:46 +03:00
|
|
|
initializeDxilValueCachePass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
StringRef DxilValueCache::getPassName() const { return "Dxil Value Cache"; }
|
2019-11-14 03:16:46 +03:00
|
|
|
|
|
|
|
Value *DxilValueCache::GetValue(Value *V, DominatorTree *DT) {
|
2020-05-31 00:06:19 +03:00
|
|
|
if (dyn_cast<Constant>(V))
|
|
|
|
return V;
|
2023-05-19 21:36:51 +03:00
|
|
|
if (Value *NewV = Map.Get(V))
|
2019-11-14 03:16:46 +03:00
|
|
|
return NewV;
|
2021-10-05 13:28:21 +03:00
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
return ProcessValue(V, DT);
|
|
|
|
}
|
|
|
|
|
2020-02-14 02:46:00 +03:00
|
|
|
Constant *DxilValueCache::GetConstValue(Value *V, DominatorTree *DT) {
|
|
|
|
if (Value *NewV = GetValue(V))
|
|
|
|
return dyn_cast<Constant>(NewV);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-05-31 00:06:19 +03:00
|
|
|
ConstantInt *DxilValueCache::GetConstInt(Value *V, DominatorTree *DT) {
|
|
|
|
if (Value *NewV = GetValue(V))
|
|
|
|
return dyn_cast<ConstantInt>(NewV);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
bool DxilValueCache::IsUnreachable(BasicBlock *BB, DominatorTree *DT) {
|
2019-11-14 03:16:46 +03:00
|
|
|
ProcessValue(BB, DT);
|
2020-01-31 04:27:22 +03:00
|
|
|
return IsUnreachable_(BB);
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
LLVM_DUMP_METHOD
|
2023-09-19 15:49:22 +03:00
|
|
|
void DxilValueCache::dump() const { Map.dump(); }
|
2019-11-14 03:16:46 +03:00
|
|
|
|
2020-01-31 04:27:22 +03:00
|
|
|
void DxilValueCache::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
|
2019-11-14 03:16:46 +03:00
|
|
|
Value *DxilValueCache::ProcessValue(Value *NewV, DominatorTree *DT) {
|
2021-10-05 13:28:21 +03:00
|
|
|
if (NewV->getType()->isVoidTy())
|
|
|
|
return nullptr;
|
2019-11-14 03:16:46 +03:00
|
|
|
|
|
|
|
Value *Result = nullptr;
|
|
|
|
|
|
|
|
SmallVector<Value *, 16> WorkList;
|
|
|
|
|
|
|
|
// Although we accept all values for convenience, we only process
|
|
|
|
// Instructions.
|
|
|
|
if (Instruction *I = dyn_cast<Instruction>(NewV)) {
|
|
|
|
WorkList.push_back(I);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (BasicBlock *BB = dyn_cast<BasicBlock>(NewV)) {
|
2019-11-14 03:16:46 +03:00
|
|
|
WorkList.push_back(BB->getTerminator());
|
|
|
|
WorkList.push_back(BB);
|
2023-09-19 15:49:22 +03:00
|
|
|
} else {
|
2019-11-14 03:16:46 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unconditionally process this one instruction, whether we've seen
|
|
|
|
// it or not. The simplification might be able to do something to
|
|
|
|
// simplify it even when we don't have its value cached.
|
|
|
|
|
|
|
|
// This is a basic DFS setup.
|
|
|
|
while (WorkList.size()) {
|
|
|
|
Value *V = WorkList.back();
|
|
|
|
|
|
|
|
// If we haven't seen this value, go in and push things it depends on
|
|
|
|
// into the worklist.
|
2023-05-19 21:36:51 +03:00
|
|
|
if (!Map.Seen(V)) {
|
|
|
|
Map.SetSentinel(V);
|
2019-11-14 03:16:46 +03:00
|
|
|
if (Instruction *I = dyn_cast<Instruction>(V)) {
|
|
|
|
|
|
|
|
for (Use &U : I->operands()) {
|
|
|
|
Instruction *UseI = dyn_cast<Instruction>(U.get());
|
|
|
|
if (!UseI)
|
|
|
|
continue;
|
2023-05-19 21:36:51 +03:00
|
|
|
if (!Map.Seen(UseI))
|
2019-11-14 03:16:46 +03:00
|
|
|
WorkList.push_back(UseI);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PHINode *PN = dyn_cast<PHINode>(I)) {
|
|
|
|
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
|
|
|
|
BasicBlock *BB = PN->getIncomingBlock(i);
|
|
|
|
TerminatorInst *Term = BB->getTerminator();
|
2023-05-19 21:36:51 +03:00
|
|
|
if (!Map.Seen(Term))
|
2019-11-14 03:16:46 +03:00
|
|
|
WorkList.push_back(Term);
|
2023-05-19 21:36:51 +03:00
|
|
|
if (!Map.Seen(BB))
|
2019-11-14 03:16:46 +03:00
|
|
|
WorkList.push_back(BB);
|
|
|
|
}
|
|
|
|
}
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (BasicBlock *BB = dyn_cast<BasicBlock>(V)) {
|
|
|
|
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E;
|
|
|
|
PI++) {
|
2019-11-14 03:16:46 +03:00
|
|
|
BasicBlock *PredBB = *PI;
|
|
|
|
TerminatorInst *Term = PredBB->getTerminator();
|
2023-05-19 21:36:51 +03:00
|
|
|
if (!Map.Seen(Term))
|
2019-11-14 03:16:46 +03:00
|
|
|
WorkList.push_back(Term);
|
2023-05-19 21:36:51 +03:00
|
|
|
if (!Map.Seen(PredBB))
|
2019-11-14 03:16:46 +03:00
|
|
|
WorkList.push_back(PredBB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If we've seen this values, all its dependencies must have been processed
|
|
|
|
// as well.
|
|
|
|
else {
|
|
|
|
WorkList.pop_back();
|
|
|
|
if (Instruction *I = dyn_cast<Instruction>(V)) {
|
|
|
|
Value *SimplifiedValue = SimplifyAndCacheResult(I, DT);
|
|
|
|
// Set the result if this is the input inst.
|
|
|
|
// SimplifyInst may not have cached the value
|
|
|
|
// so we return it directly.
|
|
|
|
if (I == NewV)
|
|
|
|
Result = SimplifiedValue;
|
2023-09-19 15:49:22 +03:00
|
|
|
} else if (BasicBlock *BB = dyn_cast<BasicBlock>(V)) {
|
2019-11-14 03:16:46 +03:00
|
|
|
// Deduce the basic block's reachability based on
|
|
|
|
// other analysis.
|
|
|
|
if (!IsEntryBlock(BB)) {
|
|
|
|
bool AllNeverReachable = true;
|
2023-09-19 15:49:22 +03:00
|
|
|
for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E;
|
|
|
|
PI++) {
|
2021-10-05 13:28:21 +03:00
|
|
|
if (!IsUnreachable_(*PI)) {
|
2019-11-14 03:16:46 +03:00
|
|
|
AllNeverReachable = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (AllNeverReachable)
|
2020-01-31 04:27:22 +03:00
|
|
|
MarkUnreachable(BB);
|
2019-11-14 03:16:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
char DxilValueCache::ID;
|
|
|
|
|
2023-09-19 15:49:22 +03:00
|
|
|
Pass *llvm::createDxilValueCachePass() { return new DxilValueCache(); }
|
2019-11-14 03:16:46 +03:00
|
|
|
|
|
|
|
INITIALIZE_PASS(DxilValueCache, DEBUG_TYPE, "Dxil Value Cache", false, false)
|