Move the ir namespace to opt. (#1680)

This CL moves the files in opt/ to consistenly be under the opt::
namespace. This frees up the ir:: namespace so it can be used to make a
shared ir represenation.
This commit is contained in:
dan sinclair 2018-07-09 11:32:29 -04:00 committed by GitHub
parent 50312ca146
commit e6b953361d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
215 changed files with 5014 additions and 4963 deletions

View File

@ -37,10 +37,10 @@
namespace spvtools {
using ir::Instruction;
using ir::IRContext;
using ir::Module;
using ir::Operand;
using opt::IRContext;
using opt::Instruction;
using opt::Module;
using opt::Operand;
using opt::PassManager;
using opt::RemoveDuplicatesPass;
using opt::analysis::DecorationManager;
@ -73,7 +73,7 @@ using LinkageTable = std::vector<LinkageEntry>;
// not be empty either. Furthermore |modules| should not contain any null
// pointers.
static spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
std::vector<ir::Module*>* modules,
std::vector<opt::Module*>* modules,
uint32_t* max_id_bound);
// Generates the header for the linked module and returns it in |header|.
@ -85,9 +85,9 @@ static spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
// SPIR-V? For now, use the max of all versions found in
// the input modules.
static spv_result_t GenerateHeader(const MessageConsumer& consumer,
const std::vector<ir::Module*>& modules,
const std::vector<opt::Module*>& modules,
uint32_t max_id_bound,
ir::ModuleHeader* header);
opt::ModuleHeader* header);
// Merge all the modules from |in_modules| into a single module owned by
// |linked_context|.
@ -108,7 +108,7 @@ static spv_result_t MergeModules(const MessageConsumer& consumer,
// TODO(pierremoreau): What should be the proper behaviour with built-in
// symbols?
static spv_result_t GetImportExportPairs(
const MessageConsumer& consumer, const ir::IRContext& linked_context,
const MessageConsumer& consumer, const opt::IRContext& linked_context,
const DefUseManager& def_use_manager,
const DecorationManager& decoration_manager, bool allow_partial_linkage,
LinkageTable* linkings_to_do);
@ -120,7 +120,7 @@ static spv_result_t GetImportExportPairs(
// checked.
static spv_result_t CheckImportExportCompatibility(
const MessageConsumer& consumer, const LinkageTable& linkings_to_do,
ir::IRContext* context);
opt::IRContext* context);
// Remove linkage specific instructions, such as prototypes of imported
// functions, declarations of imported variables, import (and export if
@ -137,12 +137,12 @@ static spv_result_t CheckImportExportCompatibility(
static spv_result_t RemoveLinkageSpecificInstructions(
const MessageConsumer& consumer, const LinkerOptions& options,
const LinkageTable& linkings_to_do, DecorationManager* decoration_manager,
ir::IRContext* linked_context);
opt::IRContext* linked_context);
// Verify that the unique ids of each instruction in |linked_context| (i.e. the
// merged module) are truly unique. Does not check the validity of other ids
static spv_result_t VerifyIds(const MessageConsumer& consumer,
ir::IRContext* linked_context);
opt::IRContext* linked_context);
spv_result_t Link(const Context& context,
const std::vector<std::vector<uint32_t>>& binaries,
@ -202,7 +202,7 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries,
if (res != SPV_SUCCESS) return res;
// Phase 2: Generate the header
ir::ModuleHeader header;
opt::ModuleHeader header;
res = GenerateHeader(consumer, modules, max_id_bound, &header);
if (res != SPV_SUCCESS) return res;
IRContext linked_context(c_context->target_env, consumer);
@ -262,7 +262,7 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries,
}
static spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
std::vector<ir::Module*>* modules,
std::vector<opt::Module*>* modules,
uint32_t* max_id_bound) {
spv_position_t position = {};
@ -290,7 +290,7 @@ static spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
<< " " << id_bound << " is the current ID bound.";
// Invalidate the DefUseManager
module->context()->InvalidateAnalyses(ir::IRContext::kAnalysisDefUse);
module->context()->InvalidateAnalyses(opt::IRContext::kAnalysisDefUse);
}
++id_bound;
if (id_bound > 0x3FFFFF)
@ -304,9 +304,9 @@ static spv_result_t ShiftIdsInModules(const MessageConsumer& consumer,
}
static spv_result_t GenerateHeader(const MessageConsumer& consumer,
const std::vector<ir::Module*>& modules,
const std::vector<opt::Module*>& modules,
uint32_t max_id_bound,
ir::ModuleHeader* header) {
opt::ModuleHeader* header) {
spv_position_t position = {};
if (modules.empty())
@ -477,7 +477,7 @@ static spv_result_t MergeModules(const MessageConsumer& consumer,
// Process functions and their basic blocks
for (const auto& module : input_modules) {
for (const auto& func : *module) {
std::unique_ptr<ir::Function> cloned_func(func.Clone(linked_context));
std::unique_ptr<opt::Function> cloned_func(func.Clone(linked_context));
cloned_func->SetParent(linked_module);
linked_module->AddFunction(std::move(cloned_func));
}
@ -487,7 +487,7 @@ static spv_result_t MergeModules(const MessageConsumer& consumer,
}
static spv_result_t GetImportExportPairs(
const MessageConsumer& consumer, const ir::IRContext& linked_context,
const MessageConsumer& consumer, const opt::IRContext& linked_context,
const DefUseManager& def_use_manager,
const DecorationManager& decoration_manager, bool allow_partial_linkage,
LinkageTable* linkings_to_do) {
@ -584,7 +584,7 @@ static spv_result_t GetImportExportPairs(
static spv_result_t CheckImportExportCompatibility(
const MessageConsumer& consumer, const LinkageTable& linkings_to_do,
ir::IRContext* context) {
opt::IRContext* context) {
spv_position_t position = {};
// Ensure th import and export types are the same.
@ -628,7 +628,7 @@ static spv_result_t CheckImportExportCompatibility(
static spv_result_t RemoveLinkageSpecificInstructions(
const MessageConsumer& consumer, const LinkerOptions& options,
const LinkageTable& linkings_to_do, DecorationManager* decoration_manager,
ir::IRContext* linked_context) {
opt::IRContext* linked_context) {
spv_position_t position = {};
if (decoration_manager == nullptr)
@ -746,11 +746,11 @@ static spv_result_t RemoveLinkageSpecificInstructions(
}
spv_result_t VerifyIds(const MessageConsumer& consumer,
ir::IRContext* linked_context) {
opt::IRContext* linked_context) {
std::unordered_set<uint32_t> ids;
bool ok = true;
linked_context->module()->ForEachInst(
[&ids, &ok](const ir::Instruction* inst) {
[&ids, &ok](const opt::Instruction* inst) {
ok &= ids.insert(inst->unique_id()).second;
});

View File

@ -50,8 +50,8 @@ const uint32_t kCopyMemorySourceAddrInIdx = 1;
// SpvOpDecorateStringGOOGLE
// SpvOpDecorationGroup
struct DecorationLess {
bool operator()(const ir::Instruction* lhs,
const ir::Instruction* rhs) const {
bool operator()(const opt::Instruction* lhs,
const opt::Instruction* rhs) const {
assert(lhs && rhs);
SpvOp lhsOp = lhs->opcode();
SpvOp rhsOp = rhs->opcode();
@ -82,11 +82,11 @@ struct DecorationLess {
bool AggressiveDCEPass::IsVarOfStorage(uint32_t varId, uint32_t storageClass) {
if (varId == 0) return false;
const ir::Instruction* varInst = get_def_use_mgr()->GetDef(varId);
const opt::Instruction* varInst = get_def_use_mgr()->GetDef(varId);
const SpvOp op = varInst->opcode();
if (op != SpvOpVariable) return false;
const uint32_t varTypeId = varInst->type_id();
const ir::Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId);
const opt::Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId);
if (varTypeInst->opcode() != SpvOpTypePointer) return false;
return varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) ==
storageClass;
@ -105,7 +105,7 @@ bool AggressiveDCEPass::IsLocalVar(uint32_t varId) {
}
void AggressiveDCEPass::AddStores(uint32_t ptrId) {
get_def_use_mgr()->ForEachUser(ptrId, [this, ptrId](ir::Instruction* user) {
get_def_use_mgr()->ForEachUser(ptrId, [this, ptrId](opt::Instruction* user) {
switch (user->opcode()) {
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
@ -140,7 +140,7 @@ bool AggressiveDCEPass::AllExtensionsSupported() const {
return true;
}
bool AggressiveDCEPass::IsDead(ir::Instruction* inst) {
bool AggressiveDCEPass::IsDead(opt::Instruction* inst) {
if (IsLive(inst)) return false;
if (inst->IsBranch() && !IsStructuredHeader(context()->get_instr_block(inst),
nullptr, nullptr, nullptr))
@ -148,16 +148,16 @@ bool AggressiveDCEPass::IsDead(ir::Instruction* inst) {
return true;
}
bool AggressiveDCEPass::IsTargetDead(ir::Instruction* inst) {
bool AggressiveDCEPass::IsTargetDead(opt::Instruction* inst) {
const uint32_t tId = inst->GetSingleWordInOperand(0);
ir::Instruction* tInst = get_def_use_mgr()->GetDef(tId);
if (ir::IsAnnotationInst(tInst->opcode())) {
opt::Instruction* tInst = get_def_use_mgr()->GetDef(tId);
if (opt::IsAnnotationInst(tInst->opcode())) {
// This must be a decoration group. We go through annotations in a specific
// order. So if this is not used by any group or group member decorates, it
// is dead.
assert(tInst->opcode() == SpvOpDecorationGroup);
bool dead = true;
get_def_use_mgr()->ForEachUser(tInst, [&dead](ir::Instruction* user) {
get_def_use_mgr()->ForEachUser(tInst, [&dead](opt::Instruction* user) {
if (user->opcode() == SpvOpGroupDecorate ||
user->opcode() == SpvOpGroupMemberDecorate)
dead = false;
@ -178,14 +178,14 @@ void AggressiveDCEPass::ProcessLoad(uint32_t varId) {
live_local_vars_.insert(varId);
}
bool AggressiveDCEPass::IsStructuredHeader(ir::BasicBlock* bp,
ir::Instruction** mergeInst,
ir::Instruction** branchInst,
bool AggressiveDCEPass::IsStructuredHeader(opt::BasicBlock* bp,
opt::Instruction** mergeInst,
opt::Instruction** branchInst,
uint32_t* mergeBlockId) {
if (!bp) return false;
ir::Instruction* mi = bp->GetMergeInst();
opt::Instruction* mi = bp->GetMergeInst();
if (mi == nullptr) return false;
ir::Instruction* bri = &*bp->tail();
opt::Instruction* bri = &*bp->tail();
if (branchInst != nullptr) *branchInst = bri;
if (mergeInst != nullptr) *mergeInst = mi;
if (mergeBlockId != nullptr) *mergeBlockId = mi->GetSingleWordInOperand(0);
@ -193,11 +193,11 @@ bool AggressiveDCEPass::IsStructuredHeader(ir::BasicBlock* bp,
}
void AggressiveDCEPass::ComputeBlock2HeaderMaps(
std::list<ir::BasicBlock*>& structuredOrder) {
std::list<opt::BasicBlock*>& structuredOrder) {
block2headerBranch_.clear();
branch2merge_.clear();
structured_order_index_.clear();
std::stack<ir::Instruction*> currentHeaderBranch;
std::stack<opt::Instruction*> currentHeaderBranch;
currentHeaderBranch.push(nullptr);
uint32_t currentMergeBlockId = 0;
uint32_t index = 0;
@ -208,12 +208,12 @@ void AggressiveDCEPass::ComputeBlock2HeaderMaps(
// we are leaving the current construct so we must update state
if ((*bi)->id() == currentMergeBlockId) {
currentHeaderBranch.pop();
ir::Instruction* chb = currentHeaderBranch.top();
opt::Instruction* chb = currentHeaderBranch.top();
if (chb != nullptr)
currentMergeBlockId = branch2merge_[chb]->GetSingleWordInOperand(0);
}
ir::Instruction* mergeInst;
ir::Instruction* branchInst;
opt::Instruction* mergeInst;
opt::Instruction* branchInst;
uint32_t mergeBlockId;
bool is_header =
IsStructuredHeader(*bi, &mergeInst, &branchInst, &mergeBlockId);
@ -235,8 +235,8 @@ void AggressiveDCEPass::ComputeBlock2HeaderMaps(
}
}
void AggressiveDCEPass::AddBranch(uint32_t labelId, ir::BasicBlock* bp) {
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
void AggressiveDCEPass::AddBranch(uint32_t labelId, opt::BasicBlock* bp) {
std::unique_ptr<opt::Instruction> newBranch(new opt::Instruction(
context(), SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
context()->AnalyzeDefUse(&*newBranch);
@ -245,35 +245,35 @@ void AggressiveDCEPass::AddBranch(uint32_t labelId, ir::BasicBlock* bp) {
}
void AggressiveDCEPass::AddBreaksAndContinuesToWorklist(
ir::Instruction* loopMerge) {
ir::BasicBlock* header = context()->get_instr_block(loopMerge);
opt::Instruction* loopMerge) {
opt::BasicBlock* header = context()->get_instr_block(loopMerge);
uint32_t headerIndex = structured_order_index_[header];
const uint32_t mergeId =
loopMerge->GetSingleWordInOperand(kLoopMergeMergeBlockIdInIdx);
ir::BasicBlock* merge = context()->get_instr_block(mergeId);
opt::BasicBlock* merge = context()->get_instr_block(mergeId);
uint32_t mergeIndex = structured_order_index_[merge];
get_def_use_mgr()->ForEachUser(
mergeId, [headerIndex, mergeIndex, this](ir::Instruction* user) {
mergeId, [headerIndex, mergeIndex, this](opt::Instruction* user) {
if (!user->IsBranch()) return;
ir::BasicBlock* block = context()->get_instr_block(user);
opt::BasicBlock* block = context()->get_instr_block(user);
uint32_t index = structured_order_index_[block];
if (headerIndex < index && index < mergeIndex) {
// This is a break from the loop.
AddToWorklist(user);
// Add branch's merge if there is one.
ir::Instruction* userMerge = branch2merge_[user];
opt::Instruction* userMerge = branch2merge_[user];
if (userMerge != nullptr) AddToWorklist(userMerge);
}
});
const uint32_t contId =
loopMerge->GetSingleWordInOperand(kLoopMergeContinueBlockIdInIdx);
get_def_use_mgr()->ForEachUser(contId, [&contId,
this](ir::Instruction* user) {
this](opt::Instruction* user) {
SpvOp op = user->opcode();
if (op == SpvOpBranchConditional || op == SpvOpSwitch) {
// A conditional branch or switch can only be a continue if it does not
// have a merge instruction or its merge block is not the continue block.
ir::Instruction* hdrMerge = branch2merge_[user];
opt::Instruction* hdrMerge = branch2merge_[user];
if (hdrMerge != nullptr && hdrMerge->opcode() == SpvOpSelectionMerge) {
uint32_t hdrMergeId =
hdrMerge->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
@ -284,10 +284,10 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist(
} else if (op == SpvOpBranch) {
// An unconditional branch can only be a continue if it is not
// branching to its own merge block.
ir::BasicBlock* blk = context()->get_instr_block(user);
ir::Instruction* hdrBranch = block2headerBranch_[blk];
opt::BasicBlock* blk = context()->get_instr_block(user);
opt::Instruction* hdrBranch = block2headerBranch_[blk];
if (hdrBranch == nullptr) return;
ir::Instruction* hdrMerge = branch2merge_[hdrBranch];
opt::Instruction* hdrMerge = branch2merge_[hdrBranch];
if (hdrMerge->opcode() == SpvOpLoopMerge) return;
uint32_t hdrMergeId =
hdrMerge->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
@ -299,17 +299,17 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist(
});
}
bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
bool AggressiveDCEPass::AggressiveDCE(opt::Function* func) {
// Mark function parameters as live.
AddToWorklist(&func->DefInst());
func->ForEachParam(
[this](const ir::Instruction* param) {
AddToWorklist(const_cast<ir::Instruction*>(param));
[this](const opt::Instruction* param) {
AddToWorklist(const_cast<opt::Instruction*>(param));
},
false);
// Compute map from block to controlling conditional branch
std::list<ir::BasicBlock*> structuredOrder;
std::list<opt::BasicBlock*> structuredOrder;
cfg()->ComputeStructuredOrder(func, &*func->begin(), &structuredOrder);
ComputeBlock2HeaderMaps(structuredOrder);
bool modified = false;
@ -404,10 +404,10 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
for (auto& ps : private_stores_) AddToWorklist(ps);
// Perform closure on live instruction set.
while (!worklist_.empty()) {
ir::Instruction* liveInst = worklist_.front();
opt::Instruction* liveInst = worklist_.front();
// Add all operand instructions if not already live
liveInst->ForEachInId([&liveInst, this](const uint32_t* iid) {
ir::Instruction* inInst = get_def_use_mgr()->GetDef(*iid);
opt::Instruction* inInst = get_def_use_mgr()->GetDef(*iid);
// Do not add label if an operand of a branch. This is not needed
// as part of live code discovery and can create false live code,
// for example, the branch to a header of a loop.
@ -421,11 +421,11 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
// conditional branch and its merge. Any containing control construct
// is marked live when the merge and branch are processed out of the
// worklist.
ir::BasicBlock* blk = context()->get_instr_block(liveInst);
ir::Instruction* branchInst = block2headerBranch_[blk];
opt::BasicBlock* blk = context()->get_instr_block(liveInst);
opt::Instruction* branchInst = block2headerBranch_[blk];
if (branchInst != nullptr) {
AddToWorklist(branchInst);
ir::Instruction* mergeInst = branch2merge_[branchInst];
opt::Instruction* mergeInst = branch2merge_[branchInst];
AddToWorklist(mergeInst);
// If in a loop, mark all its break and continue instructions live
if (mergeInst->opcode() == SpvOpLoopMerge)
@ -476,7 +476,8 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
// Kill dead instructions and remember dead blocks
for (auto bi = structuredOrder.begin(); bi != structuredOrder.end();) {
uint32_t mergeBlockId = 0;
(*bi)->ForEachInst([this, &modified, &mergeBlockId](ir::Instruction* inst) {
(*bi)->ForEachInst([this, &modified,
&mergeBlockId](opt::Instruction* inst) {
if (!IsDead(inst)) return;
if (inst->opcode() == SpvOpLabel) return;
// If dead instruction is selection merge, remember merge block
@ -502,7 +503,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
return modified;
}
void AggressiveDCEPass::Initialize(ir::IRContext* c) {
void AggressiveDCEPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
// Initialize extensions whitelist
@ -549,7 +550,7 @@ Pass::Status AggressiveDCEPass::ProcessImpl() {
InitializeModuleScopeLiveInstructions();
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) { return AggressiveDCE(fp); };
ProcessFunction pfn = [this](opt::Function* fp) { return AggressiveDCE(fp); };
modified |= ProcessEntryPointCallTree(pfn, get_module());
// Process module-level instructions. Now that all live instructions have
@ -562,7 +563,7 @@ Pass::Status AggressiveDCEPass::ProcessImpl() {
}
// Cleanup all CFG including all unreachable blocks.
ProcessFunction cleanup = [this](ir::Function* f) { return CFGCleanup(f); };
ProcessFunction cleanup = [this](opt::Function* f) { return CFGCleanup(f); };
modified |= ProcessEntryPointCallTree(cleanup, get_module());
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
@ -572,8 +573,8 @@ bool AggressiveDCEPass::EliminateDeadFunctions() {
// Identify live functions first. Those that are not live
// are dead. ADCE is disabled for non-shaders so we do not check for exported
// functions here.
std::unordered_set<const ir::Function*> live_function_set;
ProcessFunction mark_live = [&live_function_set](ir::Function* fp) {
std::unordered_set<const opt::Function*> live_function_set;
ProcessFunction mark_live = [&live_function_set](opt::Function* fp) {
live_function_set.insert(fp);
return false;
};
@ -594,10 +595,10 @@ bool AggressiveDCEPass::EliminateDeadFunctions() {
return modified;
}
void AggressiveDCEPass::EliminateFunction(ir::Function* func) {
void AggressiveDCEPass::EliminateFunction(opt::Function* func) {
// Remove all of the instruction in the function body
func->ForEachInst(
[this](ir::Instruction* inst) { context()->KillInst(inst); }, true);
[this](opt::Instruction* inst) { context()->KillInst(inst); }, true);
}
bool AggressiveDCEPass::ProcessGlobalValues() {
@ -605,7 +606,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
// This must be done before killing the instructions, otherwise there are
// dead objects in the def/use database.
bool modified = false;
ir::Instruction* instruction = &*get_module()->debug2_begin();
opt::Instruction* instruction = &*get_module()->debug2_begin();
while (instruction) {
if (instruction->opcode() != SpvOpName) {
instruction = instruction->NextNode();
@ -623,7 +624,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
// This code removes all unnecessary decorations safely (see #1174). It also
// does so in a more efficient manner than deleting them only as the targets
// are deleted.
std::vector<ir::Instruction*> annotations;
std::vector<opt::Instruction*> annotations;
for (auto& inst : get_module()->annotations()) annotations.push_back(&inst);
std::sort(annotations.begin(), annotations.end(), DecorationLess());
for (auto annotation : annotations) {
@ -642,7 +643,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
// target. If all targets are dead, remove this decoration.
bool dead = true;
for (uint32_t i = 1; i < annotation->NumOperands();) {
ir::Instruction* opInst =
opt::Instruction* opInst =
get_def_use_mgr()->GetDef(annotation->GetSingleWordOperand(i));
if (IsDead(opInst)) {
// Don't increment |i|.
@ -665,7 +666,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
// decoration.
bool dead = true;
for (uint32_t i = 1; i < annotation->NumOperands();) {
ir::Instruction* opInst =
opt::Instruction* opInst =
get_def_use_mgr()->GetDef(annotation->GetSingleWordOperand(i));
if (IsDead(opInst)) {
// Don't increment |i|.
@ -710,7 +711,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
AggressiveDCEPass::AggressiveDCEPass() {}
Pass::Status AggressiveDCEPass::Process(ir::IRContext* c) {
Pass::Status AggressiveDCEPass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -35,19 +35,19 @@ namespace opt {
// See optimizer.hpp for documentation.
class AggressiveDCEPass : public MemPass {
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const opt::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
std::function<std::vector<opt::BasicBlock*>*(const opt::BasicBlock*)>;
AggressiveDCEPass();
const char* name() const override { return "eliminate-dead-code-aggressive"; }
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping;
}
private:
@ -61,19 +61,19 @@ class AggressiveDCEPass : public MemPass {
bool IsLocalVar(uint32_t varId);
// Return true if |inst| is marked live.
bool IsLive(const ir::Instruction* inst) const {
bool IsLive(const opt::Instruction* inst) const {
return live_insts_.Get(inst->unique_id());
}
// Returns true if |inst| is dead.
bool IsDead(ir::Instruction* inst);
bool IsDead(opt::Instruction* inst);
// Adds entry points, execution modes and workgroup size decorations to the
// worklist for processing with the first function.
void InitializeModuleScopeLiveInstructions();
// Add |inst| to worklist_ and live_insts_.
void AddToWorklist(ir::Instruction* inst) {
void AddToWorklist(opt::Instruction* inst) {
if (!live_insts_.Set(inst->unique_id())) {
worklist_.push(inst);
}
@ -92,7 +92,7 @@ class AggressiveDCEPass : public MemPass {
// Returns true if the target of |inst| is dead. An instruction is dead if
// its result id is used in decoration or debug instructions only. |inst| is
// assumed to be OpName, OpMemberName or an annotation instruction.
bool IsTargetDead(ir::Instruction* inst);
bool IsTargetDead(opt::Instruction* inst);
// If |varId| is local, mark all stores of varId as live.
void ProcessLoad(uint32_t varId);
@ -102,19 +102,20 @@ class AggressiveDCEPass : public MemPass {
// merge block if they are not nullptr. Any of |mergeInst|, |branchInst| or
// |mergeBlockId| may be a null pointer. Returns false if |bp| is a null
// pointer.
bool IsStructuredHeader(ir::BasicBlock* bp, ir::Instruction** mergeInst,
ir::Instruction** branchInst, uint32_t* mergeBlockId);
bool IsStructuredHeader(opt::BasicBlock* bp, opt::Instruction** mergeInst,
opt::Instruction** branchInst,
uint32_t* mergeBlockId);
// Initialize block2headerBranch_ and branch2merge_ using |structuredOrder|
// to order blocks.
void ComputeBlock2HeaderMaps(std::list<ir::BasicBlock*>& structuredOrder);
void ComputeBlock2HeaderMaps(std::list<opt::BasicBlock*>& structuredOrder);
// Add branch to |labelId| to end of block |bp|.
void AddBranch(uint32_t labelId, ir::BasicBlock* bp);
void AddBranch(uint32_t labelId, opt::BasicBlock* bp);
// Add all break and continue branches in the loop associated with
// |mergeInst| to worklist if not already live
void AddBreaksAndContinuesToWorklist(ir::Instruction* mergeInst);
void AddBreaksAndContinuesToWorklist(opt::Instruction* mergeInst);
// Eliminates dead debug2 and annotation instructions. Marks dead globals for
// removal (e.g. types, constants and variables).
@ -124,7 +125,7 @@ class AggressiveDCEPass : public MemPass {
bool EliminateDeadFunctions();
// Removes |func| from the module and deletes all its instructions.
void EliminateFunction(ir::Function* func);
void EliminateFunction(opt::Function* func);
// For function |func|, mark all Stores to non-function-scope variables
// and block terminating instructions as live. Recursively mark the values
@ -135,9 +136,9 @@ class AggressiveDCEPass : public MemPass {
// existing control structures will remain. This can leave not-insignificant
// sequences of ultimately useless code.
// TODO(): Remove useless control constructs.
bool AggressiveDCE(ir::Function* func);
bool AggressiveDCE(opt::Function* func);
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
// True if current function has a call instruction contained in it
@ -154,22 +155,22 @@ class AggressiveDCEPass : public MemPass {
// If we don't know, then add it to this list. Instructions are
// removed from this list as the algorithm traces side effects,
// building up the live instructions set |live_insts_|.
std::queue<ir::Instruction*> worklist_;
std::queue<opt::Instruction*> worklist_;
// Map from block to the branch instruction in the header of the most
// immediate controlling structured if or loop. A loop header block points
// to its own branch instruction. An if-selection block points to the branch
// of an enclosing construct's header, if one exists.
std::unordered_map<ir::BasicBlock*, ir::Instruction*> block2headerBranch_;
std::unordered_map<opt::BasicBlock*, opt::Instruction*> block2headerBranch_;
// Maps basic block to their index in the structured order traversal.
std::unordered_map<ir::BasicBlock*, uint32_t> structured_order_index_;
std::unordered_map<opt::BasicBlock*, uint32_t> structured_order_index_;
// Map from branch to its associated merge instruction, if any
std::unordered_map<ir::Instruction*, ir::Instruction*> branch2merge_;
std::unordered_map<opt::Instruction*, opt::Instruction*> branch2merge_;
// Store instructions to variables of private storage
std::vector<ir::Instruction*> private_stores_;
std::vector<opt::Instruction*> private_stores_;
// Live Instructions
utils::BitVector live_insts_;
@ -179,7 +180,7 @@ class AggressiveDCEPass : public MemPass {
// List of instructions to delete. Deletion is delayed until debug and
// annotation instructions are processed.
std::vector<ir::Instruction*> to_kill_;
std::vector<opt::Instruction*> to_kill_;
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;

View File

@ -23,8 +23,7 @@
#include <ostream>
namespace spvtools {
namespace ir {
namespace opt {
namespace {
const uint32_t kLoopMergeContinueBlockIdInIdx = 1;
@ -91,7 +90,7 @@ Instruction* BasicBlock::GetLoopMergeInst() {
}
void BasicBlock::KillAllInsts(bool killLabel) {
ForEachInst([killLabel](ir::Instruction* ip) {
ForEachInst([killLabel](opt::Instruction* ip) {
if (killLabel || ip->opcode() != SpvOpLabel) {
ip->context()->KillInst(ip);
}
@ -140,7 +139,7 @@ void BasicBlock::ForEachSuccessorLabel(
}
}
bool BasicBlock::IsSuccessor(const ir::BasicBlock* block) const {
bool BasicBlock::IsSuccessor(const opt::BasicBlock* block) const {
uint32_t succId = block->id();
bool isSuccessor = false;
ForEachSuccessorLabel([&isSuccessor, succId](const uint32_t label) {
@ -196,7 +195,7 @@ std::ostream& operator<<(std::ostream& str, const BasicBlock& block) {
std::string BasicBlock::PrettyPrint(uint32_t options) const {
std::ostringstream str;
ForEachInst([&str, options](const ir::Instruction* inst) {
ForEachInst([&str, options](const opt::Instruction* inst) {
str << inst->PrettyPrint(options);
if (!IsTerminatorInst(inst->opcode())) {
str << std::endl;
@ -210,13 +209,13 @@ BasicBlock* BasicBlock::SplitBasicBlock(IRContext* context, uint32_t label_id,
assert(!insts_.empty());
BasicBlock* new_block = new BasicBlock(MakeUnique<Instruction>(
context, SpvOpLabel, 0, label_id, std::initializer_list<ir::Operand>{}));
context, SpvOpLabel, 0, label_id, std::initializer_list<opt::Operand>{}));
new_block->insts_.Splice(new_block->end(), &insts_, iter, end());
new_block->SetParent(GetParent());
if (context->AreAnalysesValid(ir::IRContext::kAnalysisInstrToBlockMapping)) {
new_block->ForEachInst([new_block, context](ir::Instruction* inst) {
if (context->AreAnalysesValid(opt::IRContext::kAnalysisInstrToBlockMapping)) {
new_block->ForEachInst([new_block, context](opt::Instruction* inst) {
context->set_instr_block(inst, new_block);
});
}
@ -224,5 +223,5 @@ BasicBlock* BasicBlock::SplitBasicBlock(IRContext* context, uint32_t label_id,
return new_block;
}
} // namespace ir
} // namespace opt
} // namespace spvtools

View File

@ -30,7 +30,7 @@
#include "iterator.h"
namespace spvtools {
namespace ir {
namespace opt {
class Function;
class IRContext;
@ -159,14 +159,14 @@ class BasicBlock {
void ForEachSuccessorLabel(const std::function<void(uint32_t*)>& f);
// Returns true if |block| is a direct successor of |this|.
bool IsSuccessor(const ir::BasicBlock* block) const;
bool IsSuccessor(const opt::BasicBlock* block) const;
// Runs the given function |f| on the merge and continue label, if any
void ForMergeAndContinueLabel(const std::function<void(const uint32_t)>& f);
// Returns true if this basic block has any Phi instructions.
bool HasPhiInstructions() {
return !WhileEachPhiInst([](ir::Instruction*) { return false; });
return !WhileEachPhiInst([](opt::Instruction*) { return false; });
}
// Return true if this block is a loop header block.
@ -313,7 +313,7 @@ inline void BasicBlock::ForEachPhiInst(
run_on_debug_line_insts);
}
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_BASIC_BLOCK_H_

View File

@ -22,9 +22,9 @@
namespace spvtools {
namespace opt {
void BlockMergePass::KillInstAndName(ir::Instruction* inst) {
std::vector<ir::Instruction*> to_kill;
get_def_use_mgr()->ForEachUser(inst, [&to_kill](ir::Instruction* user) {
void BlockMergePass::KillInstAndName(opt::Instruction* inst) {
std::vector<opt::Instruction*> to_kill;
get_def_use_mgr()->ForEachUser(inst, [&to_kill](opt::Instruction* user) {
if (user->opcode() == SpvOpName) {
to_kill.push_back(user);
}
@ -35,13 +35,13 @@ void BlockMergePass::KillInstAndName(ir::Instruction* inst) {
context()->KillInst(inst);
}
bool BlockMergePass::MergeBlocks(ir::Function* func) {
bool BlockMergePass::MergeBlocks(opt::Function* func) {
bool modified = false;
for (auto bi = func->begin(); bi != func->end();) {
// Find block with single successor which has no other predecessors.
auto ii = bi->end();
--ii;
ir::Instruction* br = &*ii;
opt::Instruction* br = &*ii;
if (br->opcode() != SpvOpBranch) {
++bi;
continue;
@ -69,14 +69,14 @@ bool BlockMergePass::MergeBlocks(ir::Function* func) {
continue;
}
ir::Instruction* merge_inst = bi->GetMergeInst();
opt::Instruction* merge_inst = bi->GetMergeInst();
if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) {
// If this is a header block and the successor is not its merge, we must
// be careful about which blocks we are willing to merge together.
// OpLoopMerge must be followed by a conditional or unconditional branch.
// The merge must be a loop merge because a selection merge cannot be
// followed by an unconditional branch.
ir::BasicBlock* succ_block = context()->get_instr_block(lab_id);
opt::BasicBlock* succ_block = context()->get_instr_block(lab_id);
SpvOp succ_term_op = succ_block->terminator()->opcode();
assert(merge_inst->opcode() == SpvOpLoopMerge);
if (succ_term_op != SpvOpBranch &&
@ -122,7 +122,7 @@ bool BlockMergePass::MergeBlocks(ir::Function* func) {
return modified;
}
bool BlockMergePass::IsHeader(ir::BasicBlock* block) {
bool BlockMergePass::IsHeader(opt::BasicBlock* block) {
return block->GetMergeInst() != nullptr;
}
@ -131,7 +131,7 @@ bool BlockMergePass::IsHeader(uint32_t id) {
}
bool BlockMergePass::IsMerge(uint32_t id) {
return !get_def_use_mgr()->WhileEachUse(id, [](ir::Instruction* user,
return !get_def_use_mgr()->WhileEachUse(id, [](opt::Instruction* user,
uint32_t index) {
SpvOp op = user->opcode();
if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) {
@ -141,22 +141,22 @@ bool BlockMergePass::IsMerge(uint32_t id) {
});
}
bool BlockMergePass::IsMerge(ir::BasicBlock* block) {
bool BlockMergePass::IsMerge(opt::BasicBlock* block) {
return IsMerge(block->id());
}
void BlockMergePass::Initialize(ir::IRContext* c) { InitializeProcessing(c); }
void BlockMergePass::Initialize(opt::IRContext* c) { InitializeProcessing(c); }
Pass::Status BlockMergePass::ProcessImpl() {
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) { return MergeBlocks(fp); };
ProcessFunction pfn = [this](opt::Function* fp) { return MergeBlocks(fp); };
bool modified = ProcessEntryPointCallTree(pfn, get_module());
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
BlockMergePass::BlockMergePass() {}
Pass::Status BlockMergePass::Process(ir::IRContext* c) {
Pass::Status BlockMergePass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -38,33 +38,33 @@ class BlockMergePass : public Pass {
public:
BlockMergePass();
const char* name() const override { return "merge-blocks"; }
Status Process(ir::IRContext*) override;
virtual ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisDecorations |
ir::IRContext::kAnalysisCombinators |
ir::IRContext::kAnalysisNameMap;
Status Process(opt::IRContext*) override;
virtual opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisDecorations |
opt::IRContext::kAnalysisCombinators |
opt::IRContext::kAnalysisNameMap;
}
private:
// Kill any OpName instruction referencing |inst|, then kill |inst|.
void KillInstAndName(ir::Instruction* inst);
void KillInstAndName(opt::Instruction* inst);
// Search |func| for blocks which have a single Branch to a block
// with no other predecessors. Merge these blocks into a single block.
bool MergeBlocks(ir::Function* func);
bool MergeBlocks(opt::Function* func);
// Returns true if |block| (or |id|) contains a merge instruction.
bool IsHeader(ir::BasicBlock* block);
bool IsHeader(opt::BasicBlock* block);
bool IsHeader(uint32_t id);
// Returns true if |block| (or |id|) is the merge target of a merge
// instruction.
bool IsMerge(ir::BasicBlock* block);
bool IsMerge(opt::BasicBlock* block);
bool IsMerge(uint32_t id);
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
};

View File

@ -27,7 +27,7 @@ namespace {
spv_result_t SetSpvHeader(void* builder, spv_endianness_t, uint32_t magic,
uint32_t version, uint32_t generator,
uint32_t id_bound, uint32_t reserved) {
reinterpret_cast<ir::IrLoader*>(builder)->SetModuleHeader(
reinterpret_cast<opt::IrLoader*>(builder)->SetModuleHeader(
magic, version, generator, id_bound, reserved);
return SPV_SUCCESS;
}
@ -35,7 +35,7 @@ spv_result_t SetSpvHeader(void* builder, spv_endianness_t, uint32_t magic,
// Processes a parsed instruction for IrLoader. Meets the interface requirement
// of spvBinaryParse().
spv_result_t SetSpvInst(void* builder, const spv_parsed_instruction_t* inst) {
if (reinterpret_cast<ir::IrLoader*>(builder)->AddInstruction(inst)) {
if (reinterpret_cast<opt::IrLoader*>(builder)->AddInstruction(inst)) {
return SPV_SUCCESS;
}
return SPV_ERROR_INVALID_BINARY;
@ -43,15 +43,15 @@ spv_result_t SetSpvInst(void* builder, const spv_parsed_instruction_t* inst) {
} // namespace
std::unique_ptr<ir::IRContext> BuildModule(spv_target_env env,
MessageConsumer consumer,
const uint32_t* binary,
const size_t size) {
std::unique_ptr<opt::IRContext> BuildModule(spv_target_env env,
MessageConsumer consumer,
const uint32_t* binary,
const size_t size) {
auto context = spvContextCreate(env);
SetContextMessageConsumer(context, consumer);
auto irContext = MakeUnique<ir::IRContext>(env, consumer);
ir::IrLoader loader(consumer, irContext->module());
auto irContext = MakeUnique<opt::IRContext>(env, consumer);
opt::IrLoader loader(consumer, irContext->module());
spv_result_t status = spvBinaryParse(context, &loader, binary, size,
SetSpvHeader, SetSpvInst, nullptr);
@ -62,10 +62,10 @@ std::unique_ptr<ir::IRContext> BuildModule(spv_target_env env,
return status == SPV_SUCCESS ? std::move(irContext) : nullptr;
}
std::unique_ptr<ir::IRContext> BuildModule(spv_target_env env,
MessageConsumer consumer,
const std::string& text,
uint32_t assemble_options) {
std::unique_ptr<opt::IRContext> BuildModule(spv_target_env env,
MessageConsumer consumer,
const std::string& text,
uint32_t assemble_options) {
SpirvTools t(env);
t.SetMessageConsumer(consumer);
std::vector<uint32_t> binary;

View File

@ -24,19 +24,20 @@
namespace spvtools {
// Builds an ir::Module returns the owning ir::IRContext from the given SPIR-V
// Builds an opt::Module returns the owning opt::IRContext from the given SPIR-V
// |binary|. |size| specifies number of words in |binary|. The |binary| will be
// decoded according to the given target |env|. Returns nullptr if errors occur
// and sends the errors to |consumer|.
std::unique_ptr<ir::IRContext> BuildModule(spv_target_env env,
MessageConsumer consumer,
const uint32_t* binary, size_t size);
std::unique_ptr<opt::IRContext> BuildModule(spv_target_env env,
MessageConsumer consumer,
const uint32_t* binary,
size_t size);
// Builds an ir::Module and returns the owning ir::IRContext from the given
// Builds an opt::Module and returns the owning opt::IRContext from the given
// SPIR-V assembly |text|. The |text| will be encoded according to the given
// target |env|. Returns nullptr if errors occur and sends the errors to
// |consumer|.
std::unique_ptr<ir::IRContext> BuildModule(
std::unique_ptr<opt::IRContext> BuildModule(
spv_target_env env, MessageConsumer consumer, const std::string& text,
uint32_t assemble_options = SpirvTools::kDefaultAssembleOption);

View File

@ -39,14 +39,14 @@ const uint32_t kVaryingSSAId = std::numeric_limits<uint32_t>::max();
bool CCPPass::IsVaryingValue(uint32_t id) const { return id == kVaryingSSAId; }
SSAPropagator::PropStatus CCPPass::MarkInstructionVarying(
ir::Instruction* instr) {
opt::Instruction* instr) {
assert(instr->result_id() != 0 &&
"Instructions with no result cannot be marked varying.");
values_[instr->result_id()] = kVaryingSSAId;
return SSAPropagator::kVarying;
}
SSAPropagator::PropStatus CCPPass::VisitPhi(ir::Instruction* phi) {
SSAPropagator::PropStatus CCPPass::VisitPhi(opt::Instruction* phi) {
uint32_t meet_val_id = 0;
// Implement the lattice meet operation. The result of this Phi instruction is
@ -100,7 +100,7 @@ SSAPropagator::PropStatus CCPPass::VisitPhi(ir::Instruction* phi) {
return SSAPropagator::kInteresting;
}
SSAPropagator::PropStatus CCPPass::VisitAssignment(ir::Instruction* instr) {
SSAPropagator::PropStatus CCPPass::VisitAssignment(opt::Instruction* instr) {
assert(instr->result_id() != 0 &&
"Expecting an instruction that produces a result");
@ -133,7 +133,7 @@ SSAPropagator::PropStatus CCPPass::VisitAssignment(ir::Instruction* instr) {
}
return it->second;
};
ir::Instruction* folded_inst =
opt::Instruction* folded_inst =
context()->get_instruction_folder().FoldInstructionToConstant(instr,
map_func);
if (folded_inst != nullptr) {
@ -168,8 +168,8 @@ SSAPropagator::PropStatus CCPPass::VisitAssignment(ir::Instruction* instr) {
return MarkInstructionVarying(instr);
}
SSAPropagator::PropStatus CCPPass::VisitBranch(ir::Instruction* instr,
ir::BasicBlock** dest_bb) const {
SSAPropagator::PropStatus CCPPass::VisitBranch(
opt::Instruction* instr, opt::BasicBlock** dest_bb) const {
assert(instr->IsBranch() && "Expected a branch instruction.");
*dest_bb = nullptr;
@ -250,8 +250,8 @@ SSAPropagator::PropStatus CCPPass::VisitBranch(ir::Instruction* instr,
return SSAPropagator::kInteresting;
}
SSAPropagator::PropStatus CCPPass::VisitInstruction(ir::Instruction* instr,
ir::BasicBlock** dest_bb) {
SSAPropagator::PropStatus CCPPass::VisitInstruction(opt::Instruction* instr,
opt::BasicBlock** dest_bb) {
*dest_bb = nullptr;
if (instr->opcode() == SpvOpPhi) {
return VisitPhi(instr);
@ -275,14 +275,14 @@ bool CCPPass::ReplaceValues() {
return retval;
}
bool CCPPass::PropagateConstants(ir::Function* fp) {
bool CCPPass::PropagateConstants(opt::Function* fp) {
// Mark function parameters as varying.
fp->ForEachParam([this](const ir::Instruction* inst) {
fp->ForEachParam([this](const opt::Instruction* inst) {
values_[inst->result_id()] = kVaryingSSAId;
});
const auto visit_fn = [this](ir::Instruction* instr,
ir::BasicBlock** dest_bb) {
const auto visit_fn = [this](opt::Instruction* instr,
opt::BasicBlock** dest_bb) {
return VisitInstruction(instr, dest_bb);
};
@ -296,7 +296,7 @@ bool CCPPass::PropagateConstants(ir::Function* fp) {
return false;
}
void CCPPass::Initialize(ir::IRContext* c) {
void CCPPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
const_mgr_ = context()->get_constant_mgr();
@ -315,11 +315,11 @@ void CCPPass::Initialize(ir::IRContext* c) {
}
}
Pass::Status CCPPass::Process(ir::IRContext* c) {
Pass::Status CCPPass::Process(opt::IRContext* c) {
Initialize(c);
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return PropagateConstants(fp);
};
bool modified = ProcessReachableCallTree(pfn, context());

View File

@ -29,46 +29,46 @@ class CCPPass : public MemPass {
public:
CCPPass() = default;
const char* name() const override { return "ccp"; }
Status Process(ir::IRContext* c) override;
virtual ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisDecorations |
ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG |
ir::IRContext::kAnalysisDominatorAnalysis |
ir::IRContext::kAnalysisNameMap;
Status Process(opt::IRContext* c) override;
virtual opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisDecorations |
opt::IRContext::kAnalysisCombinators | opt::IRContext::kAnalysisCFG |
opt::IRContext::kAnalysisDominatorAnalysis |
opt::IRContext::kAnalysisNameMap;
}
private:
// Initializes the pass.
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
// Runs constant propagation on the given function |fp|. Returns true if any
// constants were propagated and the IR modified.
bool PropagateConstants(ir::Function* fp);
bool PropagateConstants(opt::Function* fp);
// Visits a single instruction |instr|. If the instruction is a conditional
// branch that always jumps to the same basic block, it sets the destination
// block in |dest_bb|.
SSAPropagator::PropStatus VisitInstruction(ir::Instruction* instr,
ir::BasicBlock** dest_bb);
SSAPropagator::PropStatus VisitInstruction(opt::Instruction* instr,
opt::BasicBlock** dest_bb);
// Visits an OpPhi instruction |phi|. This applies the meet operator for the
// CCP lattice. Essentially, if all the operands in |phi| have the same
// constant value C, the result for |phi| gets assigned the value C.
SSAPropagator::PropStatus VisitPhi(ir::Instruction* phi);
SSAPropagator::PropStatus VisitPhi(opt::Instruction* phi);
// Visits an SSA assignment instruction |instr|. If the RHS of |instr| folds
// into a constant value C, then the LHS of |instr| is assigned the value C in
// |values_|.
SSAPropagator::PropStatus VisitAssignment(ir::Instruction* instr);
SSAPropagator::PropStatus VisitAssignment(opt::Instruction* instr);
// Visits a branch instruction |instr|. If the branch is conditional
// (OpBranchConditional or OpSwitch), and the value of its selector is known,
// |dest_bb| will be set to the corresponding destination block. Unconditional
// branches always set |dest_bb| to the single destination block.
SSAPropagator::PropStatus VisitBranch(ir::Instruction* instr,
ir::BasicBlock** dest_bb) const;
SSAPropagator::PropStatus VisitBranch(opt::Instruction* instr,
opt::BasicBlock** dest_bb) const;
// Replaces all operands used in |fp| with the corresponding constant values
// in |values_|. Returns true if any operands were replaced, and false
@ -77,7 +77,7 @@ class CCPPass : public MemPass {
// Marks |instr| as varying by registering a varying value for its result
// into the |values_| table. Returns SSAPropagator::kVarying.
SSAPropagator::PropStatus MarkInstructionVarying(ir::Instruction* instr);
SSAPropagator::PropStatus MarkInstructionVarying(opt::Instruction* instr);
// Returns true if |id| is the special SSA id that corresponds to a varying
// value.

View File

@ -19,21 +19,20 @@
#include "module.h"
namespace spvtools {
namespace ir {
namespace opt {
namespace {
// Universal Limit of ResultID + 1
const int kInvalidId = 0x400000;
const int kMaxResultId = 0x400000;
} // namespace
CFG::CFG(ir::Module* module)
CFG::CFG(opt::Module* module)
: module_(module),
pseudo_entry_block_(std::unique_ptr<ir::Instruction>(
new ir::Instruction(module->context(), SpvOpLabel, 0, 0, {}))),
pseudo_exit_block_(std::unique_ptr<ir::Instruction>(new ir::Instruction(
module->context(), SpvOpLabel, 0, kInvalidId, {}))) {
pseudo_entry_block_(std::unique_ptr<opt::Instruction>(
new opt::Instruction(module->context(), SpvOpLabel, 0, 0, {}))),
pseudo_exit_block_(std::unique_ptr<opt::Instruction>(new opt::Instruction(
module->context(), SpvOpLabel, 0, kMaxResultId, {}))) {
for (auto& fn : *module) {
for (auto& blk : fn) {
RegisterBlock(&blk);
@ -41,7 +40,7 @@ CFG::CFG(ir::Module* module)
}
}
void CFG::AddEdges(ir::BasicBlock* blk) {
void CFG::AddEdges(opt::BasicBlock* blk) {
uint32_t blk_id = blk->id();
// Force the creation of an entry, not all basic block have predecessors
// (such as the entry blocks and some unreachables).
@ -54,7 +53,7 @@ void CFG::AddEdges(ir::BasicBlock* blk) {
void CFG::RemoveNonExistingEdges(uint32_t blk_id) {
std::vector<uint32_t> updated_pred_list;
for (uint32_t id : preds(blk_id)) {
const ir::BasicBlock* pred_blk = block(id);
const opt::BasicBlock* pred_blk = block(id);
bool has_branch = false;
pred_blk->ForEachSuccessorLabel([&has_branch, blk_id](uint32_t succ) {
if (succ == blk_id) {
@ -67,8 +66,8 @@ void CFG::RemoveNonExistingEdges(uint32_t blk_id) {
label2preds_.at(blk_id) = std::move(updated_pred_list);
}
void CFG::ComputeStructuredOrder(ir::Function* func, ir::BasicBlock* root,
std::list<ir::BasicBlock*>* order) {
void CFG::ComputeStructuredOrder(opt::Function* func, opt::BasicBlock* root,
std::list<opt::BasicBlock*>* order) {
assert(module_->context()->get_feature_mgr()->HasCapability(
SpvCapabilityShader) &&
"This only works on structured control flow");
@ -77,16 +76,16 @@ void CFG::ComputeStructuredOrder(ir::Function* func, ir::BasicBlock* root,
ComputeStructuredSuccessors(func);
auto ignore_block = [](cbb_ptr) {};
auto ignore_edge = [](cbb_ptr, cbb_ptr) {};
auto get_structured_successors = [this](const ir::BasicBlock* b) {
auto get_structured_successors = [this](const opt::BasicBlock* b) {
return &(block2structured_succs_[b]);
};
// TODO(greg-lunarg): Get rid of const_cast by making moving const
// out of the cfa.h prototypes and into the invoking code.
auto post_order = [&](cbb_ptr b) {
order->push_front(const_cast<ir::BasicBlock*>(b));
order->push_front(const_cast<opt::BasicBlock*>(b));
};
CFA<ir::BasicBlock>::DepthFirstTraversal(
CFA<opt::BasicBlock>::DepthFirstTraversal(
root, get_structured_successors, ignore_block, post_order, ignore_edge);
}
@ -116,7 +115,7 @@ void CFG::ForEachBlockInReversePostOrder(
}
}
void CFG::ComputeStructuredSuccessors(ir::Function* func) {
void CFG::ComputeStructuredSuccessors(opt::Function* func) {
block2structured_succs_.clear();
for (auto& blk : *func) {
// If no predecessors in function, make successor to pseudo entry.
@ -155,7 +154,7 @@ void CFG::ComputePostOrderTraversal(BasicBlock* bb, vector<BasicBlock*>* order,
order->push_back(bb);
}
BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
BasicBlock* CFG::SplitLoopHeader(opt::BasicBlock* bb) {
assert(bb->GetLoopMergeInst() && "Expecting bb to be the header of a loop.");
Function* fn = bb->GetParent();
@ -169,7 +168,7 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
const std::vector<uint32_t>& pred = preds(bb->id());
// Find the back edge
ir::BasicBlock* latch_block = nullptr;
opt::BasicBlock* latch_block = nullptr;
Function::iterator latch_block_iter = header_it;
while (++latch_block_iter != fn->end()) {
// If blocks are in the proper order, then the only branch that appears
@ -191,13 +190,13 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
++iter;
}
std::unique_ptr<ir::BasicBlock> newBlock(
std::unique_ptr<opt::BasicBlock> newBlock(
bb->SplitBasicBlock(context, context->TakeNextId(), iter));
// Insert the new bb in the correct position
auto insert_pos = header_it;
++insert_pos;
ir::BasicBlock* new_header = &*insert_pos.InsertBefore(std::move(newBlock));
opt::BasicBlock* new_header = &*insert_pos.InsertBefore(std::move(newBlock));
new_header->SetParent(fn);
uint32_t new_header_id = new_header->id();
context->AnalyzeDefUse(new_header->GetLabelInst());
@ -207,7 +206,7 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
// Update bb mappings.
context->set_instr_block(new_header->GetLabelInst(), new_header);
new_header->ForEachInst([new_header, context](ir::Instruction* inst) {
new_header->ForEachInst([new_header, context](opt::Instruction* inst) {
context->set_instr_block(inst, new_header);
});
@ -235,10 +234,10 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
if (preheader_phi_ops.size() > 2) {
opt::InstructionBuilder builder(
context, &*bb->begin(),
ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping);
opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping);
ir::Instruction* new_phi =
opt::Instruction* new_phi =
builder.AddPhi(phi->type_id(), preheader_phi_ops);
// Add the OpPhi to the header bb.
@ -252,7 +251,7 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
}
phi->RemoveFromList();
std::unique_ptr<ir::Instruction> phi_owner(phi);
std::unique_ptr<opt::Instruction> phi_owner(phi);
phi->SetInOperands(std::move(header_phi_ops));
new_header->begin()->InsertBefore(std::move(phi_owner));
context->set_instr_block(phi, new_header);
@ -262,11 +261,11 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
// Add a branch to the new header.
opt::InstructionBuilder branch_builder(
context, bb,
ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping);
bb->AddInstruction(MakeUnique<ir::Instruction>(
opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping);
bb->AddInstruction(MakeUnique<opt::Instruction>(
context, SpvOpBranch, 0, 0,
std::initializer_list<ir::Operand>{
std::initializer_list<opt::Operand>{
{SPV_OPERAND_TYPE_ID, {new_header->id()}}}));
context->AnalyzeUses(bb->terminator());
context->set_instr_block(bb->terminator(), bb);
@ -278,7 +277,7 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
*id = new_header_id;
}
});
ir::Instruction* latch_branch = latch_block->terminator();
opt::Instruction* latch_branch = latch_block->terminator();
context->AnalyzeUses(latch_branch);
label2preds_[new_header->id()].push_back(latch_block->id());
@ -289,7 +288,7 @@ BasicBlock* CFG::SplitLoopHeader(ir::BasicBlock* bb) {
block_preds.erase(latch_pos);
// Update the loop descriptors
if (context->AreAnalysesValid(ir::IRContext::kAnalysisLoopAnalysis)) {
if (context->AreAnalysesValid(opt::IRContext::kAnalysisLoopAnalysis)) {
LoopDescriptor* loop_desc = context->GetLoopDescriptor(bb->GetParent());
Loop* loop = (*loop_desc)[bb->id()];
@ -319,5 +318,5 @@ unordered_set<BasicBlock*> CFG::FindReachableBlocks(BasicBlock* start) {
return reachable_blocks;
}
} // namespace ir
} // namespace opt
} // namespace spvtools

View File

@ -23,17 +23,17 @@
#include <unordered_set>
namespace spvtools {
namespace ir {
namespace opt {
class CFG {
public:
CFG(ir::Module* module);
CFG(opt::Module* module);
// Return the module described by this CFG.
ir::Module* get_module() const { return module_; }
opt::Module* get_module() const { return module_; }
// Return the list of predecesors for basic block with label |blkid|.
// TODO(dnovillo): Move this to ir::BasicBlock.
// TODO(dnovillo): Move this to opt::BasicBlock.
const std::vector<uint32_t>& preds(uint32_t blk_id) const {
assert(label2preds_.count(blk_id));
return label2preds_.at(blk_id);
@ -41,26 +41,26 @@ class CFG {
// Return a pointer to the basic block instance corresponding to the label
// |blk_id|.
ir::BasicBlock* block(uint32_t blk_id) const { return id2block_.at(blk_id); }
opt::BasicBlock* block(uint32_t blk_id) const { return id2block_.at(blk_id); }
// Return the pseudo entry and exit blocks.
const ir::BasicBlock* pseudo_entry_block() const {
const opt::BasicBlock* pseudo_entry_block() const {
return &pseudo_entry_block_;
}
ir::BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
opt::BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
const ir::BasicBlock* pseudo_exit_block() const {
const opt::BasicBlock* pseudo_exit_block() const {
return &pseudo_exit_block_;
}
ir::BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
opt::BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
// Return true if |block_ptr| is the pseudo-entry block.
bool IsPseudoEntryBlock(ir::BasicBlock* block_ptr) const {
bool IsPseudoEntryBlock(opt::BasicBlock* block_ptr) const {
return block_ptr == &pseudo_entry_block_;
}
// Return true if |block_ptr| is the pseudo-exit block.
bool IsPseudoExitBlock(ir::BasicBlock* block_ptr) const {
bool IsPseudoExitBlock(opt::BasicBlock* block_ptr) const {
return block_ptr == &pseudo_exit_block_;
}
@ -68,8 +68,8 @@ class CFG {
// This order has the property that dominators come before all blocks they
// dominate and merge blocks come after all blocks that are in the control
// constructs of their header.
void ComputeStructuredOrder(ir::Function* func, ir::BasicBlock* root,
std::list<ir::BasicBlock*>* order);
void ComputeStructuredOrder(opt::Function* func, opt::BasicBlock* root,
std::list<opt::BasicBlock*>* order);
// Applies |f| to the basic block in post order starting with |bb|.
// Note that basic blocks that cannot be reached from |bb| node will not be
@ -85,14 +85,14 @@ class CFG {
// Registers |blk| as a basic block in the cfg, this also updates the
// predecessor lists of each successor of |blk|.
void RegisterBlock(ir::BasicBlock* blk) {
void RegisterBlock(opt::BasicBlock* blk) {
uint32_t blk_id = blk->id();
id2block_[blk_id] = blk;
AddEdges(blk);
}
// Removes from the CFG any mapping for the basic block id |blk_id|.
void ForgetBlock(const ir::BasicBlock* blk) {
void ForgetBlock(const opt::BasicBlock* blk) {
id2block_.erase(blk->id());
label2preds_.erase(blk->id());
RemoveSuccessorEdges(blk);
@ -107,7 +107,7 @@ class CFG {
}
// Registers |blk| to all of its successors.
void AddEdges(ir::BasicBlock* blk);
void AddEdges(opt::BasicBlock* blk);
// Registers the basic block id |pred_blk_id| as being a predecessor of the
// basic block id |succ_blk_id|.
@ -120,7 +120,7 @@ class CFG {
void RemoveNonExistingEdges(uint32_t blk_id);
// Remove all edges that leave |bb|.
void RemoveSuccessorEdges(const ir::BasicBlock* bb) {
void RemoveSuccessorEdges(const opt::BasicBlock* bb) {
bb->ForEachSuccessorLabel(
[bb, this](uint32_t succ_id) { RemoveEdge(bb->id(), succ_id); });
}
@ -130,12 +130,12 @@ class CFG {
// is a new block that will be the new loop header.
//
// Returns a pointer to the new loop header.
BasicBlock* SplitLoopHeader(ir::BasicBlock* bb);
BasicBlock* SplitLoopHeader(opt::BasicBlock* bb);
std::unordered_set<BasicBlock*> FindReachableBlocks(BasicBlock* start);
private:
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const opt::BasicBlock*;
// Compute structured successors for function |func|. A block's structured
// successors are the blocks it branches to together with its declared merge
@ -144,7 +144,7 @@ class CFG {
// first search in the presence of early returns and kills. If the successor
// vector contain duplicates of the merge or continue blocks, they are safely
// ignored by DFS.
void ComputeStructuredSuccessors(ir::Function* func);
void ComputeStructuredSuccessors(opt::Function* func);
// Computes the post-order traversal of the cfg starting at |bb| skipping
// nodes in |seen|. The order of the traversal is appended to |order|, and
@ -154,28 +154,28 @@ class CFG {
std::unordered_set<BasicBlock*>* seen);
// Module for this CFG.
ir::Module* module_;
opt::Module* module_;
// Map from block to its structured successor blocks. See
// ComputeStructuredSuccessors() for definition.
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
std::unordered_map<const opt::BasicBlock*, std::vector<opt::BasicBlock*>>
block2structured_succs_;
// Extra block whose successors are all blocks with no predecessors
// in function.
ir::BasicBlock pseudo_entry_block_;
opt::BasicBlock pseudo_entry_block_;
// Augmented CFG Exit Block.
ir::BasicBlock pseudo_exit_block_;
opt::BasicBlock pseudo_exit_block_;
// Map from block's label id to its predecessor blocks ids
std::unordered_map<uint32_t, std::vector<uint32_t>> label2preds_;
// Map from block's label id to block.
std::unordered_map<uint32_t, ir::BasicBlock*> id2block_;
std::unordered_map<uint32_t, opt::BasicBlock*> id2block_;
};
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_CFG_H_

View File

@ -27,13 +27,13 @@
namespace spvtools {
namespace opt {
void CFGCleanupPass::Initialize(ir::IRContext* c) { InitializeProcessing(c); }
void CFGCleanupPass::Initialize(opt::IRContext* c) { InitializeProcessing(c); }
Pass::Status CFGCleanupPass::Process(ir::IRContext* c) {
Pass::Status CFGCleanupPass::Process(opt::IRContext* c) {
Initialize(c);
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) { return CFGCleanup(fp); };
ProcessFunction pfn = [this](opt::Function* fp) { return CFGCleanup(fp); };
bool modified = ProcessReachableCallTree(pfn, context());
return modified ? Pass::Status::SuccessWithChange
: Pass::Status::SuccessWithoutChange;

View File

@ -26,15 +26,15 @@ class CFGCleanupPass : public MemPass {
public:
CFGCleanupPass() = default;
const char* name() const override { return "cfg-cleanup"; }
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse;
}
private:
// Initialize the pass.
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
};
} // namespace opt

View File

@ -41,7 +41,7 @@ bool CommonUniformElimPass::IsNonPtrAccessChain(const SpvOp opcode) const {
}
bool CommonUniformElimPass::IsSamplerOrImageType(
const ir::Instruction* typeInst) const {
const opt::Instruction* typeInst) const {
switch (typeInst->opcode()) {
case SpvOpTypeSampler:
case SpvOpTypeImage:
@ -53,7 +53,7 @@ bool CommonUniformElimPass::IsSamplerOrImageType(
if (typeInst->opcode() != SpvOpTypeStruct) return false;
// Return true if any member is a sampler or image
return !typeInst->WhileEachInId([this](const uint32_t* tid) {
const ir::Instruction* compTypeInst = get_def_use_mgr()->GetDef(*tid);
const opt::Instruction* compTypeInst = get_def_use_mgr()->GetDef(*tid);
if (IsSamplerOrImageType(compTypeInst)) {
return false;
}
@ -62,28 +62,28 @@ bool CommonUniformElimPass::IsSamplerOrImageType(
}
bool CommonUniformElimPass::IsSamplerOrImageVar(uint32_t varId) const {
const ir::Instruction* varInst = get_def_use_mgr()->GetDef(varId);
const opt::Instruction* varInst = get_def_use_mgr()->GetDef(varId);
assert(varInst->opcode() == SpvOpVariable);
const uint32_t varTypeId = varInst->type_id();
const ir::Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId);
const opt::Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId);
const uint32_t varPteTypeId =
varTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx);
ir::Instruction* varPteTypeInst = get_def_use_mgr()->GetDef(varPteTypeId);
opt::Instruction* varPteTypeInst = get_def_use_mgr()->GetDef(varPteTypeId);
return IsSamplerOrImageType(varPteTypeInst);
}
ir::Instruction* CommonUniformElimPass::GetPtr(ir::Instruction* ip,
uint32_t* objId) {
opt::Instruction* CommonUniformElimPass::GetPtr(opt::Instruction* ip,
uint32_t* objId) {
const SpvOp op = ip->opcode();
assert(op == SpvOpStore || op == SpvOpLoad);
*objId = ip->GetSingleWordInOperand(op == SpvOpStore ? kStorePtrIdInIdx
: kLoadPtrIdInIdx);
ir::Instruction* ptrInst = get_def_use_mgr()->GetDef(*objId);
opt::Instruction* ptrInst = get_def_use_mgr()->GetDef(*objId);
while (ptrInst->opcode() == SpvOpCopyObject) {
*objId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx);
ptrInst = get_def_use_mgr()->GetDef(*objId);
}
ir::Instruction* objInst = ptrInst;
opt::Instruction* objInst = ptrInst;
while (objInst->opcode() != SpvOpVariable &&
objInst->opcode() != SpvOpFunctionParameter) {
if (IsNonPtrAccessChain(objInst->opcode())) {
@ -101,21 +101,21 @@ bool CommonUniformElimPass::IsVolatileStruct(uint32_t type_id) {
assert(get_def_use_mgr()->GetDef(type_id)->opcode() == SpvOpTypeStruct);
return !get_decoration_mgr()->WhileEachDecoration(
type_id, SpvDecorationVolatile,
[](const ir::Instruction&) { return false; });
[](const opt::Instruction&) { return false; });
}
bool CommonUniformElimPass::IsAccessChainToVolatileStructType(
const ir::Instruction& AccessChainInst) {
const opt::Instruction& AccessChainInst) {
assert(AccessChainInst.opcode() == SpvOpAccessChain);
uint32_t ptr_id = AccessChainInst.GetSingleWordInOperand(0);
const ir::Instruction* ptr_inst = get_def_use_mgr()->GetDef(ptr_id);
const opt::Instruction* ptr_inst = get_def_use_mgr()->GetDef(ptr_id);
uint32_t pointee_type_id = GetPointeeTypeId(ptr_inst);
const uint32_t num_operands = AccessChainInst.NumOperands();
// walk the type tree:
for (uint32_t idx = 3; idx < num_operands; ++idx) {
ir::Instruction* pointee_type = get_def_use_mgr()->GetDef(pointee_type_id);
opt::Instruction* pointee_type = get_def_use_mgr()->GetDef(pointee_type_id);
switch (pointee_type->opcode()) {
case SpvOpTypeMatrix:
@ -130,7 +130,7 @@ bool CommonUniformElimPass::IsAccessChainToVolatileStructType(
if (idx < num_operands - 1) {
const uint32_t index_id = AccessChainInst.GetSingleWordOperand(idx);
const ir::Instruction* index_inst =
const opt::Instruction* index_inst =
get_def_use_mgr()->GetDef(index_id);
uint32_t index_value = index_inst->GetSingleWordOperand(
2); // TODO: replace with GetUintValueFromConstant()
@ -144,7 +144,7 @@ bool CommonUniformElimPass::IsAccessChainToVolatileStructType(
return false;
}
bool CommonUniformElimPass::IsVolatileLoad(const ir::Instruction& loadInst) {
bool CommonUniformElimPass::IsVolatileLoad(const opt::Instruction& loadInst) {
assert(loadInst.opcode() == SpvOpLoad);
// Check if this Load instruction has Volatile Memory Access flag
if (loadInst.NumOperands() == 4) {
@ -161,11 +161,11 @@ bool CommonUniformElimPass::IsVolatileLoad(const ir::Instruction& loadInst) {
}
bool CommonUniformElimPass::IsUniformVar(uint32_t varId) {
const ir::Instruction* varInst =
const opt::Instruction* varInst =
get_def_use_mgr()->id_to_defs().find(varId)->second;
if (varInst->opcode() != SpvOpVariable) return false;
const uint32_t varTypeId = varInst->type_id();
const ir::Instruction* varTypeInst =
const opt::Instruction* varTypeInst =
get_def_use_mgr()->id_to_defs().find(varTypeId)->second;
return varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) ==
SpvStorageClassUniform ||
@ -174,21 +174,21 @@ bool CommonUniformElimPass::IsUniformVar(uint32_t varId) {
}
bool CommonUniformElimPass::HasUnsupportedDecorates(uint32_t id) const {
return !get_def_use_mgr()->WhileEachUser(id, [this](ir::Instruction* user) {
return !get_def_use_mgr()->WhileEachUser(id, [this](opt::Instruction* user) {
if (IsNonTypeDecorate(user->opcode())) return false;
return true;
});
}
bool CommonUniformElimPass::HasOnlyNamesAndDecorates(uint32_t id) const {
return get_def_use_mgr()->WhileEachUser(id, [this](ir::Instruction* user) {
return get_def_use_mgr()->WhileEachUser(id, [this](opt::Instruction* user) {
SpvOp op = user->opcode();
if (op != SpvOpName && !IsNonTypeDecorate(op)) return false;
return true;
});
}
void CommonUniformElimPass::DeleteIfUseless(ir::Instruction* inst) {
void CommonUniformElimPass::DeleteIfUseless(opt::Instruction* inst) {
const uint32_t resId = inst->result_id();
assert(resId != 0);
if (HasOnlyNamesAndDecorates(resId)) {
@ -196,34 +196,34 @@ void CommonUniformElimPass::DeleteIfUseless(ir::Instruction* inst) {
}
}
ir::Instruction* CommonUniformElimPass::ReplaceAndDeleteLoad(
ir::Instruction* loadInst, uint32_t replId, ir::Instruction* ptrInst) {
opt::Instruction* CommonUniformElimPass::ReplaceAndDeleteLoad(
opt::Instruction* loadInst, uint32_t replId, opt::Instruction* ptrInst) {
const uint32_t loadId = loadInst->result_id();
context()->KillNamesAndDecorates(loadId);
(void)context()->ReplaceAllUsesWith(loadId, replId);
// remove load instruction
ir::Instruction* next_instruction = context()->KillInst(loadInst);
opt::Instruction* next_instruction = context()->KillInst(loadInst);
// if access chain, see if it can be removed as well
if (IsNonPtrAccessChain(ptrInst->opcode())) DeleteIfUseless(ptrInst);
return next_instruction;
}
void CommonUniformElimPass::GenACLoadRepl(
const ir::Instruction* ptrInst,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts,
const opt::Instruction* ptrInst,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts,
uint32_t* resultId) {
// Build and append Load
const uint32_t ldResultId = TakeNextId();
const uint32_t varId =
ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx);
const ir::Instruction* varInst = get_def_use_mgr()->GetDef(varId);
const opt::Instruction* varInst = get_def_use_mgr()->GetDef(varId);
assert(varInst->opcode() == SpvOpVariable);
const uint32_t varPteTypeId = GetPointeeTypeId(varInst);
std::vector<ir::Operand> load_in_operands;
std::vector<opt::Operand> load_in_operands;
load_in_operands.push_back(
ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
std::initializer_list<uint32_t>{varId}));
std::unique_ptr<ir::Instruction> newLoad(new ir::Instruction(
opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
std::initializer_list<uint32_t>{varId}));
std::unique_ptr<opt::Instruction> newLoad(new opt::Instruction(
context(), SpvOpLoad, varPteTypeId, ldResultId, load_in_operands));
get_def_use_mgr()->AnalyzeInstDefUse(&*newLoad);
newInsts->emplace_back(std::move(newLoad));
@ -231,34 +231,34 @@ void CommonUniformElimPass::GenACLoadRepl(
// Build and append Extract
const uint32_t extResultId = TakeNextId();
const uint32_t ptrPteTypeId = GetPointeeTypeId(ptrInst);
std::vector<ir::Operand> ext_in_opnds;
std::vector<opt::Operand> ext_in_opnds;
ext_in_opnds.push_back(
ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
std::initializer_list<uint32_t>{ldResultId}));
opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
std::initializer_list<uint32_t>{ldResultId}));
uint32_t iidIdx = 0;
ptrInst->ForEachInId([&iidIdx, &ext_in_opnds, this](const uint32_t* iid) {
if (iidIdx > 0) {
const ir::Instruction* cInst = get_def_use_mgr()->GetDef(*iid);
const opt::Instruction* cInst = get_def_use_mgr()->GetDef(*iid);
uint32_t val = cInst->GetSingleWordInOperand(kConstantValueInIdx);
ext_in_opnds.push_back(
ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
std::initializer_list<uint32_t>{val}));
opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
std::initializer_list<uint32_t>{val}));
}
++iidIdx;
});
std::unique_ptr<ir::Instruction> newExt(
new ir::Instruction(context(), SpvOpCompositeExtract, ptrPteTypeId,
extResultId, ext_in_opnds));
std::unique_ptr<opt::Instruction> newExt(
new opt::Instruction(context(), SpvOpCompositeExtract, ptrPteTypeId,
extResultId, ext_in_opnds));
get_def_use_mgr()->AnalyzeInstDefUse(&*newExt);
newInsts->emplace_back(std::move(newExt));
*resultId = extResultId;
}
bool CommonUniformElimPass::IsConstantIndexAccessChain(ir::Instruction* acp) {
bool CommonUniformElimPass::IsConstantIndexAccessChain(opt::Instruction* acp) {
uint32_t inIdx = 0;
return acp->WhileEachInId([&inIdx, this](uint32_t* tid) {
if (inIdx > 0) {
ir::Instruction* opInst = get_def_use_mgr()->GetDef(*tid);
opt::Instruction* opInst = get_def_use_mgr()->GetDef(*tid);
if (opInst->opcode() != SpvOpConstant) return false;
}
++inIdx;
@ -266,13 +266,14 @@ bool CommonUniformElimPass::IsConstantIndexAccessChain(ir::Instruction* acp) {
});
}
bool CommonUniformElimPass::UniformAccessChainConvert(ir::Function* func) {
bool CommonUniformElimPass::UniformAccessChainConvert(opt::Function* func) {
bool modified = false;
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (ir::Instruction* inst = &*bi->begin(); inst; inst = inst->NextNode()) {
for (opt::Instruction* inst = &*bi->begin(); inst;
inst = inst->NextNode()) {
if (inst->opcode() != SpvOpLoad) continue;
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(inst, &varId);
opt::Instruction* ptrInst = GetPtr(inst, &varId);
if (!IsNonPtrAccessChain(ptrInst->opcode())) continue;
// Do not convert nested access chains
if (ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx) != varId)
@ -283,7 +284,7 @@ bool CommonUniformElimPass::UniformAccessChainConvert(ir::Function* func) {
if (HasUnsupportedDecorates(ptrInst->result_id())) continue;
if (IsVolatileLoad(*inst)) continue;
if (IsAccessChainToVolatileStructType(*ptrInst)) continue;
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
std::vector<std::unique_ptr<opt::Instruction>> newInsts;
uint32_t replId;
GenACLoadRepl(ptrInst, &newInsts, &replId);
inst = ReplaceAndDeleteLoad(inst, replId, ptrInst);
@ -294,7 +295,7 @@ bool CommonUniformElimPass::UniformAccessChainConvert(ir::Function* func) {
return modified;
}
void CommonUniformElimPass::ComputeStructuredSuccessors(ir::Function* func) {
void CommonUniformElimPass::ComputeStructuredSuccessors(opt::Function* func) {
block2structured_succs_.clear();
for (auto& blk : *func) {
// If header, make merge block first successor.
@ -315,32 +316,32 @@ void CommonUniformElimPass::ComputeStructuredSuccessors(ir::Function* func) {
}
void CommonUniformElimPass::ComputeStructuredOrder(
ir::Function* func, std::list<ir::BasicBlock*>* order) {
opt::Function* func, std::list<opt::BasicBlock*>* order) {
// Compute structured successors and do DFS
ComputeStructuredSuccessors(func);
auto ignore_block = [](cbb_ptr) {};
auto ignore_edge = [](cbb_ptr, cbb_ptr) {};
auto get_structured_successors = [this](const ir::BasicBlock* block) {
auto get_structured_successors = [this](const opt::BasicBlock* block) {
return &(block2structured_succs_[block]);
};
// TODO(greg-lunarg): Get rid of const_cast by making moving const
// out of the cfa.h prototypes and into the invoking code.
auto post_order = [&](cbb_ptr b) {
order->push_front(const_cast<ir::BasicBlock*>(b));
order->push_front(const_cast<opt::BasicBlock*>(b));
};
order->clear();
CFA<ir::BasicBlock>::DepthFirstTraversal(
CFA<opt::BasicBlock>::DepthFirstTraversal(
&*func->begin(), get_structured_successors, ignore_block, post_order,
ignore_edge);
}
bool CommonUniformElimPass::CommonUniformLoadElimination(ir::Function* func) {
bool CommonUniformElimPass::CommonUniformLoadElimination(opt::Function* func) {
// Process all blocks in structured order. This is just one way (the
// simplest?) to keep track of the most recent block outside of control
// flow, used to copy common instructions, guaranteed to dominate all
// following load sites.
std::list<ir::BasicBlock*> structuredOrder;
std::list<opt::BasicBlock*> structuredOrder;
ComputeStructuredOrder(func, &structuredOrder);
uniform2load_id_.clear();
bool modified = false;
@ -354,7 +355,7 @@ bool CommonUniformElimPass::CommonUniformLoadElimination(ir::Function* func) {
while (IsUniformLoadToBeRemoved(&*insertItr)) ++insertItr;
uint32_t mergeBlockId = 0;
for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) {
ir::BasicBlock* bp = *bi;
opt::BasicBlock* bp = *bi;
// Check if we are exiting outermost control construct. If so, remember
// new load insertion point. Trying to keep register pressure down.
if (mergeBlockId == bp->id()) {
@ -364,10 +365,11 @@ bool CommonUniformElimPass::CommonUniformLoadElimination(ir::Function* func) {
// ReplaceAndDeleteLoad() can set |insertItr| as a dangling pointer.
while (IsUniformLoadToBeRemoved(&*insertItr)) ++insertItr;
}
for (ir::Instruction* inst = &*bp->begin(); inst; inst = inst->NextNode()) {
for (opt::Instruction* inst = &*bp->begin(); inst;
inst = inst->NextNode()) {
if (inst->opcode() != SpvOpLoad) continue;
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(inst, &varId);
opt::Instruction* ptrInst = GetPtr(inst, &varId);
if (ptrInst->opcode() != SpvOpVariable) continue;
if (!IsUniformVar(varId)) continue;
if (IsSamplerOrImageVar(varId)) continue;
@ -385,7 +387,7 @@ bool CommonUniformElimPass::CommonUniformLoadElimination(ir::Function* func) {
} else {
// Copy load into most recent dominating block and remember it
replId = TakeNextId();
std::unique_ptr<ir::Instruction> newLoad(new ir::Instruction(
std::unique_ptr<opt::Instruction> newLoad(new opt::Instruction(
context(), SpvOpLoad, inst->type_id(), replId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {varId}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*newLoad);
@ -406,14 +408,15 @@ bool CommonUniformElimPass::CommonUniformLoadElimination(ir::Function* func) {
return modified;
}
bool CommonUniformElimPass::CommonUniformLoadElimBlock(ir::Function* func) {
bool CommonUniformElimPass::CommonUniformLoadElimBlock(opt::Function* func) {
bool modified = false;
for (auto& blk : *func) {
uniform2load_id_.clear();
for (ir::Instruction* inst = &*blk.begin(); inst; inst = inst->NextNode()) {
for (opt::Instruction* inst = &*blk.begin(); inst;
inst = inst->NextNode()) {
if (inst->opcode() != SpvOpLoad) continue;
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(inst, &varId);
opt::Instruction* ptrInst = GetPtr(inst, &varId);
if (ptrInst->opcode() != SpvOpVariable) continue;
if (!IsUniformVar(varId)) continue;
if (!IsSamplerOrImageVar(varId)) continue;
@ -434,7 +437,7 @@ bool CommonUniformElimPass::CommonUniformLoadElimBlock(ir::Function* func) {
return modified;
}
bool CommonUniformElimPass::CommonExtractElimination(ir::Function* func) {
bool CommonUniformElimPass::CommonExtractElimination(opt::Function* func) {
// Find all composite ids with duplicate extracts.
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
@ -457,7 +460,7 @@ bool CommonUniformElimPass::CommonExtractElimination(ir::Function* func) {
for (auto idxItr : cItr->second) {
if (idxItr.second.size() < 2) continue;
uint32_t replId = TakeNextId();
std::unique_ptr<ir::Instruction> newExtract(
std::unique_ptr<opt::Instruction> newExtract(
idxItr.second.front()->Clone(context()));
newExtract->SetResultId(replId);
get_def_use_mgr()->AnalyzeInstDefUse(&*newExtract);
@ -476,7 +479,7 @@ bool CommonUniformElimPass::CommonExtractElimination(ir::Function* func) {
return modified;
}
bool CommonUniformElimPass::EliminateCommonUniform(ir::Function* func) {
bool CommonUniformElimPass::EliminateCommonUniform(opt::Function* func) {
bool modified = false;
modified |= UniformAccessChainConvert(func);
modified |= CommonUniformLoadElimination(func);
@ -486,7 +489,7 @@ bool CommonUniformElimPass::EliminateCommonUniform(ir::Function* func) {
return modified;
}
void CommonUniformElimPass::Initialize(ir::IRContext* c) {
void CommonUniformElimPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
// Clear collections.
@ -525,12 +528,12 @@ Pass::Status CommonUniformElimPass::ProcessImpl() {
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// If non-32-bit integer type in module, terminate processing
// TODO(): Handle non-32-bit integer constants in access chains
for (const ir::Instruction& inst : get_module()->types_values())
for (const opt::Instruction& inst : get_module()->types_values())
if (inst.opcode() == SpvOpTypeInt &&
inst.GetSingleWordInOperand(kTypeIntWidthInIdx) != 32)
return Status::SuccessWithoutChange;
// Process entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return EliminateCommonUniform(fp);
};
bool modified = ProcessEntryPointCallTree(pfn, get_module());
@ -539,7 +542,7 @@ Pass::Status CommonUniformElimPass::ProcessImpl() {
CommonUniformElimPass::CommonUniformElimPass() {}
Pass::Status CommonUniformElimPass::Process(ir::IRContext* c) {
Pass::Status CommonUniformElimPass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -36,15 +36,15 @@ namespace opt {
// See optimizer.hpp for documentation.
class CommonUniformElimPass : public Pass {
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const opt::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
std::function<std::vector<opt::BasicBlock*>*(const opt::BasicBlock*)>;
CommonUniformElimPass();
const char* name() const override { return "eliminate-common-uniform"; }
Status Process(ir::IRContext*) override;
Status Process(opt::IRContext*) override;
private:
// Returns true if |opcode| is a non-ptr access chain op
@ -52,7 +52,7 @@ class CommonUniformElimPass : public Pass {
// Returns true if |typeInst| is a sampler or image type or a struct
// containing one, recursively.
bool IsSamplerOrImageType(const ir::Instruction* typeInst) const;
bool IsSamplerOrImageType(const opt::Instruction* typeInst) const;
// Returns true if |varId| is a variable containing a sampler or image.
bool IsSamplerOrImageVar(uint32_t varId) const;
@ -60,7 +60,7 @@ class CommonUniformElimPass : public Pass {
// Given a load or store pointed at by |ip|, return the top-most
// non-CopyObj in its pointer operand. Also return the base pointer
// in |objId|.
ir::Instruction* GetPtr(ir::Instruction* ip, uint32_t* objId);
opt::Instruction* GetPtr(opt::Instruction* ip, uint32_t* objId);
// Return true if variable is uniform
bool IsUniformVar(uint32_t varId);
@ -73,12 +73,12 @@ class CommonUniformElimPass : public Pass {
// if the accessed variable belongs to a volatile
// decorated object or member of a struct type
bool IsAccessChainToVolatileStructType(
const ir::Instruction& AccessChainInst);
const opt::Instruction& AccessChainInst);
// Given an OpLoad instruction, return true if
// OpLoad has a Volatile Memory Access flag or if
// the resulting type is a volatile decorated struct
bool IsVolatileLoad(const ir::Instruction& loadInst);
bool IsVolatileLoad(const opt::Instruction& loadInst);
// Return true if any uses of |id| are decorate ops.
bool HasUnsupportedDecorates(uint32_t id) const;
@ -87,25 +87,25 @@ class CommonUniformElimPass : public Pass {
bool HasOnlyNamesAndDecorates(uint32_t id) const;
// Delete inst if it has no uses. Assumes inst has a resultId.
void DeleteIfUseless(ir::Instruction* inst);
void DeleteIfUseless(opt::Instruction* inst);
// Replace all instances of load's id with replId and delete load
// and its access chain, if any
ir::Instruction* ReplaceAndDeleteLoad(ir::Instruction* loadInst,
uint32_t replId,
ir::Instruction* ptrInst);
opt::Instruction* ReplaceAndDeleteLoad(opt::Instruction* loadInst,
uint32_t replId,
opt::Instruction* ptrInst);
// For the (constant index) access chain ptrInst, create an
// equivalent load and extract
void GenACLoadRepl(const ir::Instruction* ptrInst,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts,
void GenACLoadRepl(const opt::Instruction* ptrInst,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts,
uint32_t* resultId);
// Return true if all indices are constant
bool IsConstantIndexAccessChain(ir::Instruction* acp);
bool IsConstantIndexAccessChain(opt::Instruction* acp);
// Convert all uniform access chain loads into load/extract.
bool UniformAccessChainConvert(ir::Function* func);
bool UniformAccessChainConvert(opt::Function* func);
// Compute structured successors for function |func|.
// A block's structured successors are the blocks it branches to
@ -117,7 +117,7 @@ class CommonUniformElimPass : public Pass {
//
// TODO(dnovillo): This pass computes structured successors slightly different
// than the implementation in class Pass. Can this be re-factored?
void ComputeStructuredSuccessors(ir::Function* func);
void ComputeStructuredSuccessors(opt::Function* func);
// Compute structured block order for |func| into |structuredOrder|. This
// order has the property that dominators come before all blocks they
@ -126,24 +126,24 @@ class CommonUniformElimPass : public Pass {
//
// TODO(dnovillo): This pass computes structured order slightly different
// than the implementation in class Pass. Can this be re-factored?
void ComputeStructuredOrder(ir::Function* func,
std::list<ir::BasicBlock*>* order);
void ComputeStructuredOrder(opt::Function* func,
std::list<opt::BasicBlock*>* order);
// Eliminate loads of uniform variables which have previously been loaded.
// If first load is in control flow, move it to first block of function.
// Most effective if preceded by UniformAccessChainRemoval().
bool CommonUniformLoadElimination(ir::Function* func);
bool CommonUniformLoadElimination(opt::Function* func);
// Eliminate loads of uniform sampler and image variables which have
// previously
// been loaded in the same block for types whose loads cannot cross blocks.
bool CommonUniformLoadElimBlock(ir::Function* func);
bool CommonUniformLoadElimBlock(opt::Function* func);
// Eliminate duplicated extracts of same id. Extract may be moved to same
// block as the id definition. This is primarily intended for extracts
// from uniform loads. Most effective if preceded by
// CommonUniformLoadElimination().
bool CommonExtractElimination(ir::Function* func);
bool CommonExtractElimination(opt::Function* func);
// For function |func|, first change all uniform constant index
// access chain loads into equivalent composite extracts. Then consolidate
@ -157,7 +157,7 @@ class CommonUniformElimPass : public Pass {
// is not enabled. It also currently does not support any extensions.
//
// This function currently only optimizes loads with a single index.
bool EliminateCommonUniform(ir::Function* func);
bool EliminateCommonUniform(opt::Function* func);
// Initialize extensions whitelist
void InitExtensions();
@ -172,10 +172,10 @@ class CommonUniformElimPass : public Pass {
// Return true if |inst| is an instruction that loads uniform variable and
// can be replaced with other uniform load instruction.
bool IsUniformLoadToBeRemoved(ir::Instruction* inst) {
bool IsUniformLoadToBeRemoved(opt::Instruction* inst) {
if (inst->opcode() == SpvOpLoad) {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(inst, &varId);
opt::Instruction* ptrInst = GetPtr(inst, &varId);
if (ptrInst->opcode() == SpvOpVariable && IsUniformVar(varId) &&
!IsSamplerOrImageVar(varId) &&
!HasUnsupportedDecorates(inst->result_id()) && !IsVolatileLoad(*inst))
@ -184,7 +184,7 @@ class CommonUniformElimPass : public Pass {
return false;
}
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
// Map from uniform variable id to its common load id
@ -193,7 +193,7 @@ class CommonUniformElimPass : public Pass {
// Map of extract composite ids to map of indices to insts
// TODO(greg-lunarg): Consider std::vector.
std::unordered_map<uint32_t,
std::unordered_map<uint32_t, std::list<ir::Instruction*>>>
std::unordered_map<uint32_t, std::list<opt::Instruction*>>>
comp2idx2inst_;
// Extensions supported by this pass.
@ -201,7 +201,7 @@ class CommonUniformElimPass : public Pass {
// Map from block to its structured successor blocks. See
// ComputeStructuredSuccessors() for definition.
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
std::unordered_map<const opt::BasicBlock*, std::vector<opt::BasicBlock*>>
block2structured_succs_;
};

View File

@ -21,10 +21,10 @@
namespace spvtools {
namespace opt {
using ir::Instruction;
using ir::Operand;
using opt::Instruction;
using opt::Operand;
Pass::Status CompactIdsPass::Process(ir::IRContext* c) {
Pass::Status CompactIdsPass::Process(opt::IRContext* c) {
InitializeProcessing(c);
bool modified = false;

View File

@ -26,13 +26,13 @@ namespace opt {
class CompactIdsPass : public Pass {
public:
const char* name() const override { return "compact-ids"; }
Status Process(ir::IRContext*) override;
Status Process(opt::IRContext*) override;
// Return the mask of preserved Analyses.
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisDominatorAnalysis |
ir::IRContext::kAnalysisLoopAnalysis;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisDominatorAnalysis |
opt::IRContext::kAnalysisLoopAnalysis;
}
};

View File

@ -26,7 +26,7 @@ namespace spvtools {
namespace opt {
bool ExtInsMatch(const std::vector<uint32_t>& extIndices,
const ir::Instruction* insInst, const uint32_t extOffset) {
const opt::Instruction* insInst, const uint32_t extOffset) {
uint32_t numIndices = static_cast<uint32_t>(extIndices.size()) - extOffset;
if (numIndices != insInst->NumInOperands() - 2) return false;
for (uint32_t i = 0; i < numIndices; ++i)
@ -36,7 +36,7 @@ bool ExtInsMatch(const std::vector<uint32_t>& extIndices,
}
bool ExtInsConflict(const std::vector<uint32_t>& extIndices,
const ir::Instruction* insInst, const uint32_t extOffset) {
const opt::Instruction* insInst, const uint32_t extOffset) {
if (extIndices.size() - extOffset == insInst->NumInOperands() - 2)
return false;
uint32_t extNumIndices = static_cast<uint32_t>(extIndices.size()) - extOffset;

View File

@ -34,7 +34,7 @@ namespace opt {
// Return true if the extract indices in |extIndices| starting at |extOffset|
// match indices of insert |insInst|.
bool ExtInsMatch(const std::vector<uint32_t>& extIndices,
const ir::Instruction* insInst, const uint32_t extOffset);
const opt::Instruction* insInst, const uint32_t extOffset);
// Return true if indices in |extIndices| starting at |extOffset| and
// indices of insert |insInst| conflict, specifically, if the insert
@ -42,7 +42,7 @@ bool ExtInsMatch(const std::vector<uint32_t>& extIndices,
// or less bits than the extract specifies, meaning the exact value being
// inserted cannot be used to replace the extract.
bool ExtInsConflict(const std::vector<uint32_t>& extIndices,
const ir::Instruction* insInst, const uint32_t extOffset);
const opt::Instruction* insInst, const uint32_t extOffset);
} // namespace opt
} // namespace spvtools

View File

@ -35,7 +35,7 @@ bool HasFloatingPoint(const analysis::Type* type) {
// Folds an OpcompositeExtract where input is a composite constant.
ConstantFoldingRule FoldExtractWithConstants() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
const analysis::Constant* c = constants[kExtractCompositeIdInIdx];
@ -47,7 +47,7 @@ ConstantFoldingRule FoldExtractWithConstants() {
uint32_t element_index = inst->GetSingleWordInOperand(i);
if (c->AsNullConstant()) {
// Return Null for the return type.
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
return const_mgr->GetConstant(type_mgr->GetType(inst->type_id()), {});
@ -63,7 +63,7 @@ ConstantFoldingRule FoldExtractWithConstants() {
}
ConstantFoldingRule FoldVectorShuffleWithConstants() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
assert(inst->opcode() == SpvOpVectorShuffle);
@ -73,7 +73,7 @@ ConstantFoldingRule FoldVectorShuffleWithConstants() {
return nullptr;
}
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* element_type = c1->type()->AsVector()->element_type();
@ -100,11 +100,11 @@ ConstantFoldingRule FoldVectorShuffleWithConstants() {
for (uint32_t i = 2; i < inst->NumInOperands(); ++i) {
uint32_t index = inst->GetSingleWordInOperand(i);
if (index < c1_components.size()) {
ir::Instruction* member_inst =
opt::Instruction* member_inst =
const_mgr->GetDefiningInstruction(c1_components[index]);
ids.push_back(member_inst->result_id());
} else {
ir::Instruction* member_inst = const_mgr->GetDefiningInstruction(
opt::Instruction* member_inst = const_mgr->GetDefiningInstruction(
c2_components[index - c1_components.size()]);
ids.push_back(member_inst->result_id());
}
@ -116,11 +116,11 @@ ConstantFoldingRule FoldVectorShuffleWithConstants() {
}
ConstantFoldingRule FoldVectorTimesScalar() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
assert(inst->opcode() == SpvOpVectorTimesScalar);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
@ -194,10 +194,10 @@ ConstantFoldingRule FoldVectorTimesScalar() {
ConstantFoldingRule FoldCompositeWithConstants() {
// Folds an OpCompositeConstruct where all of the inputs are constants to a
// constant. A new constant is created if necessary.
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* new_type = type_mgr->GetType(inst->type_id());
@ -238,10 +238,10 @@ using BinaryScalarFoldingRule = std::function<const analysis::Constant*(
// not |nullptr|, then their type is either |Float| or |Integer| or a |Vector|
// whose element type is |Float| or |Integer|.
ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) {
return [scalar_rule](ir::Instruction* inst,
return [scalar_rule](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
@ -288,10 +288,10 @@ ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) {
// that |constants| contains 2 entries. If they are not |nullptr|, then their
// type is either |Float| or a |Vector| whose element type is |Float|.
ConstantFoldingRule FoldFPBinaryOp(BinaryScalarFoldingRule scalar_rule) {
return [scalar_rule](ir::Instruction* inst,
return [scalar_rule](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* result_type = type_mgr->GetType(inst->type_id());
@ -518,10 +518,10 @@ ConstantFoldingRule FoldFUnordGreaterThanEqual() {
// Folds an OpDot where all of the inputs are constants to a
// constant. A new constant is created if necessary.
ConstantFoldingRule FoldOpDotWithConstants() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* new_type = type_mgr->GetType(inst->type_id());
@ -614,10 +614,10 @@ UnaryScalarFoldingRule FoldFNegateOp() {
ConstantFoldingRule FoldFNegate() { return FoldFPUnaryOp(FoldFNegateOp()); }
ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
return [cmp_opcode](ir::Instruction* inst,
return [cmp_opcode](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)
-> const analysis::Constant* {
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
@ -627,7 +627,7 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) {
uint32_t non_const_idx = (constants[0] ? 1 : 0);
uint32_t operand_id = inst->GetSingleWordInOperand(non_const_idx);
ir::Instruction* operand_inst = def_use_mgr->GetDef(operand_id);
opt::Instruction* operand_inst = def_use_mgr->GetDef(operand_id);
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* operand_type =

View File

@ -48,7 +48,7 @@ namespace opt {
// fold an instruction, the later rules will not be attempted.
using ConstantFoldingRule = std::function<const analysis::Constant*(
ir::Instruction* inst,
opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)>;
class ConstantFoldingRules {

View File

@ -102,7 +102,7 @@ int64_t Constant::GetS64() const {
}
}
ConstantManager::ConstantManager(ir::IRContext* ctx) : ctx_(ctx) {
ConstantManager::ConstantManager(opt::IRContext* ctx) : ctx_(ctx) {
// Populate the constant table with values from constant declarations in the
// module. The values of each OpConstant declaration is the identity
// assignment (i.e., each constant is its own value).
@ -111,15 +111,15 @@ ConstantManager::ConstantManager(ir::IRContext* ctx) : ctx_(ctx) {
}
}
Type* ConstantManager::GetType(const ir::Instruction* inst) const {
Type* ConstantManager::GetType(const opt::Instruction* inst) const {
return context()->get_type_mgr()->GetType(inst->type_id());
}
std::vector<const Constant*> ConstantManager::GetOperandConstants(
ir::Instruction* inst) const {
opt::Instruction* inst) const {
std::vector<const Constant*> constants;
for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
const ir::Operand* operand = &inst->GetInOperand(i);
const opt::Operand* operand = &inst->GetInOperand(i);
if (operand->type != SPV_OPERAND_TYPE_ID) {
constants.push_back(nullptr);
} else {
@ -144,8 +144,8 @@ std::vector<const Constant*> ConstantManager::GetConstantsFromIds(
return constants;
}
ir::Instruction* ConstantManager::BuildInstructionAndAddToModule(
const Constant* new_const, ir::Module::inst_iterator* pos,
opt::Instruction* ConstantManager::BuildInstructionAndAddToModule(
const Constant* new_const, opt::Module::inst_iterator* pos,
uint32_t type_id) {
uint32_t new_id = context()->TakeNextId();
auto new_inst = CreateInstruction(new_id, new_const, type_id);
@ -160,8 +160,8 @@ ir::Instruction* ConstantManager::BuildInstructionAndAddToModule(
return new_inst_ptr;
}
ir::Instruction* ConstantManager::GetDefiningInstruction(
const Constant* c, uint32_t type_id, ir::Module::inst_iterator* pos) {
opt::Instruction* ConstantManager::GetDefiningInstruction(
const Constant* c, uint32_t type_id, opt::Module::inst_iterator* pos) {
assert(type_id == 0 ||
context()->get_type_mgr()->GetType(type_id) == c->type());
uint32_t decl_id = FindDeclaredConstant(c);
@ -231,7 +231,7 @@ const Constant* ConstantManager::CreateConstant(
}
}
const Constant* ConstantManager::GetConstantFromInst(ir::Instruction* inst) {
const Constant* ConstantManager::GetConstantFromInst(opt::Instruction* inst) {
std::vector<uint32_t> literal_words_or_ids;
// Collect the constant defining literals or component ids.
@ -262,29 +262,29 @@ const Constant* ConstantManager::GetConstantFromInst(ir::Instruction* inst) {
return GetConstant(GetType(inst), literal_words_or_ids);
}
std::unique_ptr<ir::Instruction> ConstantManager::CreateInstruction(
std::unique_ptr<opt::Instruction> ConstantManager::CreateInstruction(
uint32_t id, const Constant* c, uint32_t type_id) const {
uint32_t type =
(type_id == 0) ? context()->get_type_mgr()->GetId(c->type()) : type_id;
if (c->AsNullConstant()) {
return MakeUnique<ir::Instruction>(context(), SpvOp::SpvOpConstantNull,
type, id,
std::initializer_list<ir::Operand>{});
return MakeUnique<opt::Instruction>(context(), SpvOp::SpvOpConstantNull,
type, id,
std::initializer_list<opt::Operand>{});
} else if (const BoolConstant* bc = c->AsBoolConstant()) {
return MakeUnique<ir::Instruction>(
return MakeUnique<opt::Instruction>(
context(),
bc->value() ? SpvOp::SpvOpConstantTrue : SpvOp::SpvOpConstantFalse,
type, id, std::initializer_list<ir::Operand>{});
type, id, std::initializer_list<opt::Operand>{});
} else if (const IntConstant* ic = c->AsIntConstant()) {
return MakeUnique<ir::Instruction>(
return MakeUnique<opt::Instruction>(
context(), SpvOp::SpvOpConstant, type, id,
std::initializer_list<ir::Operand>{ir::Operand(
std::initializer_list<opt::Operand>{opt::Operand(
spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
ic->words())});
} else if (const FloatConstant* fc = c->AsFloatConstant()) {
return MakeUnique<ir::Instruction>(
return MakeUnique<opt::Instruction>(
context(), SpvOp::SpvOpConstant, type, id,
std::initializer_list<ir::Operand>{ir::Operand(
std::initializer_list<opt::Operand>{opt::Operand(
spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
fc->words())});
} else if (const CompositeConstant* cc = c->AsCompositeConstant()) {
@ -294,9 +294,9 @@ std::unique_ptr<ir::Instruction> ConstantManager::CreateInstruction(
}
}
std::unique_ptr<ir::Instruction> ConstantManager::CreateCompositeInstruction(
std::unique_ptr<opt::Instruction> ConstantManager::CreateCompositeInstruction(
uint32_t result_id, const CompositeConstant* cc, uint32_t type_id) const {
std::vector<ir::Operand> operands;
std::vector<opt::Operand> operands;
for (const Constant* component_const : cc->GetComponents()) {
uint32_t id = FindDeclaredConstant(component_const);
if (id == 0) {
@ -310,8 +310,8 @@ std::unique_ptr<ir::Instruction> ConstantManager::CreateCompositeInstruction(
}
uint32_t type =
(type_id == 0) ? context()->get_type_mgr()->GetId(cc->type()) : type_id;
return MakeUnique<ir::Instruction>(context(), SpvOp::SpvOpConstantComposite,
type, result_id, std::move(operands));
return MakeUnique<opt::Instruction>(context(), SpvOp::SpvOpConstantComposite,
type, result_id, std::move(operands));
}
const Constant* ConstantManager::GetConstant(

View File

@ -490,9 +490,9 @@ struct ConstantEqual {
// This class represents a pool of constants.
class ConstantManager {
public:
ConstantManager(ir::IRContext* ctx);
ConstantManager(opt::IRContext* ctx);
ir::IRContext* context() const { return ctx_; }
opt::IRContext* context() const { return ctx_; }
// Gets or creates a unique Constant instance of type |type| and a vector of
// constant defining words |words|. If a Constant instance existed already in
@ -511,7 +511,7 @@ class ConstantManager {
// Gets or creates a Constant instance to hold the constant value of the given
// instruction. It returns a pointer to a Constant instance or nullptr if it
// could not create the constant.
const Constant* GetConstantFromInst(ir::Instruction* inst);
const Constant* GetConstantFromInst(opt::Instruction* inst);
// Gets or creates a constant defining instruction for the given Constant |c|.
// If |c| had already been defined, it returns a pointer to the existing
@ -527,9 +527,9 @@ class ConstantManager {
//
// When |type_id| is not zero, the type of |c| must be the type returned by
// type manager when given |type_id|.
ir::Instruction* GetDefiningInstruction(
opt::Instruction* GetDefiningInstruction(
const Constant* c, uint32_t type_id = 0,
ir::Module::inst_iterator* pos = nullptr);
opt::Module::inst_iterator* pos = nullptr);
// Creates a constant defining instruction for the given Constant instance
// and inserts the instruction at the position specified by the given
@ -543,12 +543,12 @@ class ConstantManager {
// |type_id| is specified, it is used as the type of the constant. Otherwise
// the type of the constant is derived by getting an id from the type manager
// for |c|.
ir::Instruction* BuildInstructionAndAddToModule(
const Constant* c, ir::Module::inst_iterator* pos, uint32_t type_id = 0);
opt::Instruction* BuildInstructionAndAddToModule(
const Constant* c, opt::Module::inst_iterator* pos, uint32_t type_id = 0);
// A helper function to get the result type of the given instruction. Returns
// nullptr if the instruction does not have a type id (type id is 0).
Type* GetType(const ir::Instruction* inst) const;
Type* GetType(const opt::Instruction* inst) const;
// A helper function to get the collected normal constant with the given id.
// Returns the pointer to the Constant instance in case it is found.
@ -591,12 +591,13 @@ class ConstantManager {
// Returns a vector of constants representing each in operand. If an operand
// is not constant its entry is nullptr.
std::vector<const Constant*> GetOperandConstants(ir::Instruction* inst) const;
std::vector<const Constant*> GetOperandConstants(
opt::Instruction* inst) const;
// Records a mapping between |inst| and the constant value generated by it.
// It returns true if a new Constant was successfully mapped, false if |inst|
// generates no constant values.
bool MapInst(ir::Instruction* inst) {
bool MapInst(opt::Instruction* inst) {
if (auto cst = GetConstantFromInst(inst)) {
MapConstantToInst(cst, inst);
return true;
@ -614,7 +615,7 @@ class ConstantManager {
// Records a new mapping between |inst| and |const_value|. This updates the
// two mappings |id_to_const_val_| and |const_val_to_id_|.
void MapConstantToInst(const Constant* const_value, ir::Instruction* inst) {
void MapConstantToInst(const Constant* const_value, opt::Instruction* inst) {
const_val_to_id_[const_value] = inst->result_id();
id_to_const_val_[inst->result_id()] = const_value;
}
@ -645,7 +646,7 @@ class ConstantManager {
// |type_id| is specified, it is used as the type of the constant. Otherwise
// the type of the constant is derived by getting an id from the type manager
// for |c|.
std::unique_ptr<ir::Instruction> CreateInstruction(
std::unique_ptr<opt::Instruction> CreateInstruction(
uint32_t result_id, const Constant* c, uint32_t type_id = 0) const;
// Creates an OpConstantComposite instruction with the given result id and
@ -657,12 +658,12 @@ class ConstantManager {
// |type_id| is specified, it is used as the type of the constant. Otherwise
// the type of the constant is derived by getting an id from the type manager
// for |c|.
std::unique_ptr<ir::Instruction> CreateCompositeInstruction(
std::unique_ptr<opt::Instruction> CreateCompositeInstruction(
uint32_t result_id, const CompositeConstant* cc,
uint32_t type_id = 0) const;
// IR context that owns this constant manager.
ir::IRContext* ctx_;
opt::IRContext* ctx_;
// A mapping from the result ids of Normal Constants to their
// Constant instances. All Normal Constants in the module, either

View File

@ -25,12 +25,12 @@ const uint32_t kCompositeExtractObjectInOperand = 0;
namespace spvtools {
namespace opt {
Pass::Status CopyPropagateArrays::Process(ir::IRContext* ctx) {
Pass::Status CopyPropagateArrays::Process(opt::IRContext* ctx) {
InitializeProcessing(ctx);
bool modified = false;
for (ir::Function& function : *get_module()) {
ir::BasicBlock* entry_bb = &*function.begin();
for (opt::Function& function : *get_module()) {
opt::BasicBlock* entry_bb = &*function.begin();
for (auto var_inst = entry_bb->begin(); var_inst->opcode() == SpvOpVariable;
++var_inst) {
@ -39,7 +39,7 @@ Pass::Status CopyPropagateArrays::Process(ir::IRContext* ctx) {
}
// Find the only store to the entire memory location, if it exists.
ir::Instruction* store_inst = FindStoreInstruction(&*var_inst);
opt::Instruction* store_inst = FindStoreInstruction(&*var_inst);
if (!store_inst) {
continue;
@ -60,8 +60,8 @@ Pass::Status CopyPropagateArrays::Process(ir::IRContext* ctx) {
}
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::FindSourceObjectIfPossible(ir::Instruction* var_inst,
ir::Instruction* store_inst) {
CopyPropagateArrays::FindSourceObjectIfPossible(opt::Instruction* var_inst,
opt::Instruction* store_inst) {
assert(var_inst->opcode() == SpvOpVariable && "Expecting a variable.");
// Check that the variable is a composite object where |store_inst|
@ -95,11 +95,11 @@ CopyPropagateArrays::FindSourceObjectIfPossible(ir::Instruction* var_inst,
return source;
}
ir::Instruction* CopyPropagateArrays::FindStoreInstruction(
const ir::Instruction* var_inst) const {
ir::Instruction* store_inst = nullptr;
opt::Instruction* CopyPropagateArrays::FindStoreInstruction(
const opt::Instruction* var_inst) const {
opt::Instruction* store_inst = nullptr;
get_def_use_mgr()->WhileEachUser(
var_inst, [&store_inst, var_inst](ir::Instruction* use) {
var_inst, [&store_inst, var_inst](opt::Instruction* use) {
if (use->opcode() == SpvOpStore &&
use->GetSingleWordInOperand(kStorePointerInOperand) ==
var_inst->result_id()) {
@ -115,24 +115,24 @@ ir::Instruction* CopyPropagateArrays::FindStoreInstruction(
return store_inst;
}
void CopyPropagateArrays::PropagateObject(ir::Instruction* var_inst,
void CopyPropagateArrays::PropagateObject(opt::Instruction* var_inst,
MemoryObject* source,
ir::Instruction* insertion_point) {
opt::Instruction* insertion_point) {
assert(var_inst->opcode() == SpvOpVariable &&
"This function propagates variables.");
ir::Instruction* new_access_chain =
opt::Instruction* new_access_chain =
BuildNewAccessChain(insertion_point, source);
context()->KillNamesAndDecorates(var_inst);
UpdateUses(var_inst, new_access_chain);
}
ir::Instruction* CopyPropagateArrays::BuildNewAccessChain(
ir::Instruction* insertion_point,
opt::Instruction* CopyPropagateArrays::BuildNewAccessChain(
opt::Instruction* insertion_point,
CopyPropagateArrays::MemoryObject* source) const {
InstructionBuilder builder(context(), insertion_point,
ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping);
opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping);
if (source->AccessChain().size() == 0) {
return source->GetVariable();
@ -143,9 +143,9 @@ ir::Instruction* CopyPropagateArrays::BuildNewAccessChain(
source->AccessChain());
}
bool CopyPropagateArrays::HasNoStores(ir::Instruction* ptr_inst) {
bool CopyPropagateArrays::HasNoStores(opt::Instruction* ptr_inst) {
return get_def_use_mgr()->WhileEachUser(
ptr_inst, [this](ir::Instruction* use) {
ptr_inst, [this](opt::Instruction* use) {
if (use->opcode() == SpvOpLoad) {
return true;
} else if (use->opcode() == SpvOpAccessChain) {
@ -162,15 +162,15 @@ bool CopyPropagateArrays::HasNoStores(ir::Instruction* ptr_inst) {
});
}
bool CopyPropagateArrays::HasValidReferencesOnly(ir::Instruction* ptr_inst,
ir::Instruction* store_inst) {
ir::BasicBlock* store_block = context()->get_instr_block(store_inst);
bool CopyPropagateArrays::HasValidReferencesOnly(opt::Instruction* ptr_inst,
opt::Instruction* store_inst) {
opt::BasicBlock* store_block = context()->get_instr_block(store_inst);
opt::DominatorAnalysis* dominator_analysis =
context()->GetDominatorAnalysis(store_block->GetParent());
return get_def_use_mgr()->WhileEachUser(
ptr_inst,
[this, store_inst, dominator_analysis, ptr_inst](ir::Instruction* use) {
[this, store_inst, dominator_analysis, ptr_inst](opt::Instruction* use) {
if (use->opcode() == SpvOpLoad ||
use->opcode() == SpvOpImageTexelPointer) {
// TODO: If there are many load in the same BB as |store_inst| the
@ -194,7 +194,7 @@ bool CopyPropagateArrays::HasValidReferencesOnly(ir::Instruction* ptr_inst,
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::GetSourceObjectIfAny(uint32_t result) {
ir::Instruction* result_inst = context()->get_def_use_mgr()->GetDef(result);
opt::Instruction* result_inst = context()->get_def_use_mgr()->GetDef(result);
switch (result_inst->opcode()) {
case SpvOpLoad:
@ -213,11 +213,11 @@ CopyPropagateArrays::GetSourceObjectIfAny(uint32_t result) {
}
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::BuildMemoryObjectFromLoad(ir::Instruction* load_inst) {
CopyPropagateArrays::BuildMemoryObjectFromLoad(opt::Instruction* load_inst) {
std::vector<uint32_t> components_in_reverse;
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
ir::Instruction* current_inst = def_use_mgr->GetDef(
opt::Instruction* current_inst = def_use_mgr->GetDef(
load_inst->GetSingleWordInOperand(kLoadPointerInOperand));
// Build the access chain for the memory object by collecting the indices used
@ -252,7 +252,7 @@ CopyPropagateArrays::BuildMemoryObjectFromLoad(ir::Instruction* load_inst) {
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::BuildMemoryObjectFromExtract(
ir::Instruction* extract_inst) {
opt::Instruction* extract_inst) {
assert(extract_inst->opcode() == SpvOpCompositeExtract &&
"Expecting an OpCompositeExtract instruction.");
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
@ -283,7 +283,7 @@ CopyPropagateArrays::BuildMemoryObjectFromExtract(
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct(
ir::Instruction* conststruct_inst) {
opt::Instruction* conststruct_inst) {
assert(conststruct_inst->opcode() == SpvOpCompositeConstruct &&
"Expecting an OpCompositeConstruct instruction.");
@ -347,7 +347,8 @@ CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct(
}
std::unique_ptr<CopyPropagateArrays::MemoryObject>
CopyPropagateArrays::BuildMemoryObjectFromInsert(ir::Instruction* insert_inst) {
CopyPropagateArrays::BuildMemoryObjectFromInsert(
opt::Instruction* insert_inst) {
assert(insert_inst->opcode() == SpvOpCompositeInsert &&
"Expecting an OpCompositeInsert instruction.");
@ -406,7 +407,7 @@ CopyPropagateArrays::BuildMemoryObjectFromInsert(ir::Instruction* insert_inst) {
memory_object->GetParent();
ir::Instruction* current_insert =
opt::Instruction* current_insert =
def_use_mgr->GetDef(insert_inst->GetSingleWordInOperand(1));
for (uint32_t i = number_of_elements - 1; i > 0; --i) {
if (current_insert->opcode() != SpvOpCompositeInsert) {
@ -468,7 +469,7 @@ bool CopyPropagateArrays::IsPointerToArrayType(uint32_t type_id) {
return false;
}
bool CopyPropagateArrays::CanUpdateUses(ir::Instruction* original_ptr_inst,
bool CopyPropagateArrays::CanUpdateUses(opt::Instruction* original_ptr_inst,
uint32_t type_id) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
@ -487,7 +488,7 @@ bool CopyPropagateArrays::CanUpdateUses(ir::Instruction* original_ptr_inst,
return def_use_mgr->WhileEachUse(
original_ptr_inst,
[this, type_mgr, const_mgr, type](ir::Instruction* use, uint32_t) {
[this, type_mgr, const_mgr, type](opt::Instruction* use, uint32_t) {
switch (use->opcode()) {
case SpvOpLoad: {
analysis::Pointer* pointer_type = type->AsPointer();
@ -560,8 +561,8 @@ bool CopyPropagateArrays::CanUpdateUses(ir::Instruction* original_ptr_inst,
}
});
}
void CopyPropagateArrays::UpdateUses(ir::Instruction* original_ptr_inst,
ir::Instruction* new_ptr_inst) {
void CopyPropagateArrays::UpdateUses(opt::Instruction* original_ptr_inst,
opt::Instruction* new_ptr_inst) {
// TODO (s-perron): Keep the def-use manager up to date. Not done now because
// it can cause problems for the |ForEachUse| traversals. Can be use by
// keeping a list of instructions that need updating, and then updating them
@ -571,14 +572,14 @@ void CopyPropagateArrays::UpdateUses(ir::Instruction* original_ptr_inst,
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
std::vector<std::pair<ir::Instruction*, uint32_t> > uses;
std::vector<std::pair<opt::Instruction*, uint32_t> > uses;
def_use_mgr->ForEachUse(original_ptr_inst,
[&uses](ir::Instruction* use, uint32_t index) {
[&uses](opt::Instruction* use, uint32_t index) {
uses.push_back({use, index});
});
for (auto pair : uses) {
ir::Instruction* use = pair.first;
opt::Instruction* use = pair.first;
uint32_t index = pair.second;
analysis::Pointer* pointer_type = nullptr;
switch (use->opcode()) {
@ -671,7 +672,7 @@ void CopyPropagateArrays::UpdateUses(ir::Instruction* original_ptr_inst,
// decomposing the object into the base type, which must be the same,
// and then rebuilding them.
if (index == 1) {
ir::Instruction* target_pointer = def_use_mgr->GetDef(
opt::Instruction* target_pointer = def_use_mgr->GetDef(
use->GetSingleWordInOperand(kStorePointerInOperand));
pointer_type =
type_mgr->GetType(target_pointer->type_id())->AsPointer();
@ -702,8 +703,8 @@ void CopyPropagateArrays::UpdateUses(ir::Instruction* original_ptr_inst,
}
uint32_t CopyPropagateArrays::GenerateCopy(
ir::Instruction* object_inst, uint32_t new_type_id,
ir::Instruction* insertion_position) {
opt::Instruction* object_inst, uint32_t new_type_id,
opt::Instruction* insertion_position) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
@ -714,8 +715,8 @@ uint32_t CopyPropagateArrays::GenerateCopy(
opt::InstructionBuilder ir_builder(
context(), insertion_position,
ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisDefUse);
opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisDefUse);
analysis::Type* original_type = type_mgr->GetType(original_type_id);
analysis::Type* new_type = type_mgr->GetType(new_type_id);
@ -735,7 +736,7 @@ uint32_t CopyPropagateArrays::GenerateCopy(
assert(length_const->AsIntConstant());
uint32_t array_length = length_const->AsIntConstant()->GetU32();
for (uint32_t i = 0; i < array_length; i++) {
ir::Instruction* extract = ir_builder.AddCompositeExtract(
opt::Instruction* extract = ir_builder.AddCompositeExtract(
original_element_type_id, object_inst->result_id(), {i});
element_ids.push_back(
GenerateCopy(extract, new_element_type_id, insertion_position));
@ -753,7 +754,7 @@ uint32_t CopyPropagateArrays::GenerateCopy(
new_struct_type->element_types();
std::vector<uint32_t> element_ids;
for (uint32_t i = 0; i < original_types.size(); i++) {
ir::Instruction* extract = ir_builder.AddCompositeExtract(
opt::Instruction* extract = ir_builder.AddCompositeExtract(
type_mgr->GetId(original_types[i]), object_inst->result_id(), {i});
element_ids.push_back(GenerateCopy(extract, type_mgr->GetId(new_types[i]),
insertion_position));
@ -777,7 +778,7 @@ void CopyPropagateArrays::MemoryObject::GetMember(
}
uint32_t CopyPropagateArrays::MemoryObject::GetNumberOfMembers() {
ir::IRContext* context = variable_inst_->context();
opt::IRContext* context = variable_inst_->context();
analysis::TypeManager* type_mgr = context->get_type_mgr();
const analysis::Type* type = type_mgr->GetType(variable_inst_->type_id());
@ -804,7 +805,7 @@ uint32_t CopyPropagateArrays::MemoryObject::GetNumberOfMembers() {
}
template <class iterator>
CopyPropagateArrays::MemoryObject::MemoryObject(ir::Instruction* var_inst,
CopyPropagateArrays::MemoryObject::MemoryObject(opt::Instruction* var_inst,
iterator begin, iterator end)
: variable_inst_(var_inst), access_chain_(begin, end) {}

View File

@ -38,15 +38,15 @@ namespace opt {
class CopyPropagateArrays : public MemPass {
public:
const char* name() const override { return "copy-propagate-arrays"; }
Status Process(ir::IRContext*) override;
Status Process(opt::IRContext*) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse | ir::IRContext::kAnalysisCFG |
ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisLoopAnalysis |
ir::IRContext::kAnalysisDecorations |
ir::IRContext::kAnalysisDominatorAnalysis |
ir::IRContext::kAnalysisNameMap;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse | opt::IRContext::kAnalysisCFG |
opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisLoopAnalysis |
opt::IRContext::kAnalysisDecorations |
opt::IRContext::kAnalysisDominatorAnalysis |
opt::IRContext::kAnalysisNameMap;
}
private:
@ -62,7 +62,7 @@ class CopyPropagateArrays : public MemPass {
// are interpreted the same way they would be in an |OpAccessChain|
// instruction.
template <class iterator>
MemoryObject(ir::Instruction* var_inst, iterator begin, iterator end);
MemoryObject(opt::Instruction* var_inst, iterator begin, iterator end);
// Change |this| to now point to the member identified by |access_chain|
// (starting from the current member). The elements in |access_chain| are
@ -87,7 +87,7 @@ class CopyPropagateArrays : public MemPass {
uint32_t GetNumberOfMembers();
// Returns the owning variable that the memory object is contained in.
ir::Instruction* GetVariable() const { return variable_inst_; }
opt::Instruction* GetVariable() const { return variable_inst_; }
// Returns a vector of integers that can be used to access the specific
// member that |this| represents starting from the owning variable. These
@ -127,7 +127,7 @@ class CopyPropagateArrays : public MemPass {
private:
// The variable that owns this memory object.
ir::Instruction* variable_inst_;
opt::Instruction* variable_inst_;
// The access chain to reach the particular member the memory object
// represents. It should be interpreted the same way the indices in an
@ -142,18 +142,18 @@ class CopyPropagateArrays : public MemPass {
// and only identifies very simple cases. If no such memory object can be
// found, the return value is |nullptr|.
std::unique_ptr<CopyPropagateArrays::MemoryObject> FindSourceObjectIfPossible(
ir::Instruction* var_inst, ir::Instruction* store_inst);
opt::Instruction* var_inst, opt::Instruction* store_inst);
// Replaces all loads of |var_inst| with a load from |source| instead.
// |insertion_pos| is a position where it is possible to construct the
// address of |source| and also dominates all of the loads of |var_inst|.
void PropagateObject(ir::Instruction* var_inst, MemoryObject* source,
ir::Instruction* insertion_pos);
void PropagateObject(opt::Instruction* var_inst, MemoryObject* source,
opt::Instruction* insertion_pos);
// Returns true if all of the references to |ptr_inst| can be rewritten and
// are dominated by |store_inst|.
bool HasValidReferencesOnly(ir::Instruction* ptr_inst,
ir::Instruction* store_inst);
bool HasValidReferencesOnly(opt::Instruction* ptr_inst,
opt::Instruction* store_inst);
// Returns a memory object that at one time was equivalent to the value in
// |result|. If no such memory object exists, the return value is |nullptr|.
@ -163,21 +163,21 @@ class CopyPropagateArrays : public MemPass {
// object cannot be identified, the return value is |nullptr|. The opcode of
// |load_inst| must be |OpLoad|.
std::unique_ptr<MemoryObject> BuildMemoryObjectFromLoad(
ir::Instruction* load_inst);
opt::Instruction* load_inst);
// Returns the memory object that at some point was equivalent to the result
// of |extract_inst|. If a memory object cannot be identified, the return
// value is |nullptr|. The opcode of |extract_inst| must be
// |OpCompositeExtract|.
std::unique_ptr<MemoryObject> BuildMemoryObjectFromExtract(
ir::Instruction* extract_inst);
opt::Instruction* extract_inst);
// Returns the memory object that at some point was equivalent to the result
// of |construct_inst|. If a memory object cannot be identified, the return
// value is |nullptr|. The opcode of |constuct_inst| must be
// |OpCompositeConstruct|.
std::unique_ptr<MemoryObject> BuildMemoryObjectFromCompositeConstruct(
ir::Instruction* conststruct_inst);
opt::Instruction* conststruct_inst);
// Returns the memory object that at some point was equivalent to the result
// of |insert_inst|. If a memory object cannot be identified, the return
@ -186,43 +186,44 @@ class CopyPropagateArrays : public MemPass {
// |OpCompositeInsert| instructions that insert the elements one at a time in
// order from beginning to end.
std::unique_ptr<MemoryObject> BuildMemoryObjectFromInsert(
ir::Instruction* insert_inst);
opt::Instruction* insert_inst);
// Return true if |type_id| is a pointer type whose pointee type is an array.
bool IsPointerToArrayType(uint32_t type_id);
// Returns true of there are not stores using |ptr_inst| or something derived
// from it.
bool HasNoStores(ir::Instruction* ptr_inst);
bool HasNoStores(opt::Instruction* ptr_inst);
// Creates an |OpAccessChain| instruction whose result is a pointer the memory
// represented by |source|. The new instruction will be placed before
// |insertion_point|. |insertion_point| must be part of a function. Returns
// the new instruction.
ir::Instruction* BuildNewAccessChain(ir::Instruction* insertion_point,
MemoryObject* source) const;
opt::Instruction* BuildNewAccessChain(opt::Instruction* insertion_point,
MemoryObject* source) const;
// Rewrites all uses of |original_ptr| to use |new_pointer_inst| updating
// types of other instructions as needed. This function should not be called
// if |CanUpdateUses(original_ptr_inst, new_pointer_inst->type_id())| returns
// false.
void UpdateUses(ir::Instruction* original_ptr_inst,
ir::Instruction* new_pointer_inst);
void UpdateUses(opt::Instruction* original_ptr_inst,
opt::Instruction* new_pointer_inst);
// Return true if |UpdateUses| is able to change all of the uses of
// |original_ptr_inst| to |type_id| and still have valid code.
bool CanUpdateUses(ir::Instruction* original_ptr_inst, uint32_t type_id);
bool CanUpdateUses(opt::Instruction* original_ptr_inst, uint32_t type_id);
// Returns the id whose value is the same as |object_to_copy| except its type
// is |new_type_id|. Any instructions need to generate this value will be
// inserted before |insertion_position|.
uint32_t GenerateCopy(ir::Instruction* object_to_copy, uint32_t new_type_id,
ir::Instruction* insertion_position);
uint32_t GenerateCopy(opt::Instruction* object_to_copy, uint32_t new_type_id,
opt::Instruction* insertion_position);
// Returns a store to |var_inst| that writes to the entire variable, and is
// the only store that does so. Note it does not look through OpAccessChain
// instruction, so partial stores are not considered.
ir::Instruction* FindStoreInstruction(const ir::Instruction* var_inst) const;
opt::Instruction* FindStoreInstruction(
const opt::Instruction* var_inst) const;
};
} // namespace opt

View File

@ -34,7 +34,7 @@ const uint32_t kBranchCondFalseLabIdInIdx = 2;
bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) {
bool condIsConst;
ir::Instruction* cInst = get_def_use_mgr()->GetDef(condId);
opt::Instruction* cInst = get_def_use_mgr()->GetDef(condId);
switch (cInst->opcode()) {
case SpvOpConstantFalse: {
*condVal = false;
@ -56,9 +56,9 @@ bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) {
}
bool DeadBranchElimPass::GetConstInteger(uint32_t selId, uint32_t* selVal) {
ir::Instruction* sInst = get_def_use_mgr()->GetDef(selId);
opt::Instruction* sInst = get_def_use_mgr()->GetDef(selId);
uint32_t typeId = sInst->type_id();
ir::Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
opt::Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
if (!typeInst || (typeInst->opcode() != SpvOpTypeInt)) return false;
// TODO(greg-lunarg): Support non-32 bit ints
if (typeInst->GetSingleWordInOperand(0) != 32) return false;
@ -72,9 +72,9 @@ bool DeadBranchElimPass::GetConstInteger(uint32_t selId, uint32_t* selVal) {
return false;
}
void DeadBranchElimPass::AddBranch(uint32_t labelId, ir::BasicBlock* bp) {
void DeadBranchElimPass::AddBranch(uint32_t labelId, opt::BasicBlock* bp) {
assert(get_def_use_mgr()->GetDef(labelId) != nullptr);
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
std::unique_ptr<opt::Instruction> newBranch(new opt::Instruction(
context(), SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
context()->AnalyzeDefUse(&*newBranch);
@ -82,18 +82,18 @@ void DeadBranchElimPass::AddBranch(uint32_t labelId, ir::BasicBlock* bp) {
bp->AddInstruction(std::move(newBranch));
}
ir::BasicBlock* DeadBranchElimPass::GetParentBlock(uint32_t id) {
opt::BasicBlock* DeadBranchElimPass::GetParentBlock(uint32_t id) {
return context()->get_instr_block(get_def_use_mgr()->GetDef(id));
}
bool DeadBranchElimPass::MarkLiveBlocks(
ir::Function* func, std::unordered_set<ir::BasicBlock*>* live_blocks) {
std::unordered_set<ir::BasicBlock*> continues;
std::vector<ir::BasicBlock*> stack;
opt::Function* func, std::unordered_set<opt::BasicBlock*>* live_blocks) {
std::unordered_set<opt::BasicBlock*> continues;
std::vector<opt::BasicBlock*> stack;
stack.push_back(&*func->begin());
bool modified = false;
while (!stack.empty()) {
ir::BasicBlock* block = stack.back();
opt::BasicBlock* block = stack.back();
stack.pop_back();
// Live blocks doubles as visited set.
@ -102,7 +102,7 @@ bool DeadBranchElimPass::MarkLiveBlocks(
uint32_t cont_id = block->ContinueBlockIdIfAny();
if (cont_id != 0) continues.insert(GetParentBlock(cont_id));
ir::Instruction* terminator = block->terminator();
opt::Instruction* terminator = block->terminator();
uint32_t live_lab_id = 0;
// Check if the terminator has a single valid successor.
if (terminator->opcode() == SpvOpBranchConditional) {
@ -153,7 +153,7 @@ bool DeadBranchElimPass::MarkLiveBlocks(
// Remove the merge instruction if it is a selection merge.
AddBranch(live_lab_id, block);
context()->KillInst(terminator);
ir::Instruction* mergeInst = block->GetMergeInst();
opt::Instruction* mergeInst = block->GetMergeInst();
if (mergeInst && mergeInst->opcode() == SpvOpSelectionMerge) {
context()->KillInst(mergeInst);
}
@ -171,18 +171,18 @@ bool DeadBranchElimPass::MarkLiveBlocks(
}
void DeadBranchElimPass::MarkUnreachableStructuredTargets(
const std::unordered_set<ir::BasicBlock*>& live_blocks,
std::unordered_set<ir::BasicBlock*>* unreachable_merges,
std::unordered_map<ir::BasicBlock*, ir::BasicBlock*>*
const std::unordered_set<opt::BasicBlock*>& live_blocks,
std::unordered_set<opt::BasicBlock*>* unreachable_merges,
std::unordered_map<opt::BasicBlock*, opt::BasicBlock*>*
unreachable_continues) {
for (auto block : live_blocks) {
if (auto merge_id = block->MergeBlockIdIfAny()) {
ir::BasicBlock* merge_block = GetParentBlock(merge_id);
opt::BasicBlock* merge_block = GetParentBlock(merge_id);
if (!live_blocks.count(merge_block)) {
unreachable_merges->insert(merge_block);
}
if (auto cont_id = block->ContinueBlockIdIfAny()) {
ir::BasicBlock* cont_block = GetParentBlock(cont_id);
opt::BasicBlock* cont_block = GetParentBlock(cont_id);
if (!live_blocks.count(cont_block)) {
(*unreachable_continues)[cont_block] = block;
}
@ -192,8 +192,9 @@ void DeadBranchElimPass::MarkUnreachableStructuredTargets(
}
bool DeadBranchElimPass::FixPhiNodesInLiveBlocks(
ir::Function* func, const std::unordered_set<ir::BasicBlock*>& live_blocks,
const std::unordered_map<ir::BasicBlock*, ir::BasicBlock*>&
opt::Function* func,
const std::unordered_set<opt::BasicBlock*>& live_blocks,
const std::unordered_map<opt::BasicBlock*, opt::BasicBlock*>&
unreachable_continues) {
bool modified = false;
for (auto& block : *func) {
@ -205,8 +206,8 @@ bool DeadBranchElimPass::FixPhiNodesInLiveBlocks(
bool changed = false;
bool backedge_added = false;
ir::Instruction* inst = &*iter;
std::vector<ir::Operand> operands;
opt::Instruction* inst = &*iter;
std::vector<opt::Operand> operands;
// Build a complete set of operands (not just input operands). Start
// with type and result id operands.
operands.push_back(inst->GetOperand(0u));
@ -219,7 +220,8 @@ bool DeadBranchElimPass::FixPhiNodesInLiveBlocks(
// However, if there is only one other incoming edge, the OpPhi can be
// eliminated.
for (uint32_t i = 1; i < inst->NumInOperands(); i += 2) {
ir::BasicBlock* inc = GetParentBlock(inst->GetSingleWordInOperand(i));
opt::BasicBlock* inc =
GetParentBlock(inst->GetSingleWordInOperand(i));
auto cont_iter = unreachable_continues.find(inc);
if (cont_iter != unreachable_continues.end() &&
cont_iter->second == &block && inst->NumInOperands() > 4) {
@ -302,9 +304,10 @@ bool DeadBranchElimPass::FixPhiNodesInLiveBlocks(
}
bool DeadBranchElimPass::EraseDeadBlocks(
ir::Function* func, const std::unordered_set<ir::BasicBlock*>& live_blocks,
const std::unordered_set<ir::BasicBlock*>& unreachable_merges,
const std::unordered_map<ir::BasicBlock*, ir::BasicBlock*>&
opt::Function* func,
const std::unordered_set<opt::BasicBlock*>& live_blocks,
const std::unordered_set<opt::BasicBlock*>& unreachable_merges,
const std::unordered_map<opt::BasicBlock*, opt::BasicBlock*>&
unreachable_continues) {
bool modified = false;
for (auto ebi = func->begin(); ebi != func->end();) {
@ -314,9 +317,9 @@ bool DeadBranchElimPass::EraseDeadBlocks(
// Make unreachable, but leave the label.
KillAllInsts(&*ebi, false);
// Add unreachable terminator.
ebi->AddInstruction(
MakeUnique<ir::Instruction>(context(), SpvOpUnreachable, 0, 0,
std::initializer_list<ir::Operand>{}));
ebi->AddInstruction(MakeUnique<opt::Instruction>(
context(), SpvOpUnreachable, 0, 0,
std::initializer_list<opt::Operand>{}));
context()->set_instr_block(&*ebi->tail(), &*ebi);
modified = true;
}
@ -330,10 +333,10 @@ bool DeadBranchElimPass::EraseDeadBlocks(
KillAllInsts(&*ebi, false);
// Add unconditional branch to header.
assert(unreachable_continues.count(&*ebi));
ebi->AddInstruction(
MakeUnique<ir::Instruction>(context(), SpvOpBranch, 0, 0,
std::initializer_list<ir::Operand>{
{SPV_OPERAND_TYPE_ID, {cont_id}}}));
ebi->AddInstruction(MakeUnique<opt::Instruction>(
context(), SpvOpBranch, 0, 0,
std::initializer_list<opt::Operand>{
{SPV_OPERAND_TYPE_ID, {cont_id}}}));
get_def_use_mgr()->AnalyzeInstUse(&*ebi->tail());
context()->set_instr_block(&*ebi->tail(), &*ebi);
modified = true;
@ -352,13 +355,13 @@ bool DeadBranchElimPass::EraseDeadBlocks(
return modified;
}
bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
bool DeadBranchElimPass::EliminateDeadBranches(opt::Function* func) {
bool modified = false;
std::unordered_set<ir::BasicBlock*> live_blocks;
std::unordered_set<opt::BasicBlock*> live_blocks;
modified |= MarkLiveBlocks(func, &live_blocks);
std::unordered_set<ir::BasicBlock*> unreachable_merges;
std::unordered_map<ir::BasicBlock*, ir::BasicBlock*> unreachable_continues;
std::unordered_set<opt::BasicBlock*> unreachable_merges;
std::unordered_map<opt::BasicBlock*, opt::BasicBlock*> unreachable_continues;
MarkUnreachableStructuredTargets(live_blocks, &unreachable_merges,
&unreachable_continues);
modified |= FixPhiNodesInLiveBlocks(func, live_blocks, unreachable_continues);
@ -368,7 +371,7 @@ bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
return modified;
}
void DeadBranchElimPass::Initialize(ir::IRContext* c) {
void DeadBranchElimPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
}
@ -379,7 +382,7 @@ Pass::Status DeadBranchElimPass::ProcessImpl() {
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// Process all entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return EliminateDeadBranches(fp);
};
bool modified = ProcessReachableCallTree(pfn, context());
@ -388,7 +391,7 @@ Pass::Status DeadBranchElimPass::ProcessImpl() {
DeadBranchElimPass::DeadBranchElimPass() {}
Pass::Status DeadBranchElimPass::Process(ir::IRContext* module) {
Pass::Status DeadBranchElimPass::Process(opt::IRContext* module) {
Initialize(module);
return ProcessImpl();
}

View File

@ -34,16 +34,16 @@ namespace opt {
// See optimizer.hpp for documentation.
class DeadBranchElimPass : public MemPass {
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const opt::BasicBlock*;
public:
DeadBranchElimPass();
const char* name() const override { return "eliminate-dead-branches"; }
Status Process(ir::IRContext* context) override;
Status Process(opt::IRContext* context) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping;
}
private:
@ -56,7 +56,7 @@ class DeadBranchElimPass : public MemPass {
bool GetConstInteger(uint32_t valId, uint32_t* value);
// Add branch to |labelId| to end of block |bp|.
void AddBranch(uint32_t labelId, ir::BasicBlock* bp);
void AddBranch(uint32_t labelId, opt::BasicBlock* bp);
// For function |func|, look for BranchConditionals with constant condition
// and convert to a Branch to the indicated label. Delete resulting dead
@ -64,21 +64,21 @@ class DeadBranchElimPass : public MemPass {
// invalid control flow.
// TODO(greg-lunarg): Remove remaining constant conditional branches and dead
// blocks.
bool EliminateDeadBranches(ir::Function* func);
bool EliminateDeadBranches(opt::Function* func);
// Returns the basic block containing |id|.
// Note: this pass only requires correct instruction block mappings for the
// input. This pass does not preserve the block mapping, so it is not kept
// up-to-date during processing.
ir::BasicBlock* GetParentBlock(uint32_t id);
opt::BasicBlock* GetParentBlock(uint32_t id);
// Marks live blocks reachable from the entry of |func|. Simplifies constant
// branches and switches as it proceeds, to limit the number of live blocks.
// It is careful not to eliminate backedges even if they are dead, but the
// header is live. Likewise, unreachable merge blocks named in live merge
// instruction must be retained (though they may be clobbered).
bool MarkLiveBlocks(ir::Function* func,
std::unordered_set<ir::BasicBlock*>* live_blocks);
bool MarkLiveBlocks(opt::Function* func,
std::unordered_set<opt::BasicBlock*>* live_blocks);
// Checks for unreachable merge and continue blocks with live headers; those
// blocks must be retained. Continues are tracked separately so that a live
@ -88,9 +88,9 @@ class DeadBranchElimPass : public MemPass {
// |unreachable_continues| maps the id of an unreachable continue target to
// the header block that declares it.
void MarkUnreachableStructuredTargets(
const std::unordered_set<ir::BasicBlock*>& live_blocks,
std::unordered_set<ir::BasicBlock*>* unreachable_merges,
std::unordered_map<ir::BasicBlock*, ir::BasicBlock*>*
const std::unordered_set<opt::BasicBlock*>& live_blocks,
std::unordered_set<opt::BasicBlock*>* unreachable_merges,
std::unordered_map<opt::BasicBlock*, opt::BasicBlock*>*
unreachable_continues);
// Fix phis in reachable blocks so that only live (or unremovable) incoming
@ -106,9 +106,9 @@ class DeadBranchElimPass : public MemPass {
// |unreachable_continues| maps continue targets that cannot be reached to
// merge instruction that declares them.
bool FixPhiNodesInLiveBlocks(
ir::Function* func,
const std::unordered_set<ir::BasicBlock*>& live_blocks,
const std::unordered_map<ir::BasicBlock*, ir::BasicBlock*>&
opt::Function* func,
const std::unordered_set<opt::BasicBlock*>& live_blocks,
const std::unordered_map<opt::BasicBlock*, opt::BasicBlock*>&
unreachable_continues);
// Erases dead blocks. Any block captured in |unreachable_merges| or
@ -123,13 +123,13 @@ class DeadBranchElimPass : public MemPass {
// |unreachable_continues| maps continue targets that cannot be reached to
// corresponding header block that declares them.
bool EraseDeadBlocks(
ir::Function* func,
const std::unordered_set<ir::BasicBlock*>& live_blocks,
const std::unordered_set<ir::BasicBlock*>& unreachable_merges,
const std::unordered_map<ir::BasicBlock*, ir::BasicBlock*>&
opt::Function* func,
const std::unordered_set<opt::BasicBlock*>& live_blocks,
const std::unordered_set<opt::BasicBlock*>& unreachable_merges,
const std::unordered_map<opt::BasicBlock*, opt::BasicBlock*>&
unreachable_continues);
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
};

View File

@ -38,7 +38,7 @@ const uint32_t kInsertCompositeIdInIdx = 1;
} // anonymous namespace
uint32_t DeadInsertElimPass::NumComponents(ir::Instruction* typeInst) {
uint32_t DeadInsertElimPass::NumComponents(opt::Instruction* typeInst) {
switch (typeInst->opcode()) {
case SpvOpTypeVector: {
return typeInst->GetSingleWordInOperand(kTypeVectorCountInIdx);
@ -49,10 +49,10 @@ uint32_t DeadInsertElimPass::NumComponents(ir::Instruction* typeInst) {
case SpvOpTypeArray: {
uint32_t lenId =
typeInst->GetSingleWordInOperand(kTypeArrayLengthIdInIdx);
ir::Instruction* lenInst = get_def_use_mgr()->GetDef(lenId);
opt::Instruction* lenInst = get_def_use_mgr()->GetDef(lenId);
if (lenInst->opcode() != SpvOpConstant) return 0;
uint32_t lenTypeId = lenInst->type_id();
ir::Instruction* lenTypeInst = get_def_use_mgr()->GetDef(lenTypeId);
opt::Instruction* lenTypeInst = get_def_use_mgr()->GetDef(lenTypeId);
// TODO(greg-lunarg): Support non-32-bit array length
if (lenTypeInst->GetSingleWordInOperand(kTypeIntWidthInIdx) != 32)
return 0;
@ -66,10 +66,11 @@ uint32_t DeadInsertElimPass::NumComponents(ir::Instruction* typeInst) {
}
void DeadInsertElimPass::MarkInsertChain(
ir::Instruction* insertChain, std::vector<uint32_t>* pExtIndices,
opt::Instruction* insertChain, std::vector<uint32_t>* pExtIndices,
uint32_t extOffset, std::unordered_set<uint32_t>* visited_phis) {
// Not currently optimizing array inserts.
ir::Instruction* typeInst = get_def_use_mgr()->GetDef(insertChain->type_id());
opt::Instruction* typeInst =
get_def_use_mgr()->GetDef(insertChain->type_id());
if (typeInst->opcode() == SpvOpTypeArray) return;
// Insert chains are only composed of inserts and phis
if (insertChain->opcode() != SpvOpCompositeInsert &&
@ -90,7 +91,7 @@ void DeadInsertElimPass::MarkInsertChain(
return;
}
}
ir::Instruction* insInst = insertChain;
opt::Instruction* insInst = insertChain;
while (insInst->opcode() == SpvOpCompositeInsert) {
// If no extract indices, mark insert and inserted object (which might
// also be an insert chain) and continue up the chain though the input
@ -159,12 +160,12 @@ void DeadInsertElimPass::MarkInsertChain(
std::sort(ids.begin(), ids.end());
auto new_end = std::unique(ids.begin(), ids.end());
for (auto id_iter = ids.begin(); id_iter != new_end; ++id_iter) {
ir::Instruction* pi = get_def_use_mgr()->GetDef(*id_iter);
opt::Instruction* pi = get_def_use_mgr()->GetDef(*id_iter);
MarkInsertChain(pi, pExtIndices, extOffset, visited_phis);
}
}
bool DeadInsertElimPass::EliminateDeadInserts(ir::Function* func) {
bool DeadInsertElimPass::EliminateDeadInserts(opt::Function* func) {
bool modified = false;
bool lastmodified = true;
// Each pass can delete dead instructions, thus potentially revealing
@ -176,7 +177,7 @@ bool DeadInsertElimPass::EliminateDeadInserts(ir::Function* func) {
return modified;
}
bool DeadInsertElimPass::EliminateDeadInsertsOnePass(ir::Function* func) {
bool DeadInsertElimPass::EliminateDeadInsertsOnePass(opt::Function* func) {
bool modified = false;
liveInserts_.clear();
visitedPhis_.clear();
@ -185,7 +186,7 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(ir::Function* func) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
// Only process Inserts and composite Phis
SpvOp op = ii->opcode();
ir::Instruction* typeInst = get_def_use_mgr()->GetDef(ii->type_id());
opt::Instruction* typeInst = get_def_use_mgr()->GetDef(ii->type_id());
if (op != SpvOpCompositeInsert &&
(op != SpvOpPhi || !spvOpcodeIsComposite(typeInst->opcode())))
continue;
@ -200,7 +201,7 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(ir::Function* func) {
}
}
const uint32_t id = ii->result_id();
get_def_use_mgr()->ForEachUser(id, [&ii, this](ir::Instruction* user) {
get_def_use_mgr()->ForEachUser(id, [&ii, this](opt::Instruction* user) {
switch (user->opcode()) {
case SpvOpCompositeInsert:
case SpvOpPhi:
@ -227,7 +228,7 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(ir::Function* func) {
}
}
// Find and disconnect dead inserts
std::vector<ir::Instruction*> dead_instructions;
std::vector<opt::Instruction*> dead_instructions;
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
if (ii->opcode() != SpvOpCompositeInsert) continue;
@ -242,9 +243,9 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(ir::Function* func) {
}
// DCE dead inserts
while (!dead_instructions.empty()) {
ir::Instruction* inst = dead_instructions.back();
opt::Instruction* inst = dead_instructions.back();
dead_instructions.pop_back();
DCEInst(inst, [&dead_instructions](ir::Instruction* other_inst) {
DCEInst(inst, [&dead_instructions](opt::Instruction* other_inst) {
auto i = std::find(dead_instructions.begin(), dead_instructions.end(),
other_inst);
if (i != dead_instructions.end()) {
@ -255,13 +256,13 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(ir::Function* func) {
return modified;
}
void DeadInsertElimPass::Initialize(ir::IRContext* c) {
void DeadInsertElimPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
}
Pass::Status DeadInsertElimPass::ProcessImpl() {
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return EliminateDeadInserts(fp);
};
bool modified = ProcessEntryPointCallTree(pfn, get_module());
@ -270,7 +271,7 @@ Pass::Status DeadInsertElimPass::ProcessImpl() {
DeadInsertElimPass::DeadInsertElimPass() {}
Pass::Status DeadInsertElimPass::Process(ir::IRContext* c) {
Pass::Status DeadInsertElimPass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -37,45 +37,45 @@ class DeadInsertElimPass : public MemPass {
public:
DeadInsertElimPass();
const char* name() const override { return "eliminate-dead-inserts"; }
Status Process(ir::IRContext*) override;
virtual ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisDecorations |
ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG |
ir::IRContext::kAnalysisDominatorAnalysis |
ir::IRContext::kAnalysisNameMap;
Status Process(opt::IRContext*) override;
virtual opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisDecorations |
opt::IRContext::kAnalysisCombinators | opt::IRContext::kAnalysisCFG |
opt::IRContext::kAnalysisDominatorAnalysis |
opt::IRContext::kAnalysisNameMap;
}
private:
// Return the number of subcomponents in the composite type |typeId|.
// Return 0 if not a composite type or number of components is not a
// 32-bit constant.
uint32_t NumComponents(ir::Instruction* typeInst);
uint32_t NumComponents(opt::Instruction* typeInst);
// Mark all inserts in instruction chain ending at |insertChain| with
// indices that intersect with extract indices |extIndices| starting with
// index at |extOffset|. Chains are composed solely of Inserts and Phis.
// Mark all inserts in chain if |extIndices| is nullptr.
void MarkInsertChain(ir::Instruction* insertChain,
void MarkInsertChain(opt::Instruction* insertChain,
std::vector<uint32_t>* extIndices, uint32_t extOffset,
std::unordered_set<uint32_t>* visited_phis);
// Perform EliminateDeadInsertsOnePass(|func|) until no modification is
// made. Return true if modified.
bool EliminateDeadInserts(ir::Function* func);
bool EliminateDeadInserts(opt::Function* func);
// DCE all dead struct, matrix and vector inserts in |func|. An insert is
// dead if the value it inserts is never used. Replace any reference to the
// insert with its original composite. Return true if modified. Dead inserts
// in dependence cycles are not currently eliminated. Dead inserts into
// arrays are not currently eliminated.
bool EliminateDeadInsertsOnePass(ir::Function* func);
bool EliminateDeadInsertsOnePass(opt::Function* func);
// Return true if all extensions in this module are allowed by this pass.
bool AllExtensionsSupported() const;
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
// Live inserts

View File

@ -22,7 +22,7 @@ namespace opt {
// This optimization removes global variables that are not needed because they
// are definitely not accessed.
Pass::Status DeadVariableElimination::Process(ir::IRContext* c) {
Pass::Status DeadVariableElimination::Process(opt::IRContext* c) {
// The algorithm will compute the reference count for every global variable.
// Anything with a reference count of 0 will then be deleted. For variables
// that might have references that are not explicit in this context, we use
@ -45,7 +45,7 @@ Pass::Status DeadVariableElimination::Process(ir::IRContext* c) {
// else, so we must keep the variable around.
get_decoration_mgr()->ForEachDecoration(
result_id, SpvDecorationLinkageAttributes,
[&count](const ir::Instruction& linkage_instruction) {
[&count](const opt::Instruction& linkage_instruction) {
uint32_t last_operand = linkage_instruction.NumOperands() - 1;
if (linkage_instruction.GetSingleWordOperand(last_operand) ==
SpvLinkageTypeExport) {
@ -58,8 +58,8 @@ Pass::Status DeadVariableElimination::Process(ir::IRContext* c) {
// at the uses and count the number of real references.
count = 0;
get_def_use_mgr()->ForEachUser(
result_id, [&count](ir::Instruction* user) {
if (!ir::IsAnnotationInst(user->opcode()) &&
result_id, [&count](opt::Instruction* user) {
if (!opt::IsAnnotationInst(user->opcode()) &&
user->opcode() != SpvOpName) {
++count;
}
@ -83,14 +83,14 @@ Pass::Status DeadVariableElimination::Process(ir::IRContext* c) {
}
void DeadVariableElimination::DeleteVariable(uint32_t result_id) {
ir::Instruction* inst = get_def_use_mgr()->GetDef(result_id);
opt::Instruction* inst = get_def_use_mgr()->GetDef(result_id);
assert(inst->opcode() == SpvOpVariable &&
"Should not be trying to delete anything other than an OpVariable.");
// Look for an initializer that references another variable. We need to know
// if that variable can be deleted after the reference is removed.
if (inst->NumOperands() == 4) {
ir::Instruction* initializer =
opt::Instruction* initializer =
get_def_use_mgr()->GetDef(inst->GetSingleWordOperand(3));
// TODO: Handle OpSpecConstantOP which might be defined in terms of other

View File

@ -27,10 +27,10 @@ namespace opt {
class DeadVariableElimination : public MemPass {
public:
const char* name() const override { return "dead-variable-elimination"; }
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse;
}
private:

View File

@ -25,35 +25,35 @@ namespace opt {
namespace analysis {
void DecorationManager::RemoveDecorationsFrom(
uint32_t id, std::function<bool(const ir::Instruction&)> pred) {
uint32_t id, std::function<bool(const opt::Instruction&)> pred) {
const auto ids_iter = id_to_decoration_insts_.find(id);
if (ids_iter == id_to_decoration_insts_.end()) return;
TargetData& decorations_info = ids_iter->second;
auto context = module_->context();
std::vector<ir::Instruction*> insts_to_kill;
std::vector<opt::Instruction*> insts_to_kill;
const bool is_group = !decorations_info.decorate_insts.empty();
// Schedule all direct decorations for removal if instructed as such by
// |pred|.
for (ir::Instruction* inst : decorations_info.direct_decorations)
for (opt::Instruction* inst : decorations_info.direct_decorations)
if (pred(*inst)) insts_to_kill.push_back(inst);
// For all groups being directly applied to |id|, remove |id| (and the
// literal if |inst| is an OpGroupMemberDecorate) from the instruction
// applying the group.
std::unordered_set<const ir::Instruction*> indirect_decorations_to_remove;
for (ir::Instruction* inst : decorations_info.indirect_decorations) {
std::unordered_set<const opt::Instruction*> indirect_decorations_to_remove;
for (opt::Instruction* inst : decorations_info.indirect_decorations) {
assert(inst->opcode() == SpvOpGroupDecorate ||
inst->opcode() == SpvOpGroupMemberDecorate);
std::vector<ir::Instruction*> group_decorations_to_keep;
std::vector<opt::Instruction*> group_decorations_to_keep;
const uint32_t group_id = inst->GetSingleWordInOperand(0u);
const auto group_iter = id_to_decoration_insts_.find(group_id);
assert(group_iter != id_to_decoration_insts_.end() &&
"Unknown decoration group");
const auto& group_decorations = group_iter->second.direct_decorations;
for (ir::Instruction* decoration : group_decorations) {
for (opt::Instruction* decoration : group_decorations) {
if (!pred(*decoration)) group_decorations_to_keep.push_back(decoration);
}
@ -97,9 +97,9 @@ void DecorationManager::RemoveDecorationsFrom(
// If only some of the decorations should be kept, clone them and apply
// them directly to |id|.
if (!group_decorations_to_keep.empty()) {
for (ir::Instruction* decoration : group_decorations_to_keep) {
for (opt::Instruction* decoration : group_decorations_to_keep) {
// simply clone decoration and change |group_id| to |id|
std::unique_ptr<ir::Instruction> new_inst(
std::unique_ptr<opt::Instruction> new_inst(
decoration->Clone(module_->context()));
new_inst->SetInOperand(0, {id});
module_->AddAnnotationInst(std::move(new_inst));
@ -113,22 +113,22 @@ void DecorationManager::RemoveDecorationsFrom(
indirect_decorations.erase(
std::remove_if(
indirect_decorations.begin(), indirect_decorations.end(),
[&indirect_decorations_to_remove](const ir::Instruction* inst) {
[&indirect_decorations_to_remove](const opt::Instruction* inst) {
return indirect_decorations_to_remove.count(inst);
}),
indirect_decorations.end());
for (ir::Instruction* inst : insts_to_kill) context->KillInst(inst);
for (opt::Instruction* inst : insts_to_kill) context->KillInst(inst);
insts_to_kill.clear();
// Schedule all instructions applying the group for removal if this group no
// longer applies decorations, either directly or indirectly.
if (is_group && decorations_info.direct_decorations.empty() &&
decorations_info.indirect_decorations.empty()) {
for (ir::Instruction* inst : decorations_info.decorate_insts)
for (opt::Instruction* inst : decorations_info.decorate_insts)
insts_to_kill.push_back(inst);
}
for (ir::Instruction* inst : insts_to_kill) context->KillInst(inst);
for (opt::Instruction* inst : insts_to_kill) context->KillInst(inst);
if (decorations_info.direct_decorations.empty() &&
decorations_info.indirect_decorations.empty() &&
@ -140,20 +140,20 @@ void DecorationManager::RemoveDecorationsFrom(
}
}
std::vector<ir::Instruction*> DecorationManager::GetDecorationsFor(
std::vector<opt::Instruction*> DecorationManager::GetDecorationsFor(
uint32_t id, bool include_linkage) {
return InternalGetDecorationsFor<ir::Instruction*>(id, include_linkage);
return InternalGetDecorationsFor<opt::Instruction*>(id, include_linkage);
}
std::vector<const ir::Instruction*> DecorationManager::GetDecorationsFor(
std::vector<const opt::Instruction*> DecorationManager::GetDecorationsFor(
uint32_t id, bool include_linkage) const {
return const_cast<DecorationManager*>(this)
->InternalGetDecorationsFor<const ir::Instruction*>(id, include_linkage);
->InternalGetDecorationsFor<const opt::Instruction*>(id, include_linkage);
}
bool DecorationManager::HaveTheSameDecorations(uint32_t id1,
uint32_t id2) const {
using InstructionList = std::vector<const ir::Instruction*>;
using InstructionList = std::vector<const opt::Instruction*>;
using DecorationSet = std::set<std::u32string>;
const InstructionList decorations_for1 = GetDecorationsFor(id1, false);
@ -167,7 +167,7 @@ bool DecorationManager::HaveTheSameDecorations(uint32_t id1,
[](const InstructionList& decoration_list, DecorationSet* decorate_set,
DecorationSet* decorate_id_set, DecorationSet* decorate_string_set,
DecorationSet* member_decorate_set) {
for (const ir::Instruction* inst : decoration_list) {
for (const opt::Instruction* inst : decoration_list) {
std::u32string decoration_payload;
// Ignore the opcode and the target as we do not want them to be
// compared.
@ -223,8 +223,8 @@ bool DecorationManager::HaveTheSameDecorations(uint32_t id1,
// TODO(pierremoreau): If OpDecorateId is referencing an OpConstant, one could
// check that the constants are the same rather than just
// looking at the constant ID.
bool DecorationManager::AreDecorationsTheSame(const ir::Instruction* inst1,
const ir::Instruction* inst2,
bool DecorationManager::AreDecorationsTheSame(const opt::Instruction* inst1,
const opt::Instruction* inst2,
bool ignore_target) const {
switch (inst1->opcode()) {
case SpvOpDecorate:
@ -250,11 +250,11 @@ void DecorationManager::AnalyzeDecorations() {
if (!module_) return;
// For each group and instruction, collect all their decoration instructions.
for (ir::Instruction& inst : module_->annotations()) {
for (opt::Instruction& inst : module_->annotations()) {
AddDecoration(&inst);
}
}
void DecorationManager::AddDecoration(ir::Instruction* inst) {
void DecorationManager::AddDecoration(opt::Instruction* inst) {
switch (inst->opcode()) {
case SpvOpDecorate:
case SpvOpDecorateId:
@ -295,8 +295,8 @@ std::vector<T> DecorationManager::InternalGetDecorationsFor(
const auto process_direct_decorations =
[include_linkage,
&decorations](const std::vector<ir::Instruction*>& direct_decorations) {
for (ir::Instruction* inst : direct_decorations) {
&decorations](const std::vector<opt::Instruction*>& direct_decorations) {
for (opt::Instruction* inst : direct_decorations) {
const bool is_linkage = inst->opcode() == SpvOpDecorate &&
inst->GetSingleWordInOperand(1u) ==
SpvDecorationLinkageAttributes;
@ -308,7 +308,7 @@ std::vector<T> DecorationManager::InternalGetDecorationsFor(
process_direct_decorations(ids_iter->second.direct_decorations);
// Process the decorations of all groups applied to |id|.
for (const ir::Instruction* inst : target_data.indirect_decorations) {
for (const opt::Instruction* inst : target_data.indirect_decorations) {
const uint32_t group_id = inst->GetSingleWordInOperand(0u);
const auto group_iter = id_to_decoration_insts_.find(group_id);
assert(group_iter != id_to_decoration_insts_.end() && "Unknown group ID");
@ -320,8 +320,8 @@ std::vector<T> DecorationManager::InternalGetDecorationsFor(
bool DecorationManager::WhileEachDecoration(
uint32_t id, uint32_t decoration,
std::function<bool(const ir::Instruction&)> f) {
for (const ir::Instruction* inst : GetDecorationsFor(id, true)) {
std::function<bool(const opt::Instruction&)> f) {
for (const opt::Instruction* inst : GetDecorationsFor(id, true)) {
switch (inst->opcode()) {
case SpvOpMemberDecorate:
if (inst->GetSingleWordInOperand(2) == decoration) {
@ -344,8 +344,8 @@ bool DecorationManager::WhileEachDecoration(
void DecorationManager::ForEachDecoration(
uint32_t id, uint32_t decoration,
std::function<void(const ir::Instruction&)> f) {
WhileEachDecoration(id, decoration, [&f](const ir::Instruction& inst) {
std::function<void(const opt::Instruction&)> f) {
WhileEachDecoration(id, decoration, [&f](const opt::Instruction& inst) {
f(inst);
return true;
});
@ -355,9 +355,9 @@ void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
const auto decoration_list = id_to_decoration_insts_.find(from);
if (decoration_list == id_to_decoration_insts_.end()) return;
auto context = module_->context();
for (ir::Instruction* inst : decoration_list->second.direct_decorations) {
for (opt::Instruction* inst : decoration_list->second.direct_decorations) {
// simply clone decoration and change |target-id| to |to|
std::unique_ptr<ir::Instruction> new_inst(inst->Clone(module_->context()));
std::unique_ptr<opt::Instruction> new_inst(inst->Clone(module_->context()));
new_inst->SetInOperand(0, {to});
module_->AddAnnotationInst(std::move(new_inst));
auto decoration_iter = --module_->annotation_end();
@ -365,15 +365,15 @@ void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
}
// We need to copy the list of instructions as ForgetUses and AnalyzeUses are
// going to modify it.
std::vector<ir::Instruction*> indirect_decorations =
std::vector<opt::Instruction*> indirect_decorations =
decoration_list->second.indirect_decorations;
for (ir::Instruction* inst : indirect_decorations) {
for (opt::Instruction* inst : indirect_decorations) {
switch (inst->opcode()) {
case SpvOpGroupDecorate:
context->ForgetUses(inst);
// add |to| to list of decorated id's
inst->AddOperand(
ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
context->AnalyzeUses(inst);
break;
case SpvOpGroupMemberDecorate: {
@ -381,10 +381,10 @@ void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
// for each (id == from), add (to, literal) as operands
const uint32_t num_operands = inst->NumOperands();
for (uint32_t i = 1; i < num_operands; i += 2) {
ir::Operand op = inst->GetOperand(i);
opt::Operand op = inst->GetOperand(i);
if (op.words[0] == from) { // add new pair of operands: (to, literal)
inst->AddOperand(
ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
opt::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
op = inst->GetOperand(i + 1);
inst->AddOperand(std::move(op));
}
@ -398,8 +398,8 @@ void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
}
}
void DecorationManager::RemoveDecoration(ir::Instruction* inst) {
const auto remove_from_container = [inst](std::vector<ir::Instruction*>& v) {
void DecorationManager::RemoveDecoration(opt::Instruction* inst) {
const auto remove_from_container = [inst](std::vector<opt::Instruction*>& v) {
v.erase(std::remove(v.begin(), v.end(), inst), v.end());
};

View File

@ -27,11 +27,11 @@ namespace spvtools {
namespace opt {
namespace analysis {
// A class for analyzing and managing decorations in an ir::Module.
// A class for analyzing and managing decorations in an opt::Module.
class DecorationManager {
public:
// Constructs a decoration manager from the given |module|
explicit DecorationManager(ir::Module* module) : module_(module) {
explicit DecorationManager(opt::Module* module) : module_(module) {
AnalyzeDecorations();
}
DecorationManager() = delete;
@ -42,22 +42,22 @@ class DecorationManager {
// removed if they have no targets left, and OpDecorationGroup will be
// removed if the group is not applied to anyone and contains no decorations.
void RemoveDecorationsFrom(uint32_t id,
std::function<bool(const ir::Instruction&)> pred =
[](const ir::Instruction&) { return true; });
std::function<bool(const opt::Instruction&)> pred =
[](const opt::Instruction&) { return true; });
// Removes all decorations from the result id of |inst|.
//
// NOTE: This is only meant to be called from ir_context, as only metadata
// will be removed, and no actual instruction.
void RemoveDecoration(ir::Instruction* inst);
void RemoveDecoration(opt::Instruction* inst);
// Returns a vector of all decorations affecting |id|. If a group is applied
// to |id|, the decorations of that group are returned rather than the group
// decoration instruction. If |include_linkage| is not set, linkage
// decorations won't be returned.
std::vector<ir::Instruction*> GetDecorationsFor(uint32_t id,
bool include_linkage);
std::vector<const ir::Instruction*> GetDecorationsFor(
std::vector<opt::Instruction*> GetDecorationsFor(uint32_t id,
bool include_linkage);
std::vector<const opt::Instruction*> GetDecorationsFor(
uint32_t id, bool include_linkage) const;
// Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate
// instructions that apply the same decorations but to different IDs, still
@ -69,22 +69,22 @@ class DecorationManager {
//
// This is only valid for OpDecorate, OpMemberDecorate and OpDecorateId; it
// will return false for other opcodes.
bool AreDecorationsTheSame(const ir::Instruction* inst1,
const ir::Instruction* inst2,
bool AreDecorationsTheSame(const opt::Instruction* inst1,
const opt::Instruction* inst2,
bool ignore_target) const;
// |f| is run on each decoration instruction for |id| with decoration
// |decoration|. Processed are all decorations which target |id| either
// directly or indirectly by Decoration Groups.
void ForEachDecoration(uint32_t id, uint32_t decoration,
std::function<void(const ir::Instruction&)> f);
std::function<void(const opt::Instruction&)> f);
// |f| is run on each decoration instruction for |id| with decoration
// |decoration|. Processes all decoration which target |id| either directly or
// indirectly through decoration groups. If |f| returns false, iteration is
// terminated and this function returns false.
bool WhileEachDecoration(uint32_t id, uint32_t decoration,
std::function<bool(const ir::Instruction&)> f);
std::function<bool(const opt::Instruction&)> f);
// Clone all decorations from one id |from|.
// The cloned decorations are assigned to the given id |to| and are
@ -93,7 +93,7 @@ class DecorationManager {
void CloneDecorations(uint32_t from, uint32_t to);
// Informs the decoration manager of a new decoration that it needs to track.
void AddDecoration(ir::Instruction* inst);
void AddDecoration(opt::Instruction* inst);
private:
// Analyzes the defs and uses in the given |module| and populates data
@ -105,19 +105,19 @@ class DecorationManager {
// Tracks decoration information of an ID.
struct TargetData {
std::vector<ir::Instruction*> direct_decorations; // All decorate
// instructions applied
// to the tracked ID.
std::vector<ir::Instruction*> indirect_decorations; // All instructions
// applying a group to
// the tracked ID.
std::vector<ir::Instruction*> decorate_insts; // All decorate instructions
// applying the decorations
// of the tracked ID to
// targets.
// It is empty if the
// tracked ID is not a
// group.
std::vector<opt::Instruction*> direct_decorations; // All decorate
// instructions applied
// to the tracked ID.
std::vector<opt::Instruction*> indirect_decorations; // All instructions
// applying a group to
// the tracked ID.
std::vector<opt::Instruction*> decorate_insts; // All decorate instructions
// applying the decorations
// of the tracked ID to
// targets.
// It is empty if the
// tracked ID is not a
// group.
};
// Mapping from ids to the instructions applying a decoration to those ids.
@ -127,7 +127,7 @@ class DecorationManager {
// SpvOpMemberGroupDecorate).
std::unordered_map<uint32_t, TargetData> id_to_decoration_insts_;
// The enclosing module.
ir::Module* module_;
opt::Module* module_;
};
} // namespace analysis

View File

@ -23,7 +23,7 @@ namespace spvtools {
namespace opt {
namespace analysis {
void DefUseManager::AnalyzeInstDef(ir::Instruction* inst) {
void DefUseManager::AnalyzeInstDef(opt::Instruction* inst) {
const uint32_t def_id = inst->result_id();
if (def_id != 0) {
auto iter = id_to_def_.find(def_id);
@ -38,7 +38,7 @@ void DefUseManager::AnalyzeInstDef(ir::Instruction* inst) {
}
}
void DefUseManager::AnalyzeInstUse(ir::Instruction* inst) {
void DefUseManager::AnalyzeInstUse(opt::Instruction* inst) {
// Create entry for the given instruction. Note that the instruction may
// not have any in-operands. In such cases, we still need a entry for those
// instructions so this manager knows it has seen the instruction later.
@ -57,7 +57,7 @@ void DefUseManager::AnalyzeInstUse(ir::Instruction* inst) {
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
case SPV_OPERAND_TYPE_SCOPE_ID: {
uint32_t use_id = inst->GetSingleWordOperand(i);
ir::Instruction* def = GetDef(use_id);
opt::Instruction* def = GetDef(use_id);
assert(def && "Definition is not registered.");
id_to_users_.insert(UserEntry(def, inst));
used_ids->push_back(use_id);
@ -68,12 +68,12 @@ void DefUseManager::AnalyzeInstUse(ir::Instruction* inst) {
}
}
void DefUseManager::AnalyzeInstDefUse(ir::Instruction* inst) {
void DefUseManager::AnalyzeInstDefUse(opt::Instruction* inst) {
AnalyzeInstDef(inst);
AnalyzeInstUse(inst);
}
void DefUseManager::UpdateDefUse(ir::Instruction* inst) {
void DefUseManager::UpdateDefUse(opt::Instruction* inst) {
const uint32_t def_id = inst->result_id();
if (def_id != 0) {
auto iter = id_to_def_.find(def_id);
@ -84,38 +84,38 @@ void DefUseManager::UpdateDefUse(ir::Instruction* inst) {
AnalyzeInstUse(inst);
}
ir::Instruction* DefUseManager::GetDef(uint32_t id) {
opt::Instruction* DefUseManager::GetDef(uint32_t id) {
auto iter = id_to_def_.find(id);
if (iter == id_to_def_.end()) return nullptr;
return iter->second;
}
const ir::Instruction* DefUseManager::GetDef(uint32_t id) const {
const opt::Instruction* DefUseManager::GetDef(uint32_t id) const {
const auto iter = id_to_def_.find(id);
if (iter == id_to_def_.end()) return nullptr;
return iter->second;
}
DefUseManager::IdToUsersMap::const_iterator DefUseManager::UsersBegin(
const ir::Instruction* def) const {
const opt::Instruction* def) const {
return id_to_users_.lower_bound(
UserEntry(const_cast<ir::Instruction*>(def), nullptr));
UserEntry(const_cast<opt::Instruction*>(def), nullptr));
}
bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const IdToUsersMap::const_iterator& cached_end,
const ir::Instruction* inst) const {
const opt::Instruction* inst) const {
return (iter != cached_end && iter->first == inst);
}
bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const ir::Instruction* inst) const {
const opt::Instruction* inst) const {
return UsersNotEnd(iter, id_to_users_.end(), inst);
}
bool DefUseManager::WhileEachUser(
const ir::Instruction* def,
const std::function<bool(ir::Instruction*)>& f) const {
const opt::Instruction* def,
const std::function<bool(opt::Instruction*)>& f) const {
// Ensure that |def| has been registered.
assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) &&
"Definition is not registered.");
@ -129,27 +129,27 @@ bool DefUseManager::WhileEachUser(
}
bool DefUseManager::WhileEachUser(
uint32_t id, const std::function<bool(ir::Instruction*)>& f) const {
uint32_t id, const std::function<bool(opt::Instruction*)>& f) const {
return WhileEachUser(GetDef(id), f);
}
void DefUseManager::ForEachUser(
const ir::Instruction* def,
const std::function<void(ir::Instruction*)>& f) const {
WhileEachUser(def, [&f](ir::Instruction* user) {
const opt::Instruction* def,
const std::function<void(opt::Instruction*)>& f) const {
WhileEachUser(def, [&f](opt::Instruction* user) {
f(user);
return true;
});
}
void DefUseManager::ForEachUser(
uint32_t id, const std::function<void(ir::Instruction*)>& f) const {
uint32_t id, const std::function<void(opt::Instruction*)>& f) const {
ForEachUser(GetDef(id), f);
}
bool DefUseManager::WhileEachUse(
const ir::Instruction* def,
const std::function<bool(ir::Instruction*, uint32_t)>& f) const {
const opt::Instruction* def,
const std::function<bool(opt::Instruction*, uint32_t)>& f) const {
// Ensure that |def| has been registered.
assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) &&
"Definition is not registered.");
@ -157,9 +157,9 @@ bool DefUseManager::WhileEachUse(
auto end = id_to_users_.end();
for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) {
ir::Instruction* user = iter->second;
opt::Instruction* user = iter->second;
for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) {
const ir::Operand& op = user->GetOperand(idx);
const opt::Operand& op = user->GetOperand(idx);
if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) {
if (def->result_id() == op.words[0]) {
if (!f(user, idx)) return false;
@ -172,14 +172,14 @@ bool DefUseManager::WhileEachUse(
bool DefUseManager::WhileEachUse(
uint32_t id,
const std::function<bool(ir::Instruction*, uint32_t)>& f) const {
const std::function<bool(opt::Instruction*, uint32_t)>& f) const {
return WhileEachUse(GetDef(id), f);
}
void DefUseManager::ForEachUse(
const ir::Instruction* def,
const std::function<void(ir::Instruction*, uint32_t)>& f) const {
WhileEachUse(def, [&f](ir::Instruction* user, uint32_t index) {
const opt::Instruction* def,
const std::function<void(opt::Instruction*, uint32_t)>& f) const {
WhileEachUse(def, [&f](opt::Instruction* user, uint32_t index) {
f(user, index);
return true;
});
@ -187,13 +187,13 @@ void DefUseManager::ForEachUse(
void DefUseManager::ForEachUse(
uint32_t id,
const std::function<void(ir::Instruction*, uint32_t)>& f) const {
const std::function<void(opt::Instruction*, uint32_t)>& f) const {
ForEachUse(GetDef(id), f);
}
uint32_t DefUseManager::NumUsers(const ir::Instruction* def) const {
uint32_t DefUseManager::NumUsers(const opt::Instruction* def) const {
uint32_t count = 0;
ForEachUser(def, [&count](ir::Instruction*) { ++count; });
ForEachUser(def, [&count](opt::Instruction*) { ++count; });
return count;
}
@ -201,9 +201,9 @@ uint32_t DefUseManager::NumUsers(uint32_t id) const {
return NumUsers(GetDef(id));
}
uint32_t DefUseManager::NumUses(const ir::Instruction* def) const {
uint32_t DefUseManager::NumUses(const opt::Instruction* def) const {
uint32_t count = 0;
ForEachUse(def, [&count](ir::Instruction*, uint32_t) { ++count; });
ForEachUse(def, [&count](opt::Instruction*, uint32_t) { ++count; });
return count;
}
@ -211,20 +211,21 @@ uint32_t DefUseManager::NumUses(uint32_t id) const {
return NumUses(GetDef(id));
}
std::vector<ir::Instruction*> DefUseManager::GetAnnotations(uint32_t id) const {
std::vector<ir::Instruction*> annos;
const ir::Instruction* def = GetDef(id);
std::vector<opt::Instruction*> DefUseManager::GetAnnotations(
uint32_t id) const {
std::vector<opt::Instruction*> annos;
const opt::Instruction* def = GetDef(id);
if (!def) return annos;
ForEachUser(def, [&annos](ir::Instruction* user) {
if (ir::IsAnnotationInst(user->opcode())) {
ForEachUser(def, [&annos](opt::Instruction* user) {
if (opt::IsAnnotationInst(user->opcode())) {
annos.push_back(user);
}
});
return annos;
}
void DefUseManager::AnalyzeDefUse(ir::Module* module) {
void DefUseManager::AnalyzeDefUse(opt::Module* module) {
if (!module) return;
// Analyze all the defs before any uses to catch forward references.
module->ForEachInst(
@ -233,7 +234,7 @@ void DefUseManager::AnalyzeDefUse(ir::Module* module) {
std::bind(&DefUseManager::AnalyzeInstUse, this, std::placeholders::_1));
}
void DefUseManager::ClearInst(ir::Instruction* inst) {
void DefUseManager::ClearInst(opt::Instruction* inst) {
auto iter = inst_to_used_ids_.find(inst);
if (iter != inst_to_used_ids_.end()) {
EraseUseRecordsOfOperandIds(inst);
@ -250,14 +251,14 @@ void DefUseManager::ClearInst(ir::Instruction* inst) {
}
}
void DefUseManager::EraseUseRecordsOfOperandIds(const ir::Instruction* inst) {
void DefUseManager::EraseUseRecordsOfOperandIds(const opt::Instruction* inst) {
// Go through all ids used by this instruction, remove this instruction's
// uses of them.
auto iter = inst_to_used_ids_.find(inst);
if (iter != inst_to_used_ids_.end()) {
for (auto use_id : iter->second) {
id_to_users_.erase(
UserEntry(GetDef(use_id), const_cast<ir::Instruction*>(inst)));
UserEntry(GetDef(use_id), const_cast<opt::Instruction*>(inst)));
}
inst_to_used_ids_.erase(inst);
}

View File

@ -33,7 +33,7 @@ namespace analysis {
// * Ids referenced in OpSectionMerge & OpLoopMerge are considered as use.
// * Ids referenced in OpPhi's in operands are considered as use.
struct Use {
ir::Instruction* inst; // Instruction using the id.
opt::Instruction* inst; // Instruction using the id.
uint32_t operand_index; // logical operand index of the id use. This can be
// the index of result type id.
};
@ -58,7 +58,7 @@ inline bool operator<(const Use& lhs, const Use& rhs) {
// Definition should never be null. User can be null, however, such an entry
// should be used only for searching (e.g. all users of a particular definition)
// and never stored in a container.
using UserEntry = std::pair<ir::Instruction*, ir::Instruction*>;
using UserEntry = std::pair<opt::Instruction*, opt::Instruction*>;
// Orders UserEntry for use in associative containers (i.e. less than ordering).
//
@ -92,17 +92,17 @@ struct UserEntryLess {
}
};
// A class for analyzing and managing defs and uses in an ir::Module.
// A class for analyzing and managing defs and uses in an opt::Module.
class DefUseManager {
public:
using IdToDefMap = std::unordered_map<uint32_t, ir::Instruction*>;
using IdToDefMap = std::unordered_map<uint32_t, opt::Instruction*>;
using IdToUsersMap = std::set<UserEntry, UserEntryLess>;
// Constructs a def-use manager from the given |module|. All internal messages
// will be communicated to the outside via the given message |consumer|. This
// instance only keeps a reference to the |consumer|, so the |consumer| should
// outlive this instance.
DefUseManager(ir::Module* module) { AnalyzeDefUse(module); }
DefUseManager(opt::Module* module) { AnalyzeDefUse(module); }
DefUseManager(const DefUseManager&) = delete;
DefUseManager(DefUseManager&&) = delete;
@ -110,20 +110,20 @@ class DefUseManager {
DefUseManager& operator=(DefUseManager&&) = delete;
// Analyzes the defs in the given |inst|.
void AnalyzeInstDef(ir::Instruction* inst);
void AnalyzeInstDef(opt::Instruction* inst);
// Analyzes the uses in the given |inst|.
//
// All operands of |inst| must be analyzed as defs.
void AnalyzeInstUse(ir::Instruction* inst);
void AnalyzeInstUse(opt::Instruction* inst);
// Analyzes the defs and uses in the given |inst|.
void AnalyzeInstDefUse(ir::Instruction* inst);
void AnalyzeInstDefUse(opt::Instruction* inst);
// Returns the def instruction for the given |id|. If there is no instruction
// defining |id|, returns nullptr.
ir::Instruction* GetDef(uint32_t id);
const ir::Instruction* GetDef(uint32_t id) const;
opt::Instruction* GetDef(uint32_t id);
const opt::Instruction* GetDef(uint32_t id) const;
// Runs the given function |f| on each unique user instruction of |def| (or
// |id|).
@ -132,10 +132,10 @@ class DefUseManager {
// only be visited once.
//
// |def| (or |id|) must be registered as a definition.
void ForEachUser(const ir::Instruction* def,
const std::function<void(ir::Instruction*)>& f) const;
void ForEachUser(const opt::Instruction* def,
const std::function<void(opt::Instruction*)>& f) const;
void ForEachUser(uint32_t id,
const std::function<void(ir::Instruction*)>& f) const;
const std::function<void(opt::Instruction*)>& f) const;
// Runs the given function |f| on each unique user instruction of |def| (or
// |id|). If |f| returns false, iteration is terminated and this function
@ -145,10 +145,10 @@ class DefUseManager {
// be only be visited once.
//
// |def| (or |id|) must be registered as a definition.
bool WhileEachUser(const ir::Instruction* def,
const std::function<bool(ir::Instruction*)>& f) const;
bool WhileEachUser(const opt::Instruction* def,
const std::function<bool(opt::Instruction*)>& f) const;
bool WhileEachUser(uint32_t id,
const std::function<bool(ir::Instruction*)>& f) const;
const std::function<bool(opt::Instruction*)>& f) const;
// Runs the given function |f| on each unique use of |def| (or
// |id|).
@ -157,11 +157,11 @@ class DefUseManager {
// visited separately.
//
// |def| (or |id|) must be registered as a definition.
void ForEachUse(const ir::Instruction* def,
const std::function<void(ir::Instruction*,
void ForEachUse(const opt::Instruction* def,
const std::function<void(opt::Instruction*,
uint32_t operand_index)>& f) const;
void ForEachUse(uint32_t id,
const std::function<void(ir::Instruction*,
const std::function<void(opt::Instruction*,
uint32_t operand_index)>& f) const;
// Runs the given function |f| on each unique use of |def| (or
@ -172,19 +172,19 @@ class DefUseManager {
// visited separately.
//
// |def| (or |id|) must be registered as a definition.
bool WhileEachUse(const ir::Instruction* def,
const std::function<bool(ir::Instruction*,
bool WhileEachUse(const opt::Instruction* def,
const std::function<bool(opt::Instruction*,
uint32_t operand_index)>& f) const;
bool WhileEachUse(uint32_t id,
const std::function<bool(ir::Instruction*,
const std::function<bool(opt::Instruction*,
uint32_t operand_index)>& f) const;
// Returns the number of users of |def| (or |id|).
uint32_t NumUsers(const ir::Instruction* def) const;
uint32_t NumUsers(const opt::Instruction* def) const;
uint32_t NumUsers(uint32_t id) const;
// Returns the number of uses of |def| (or |id|).
uint32_t NumUses(const ir::Instruction* def) const;
uint32_t NumUses(const opt::Instruction* def) const;
uint32_t NumUses(uint32_t id) const;
// Returns the annotation instrunctions which are a direct use of the given
@ -192,7 +192,7 @@ class DefUseManager {
// group(s), this function will just return the OpGroupDecorate
// instrcution(s) which refer to the given id as an operand. The OpDecorate
// instructions which decorate the decoration group will not be returned.
std::vector<ir::Instruction*> GetAnnotations(uint32_t id) const;
std::vector<opt::Instruction*> GetAnnotations(uint32_t id) const;
// Returns the map from ids to their def instructions.
const IdToDefMap& id_to_defs() const { return id_to_def_; }
@ -204,10 +204,10 @@ class DefUseManager {
// record: |inst| uses an |id|, will be removed from the use records of |id|.
// If |inst| defines an result id, the use record of this result id will also
// be removed. Does nothing if |inst| was not analyzed before.
void ClearInst(ir::Instruction* inst);
void ClearInst(opt::Instruction* inst);
// Erases the records that a given instruction uses its operand ids.
void EraseUseRecordsOfOperandIds(const ir::Instruction* inst);
void EraseUseRecordsOfOperandIds(const opt::Instruction* inst);
friend bool operator==(const DefUseManager&, const DefUseManager&);
friend bool operator!=(const DefUseManager& lhs, const DefUseManager& rhs) {
@ -216,15 +216,15 @@ class DefUseManager {
// If |inst| has not already been analysed, then analyses its defintion and
// uses.
void UpdateDefUse(ir::Instruction* inst);
void UpdateDefUse(opt::Instruction* inst);
private:
using InstToUsedIdsMap =
std::unordered_map<const ir::Instruction*, std::vector<uint32_t>>;
std::unordered_map<const opt::Instruction*, std::vector<uint32_t>>;
// Returns the first location that {|def|, nullptr} could be inserted into the
// users map without violating ordering.
IdToUsersMap::const_iterator UsersBegin(const ir::Instruction* def) const;
IdToUsersMap::const_iterator UsersBegin(const opt::Instruction* def) const;
// Returns true if |iter| has not reached the end of |def|'s users.
//
@ -233,14 +233,14 @@ class DefUseManager {
// against |cached_end| for validity before other checks. This allows caching
// the map's end which is a performance improvement on some platforms.
bool UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const ir::Instruction* def) const;
const opt::Instruction* def) const;
bool UsersNotEnd(const IdToUsersMap::const_iterator& iter,
const IdToUsersMap::const_iterator& cached_end,
const ir::Instruction* def) const;
const opt::Instruction* def) const;
// Analyzes the defs and uses in the given |module| and populates data
// structures in this class. Does nothing if |module| is nullptr.
void AnalyzeDefUse(ir::Module* module);
void AnalyzeDefUse(opt::Module* module);
IdToDefMap id_to_def_; // Mapping from ids to their definitions
IdToUsersMap id_to_users_; // Mapping from ids to their users

View File

@ -21,12 +21,12 @@
namespace spvtools {
namespace opt {
ir::BasicBlock* DominatorAnalysisBase::CommonDominator(
ir::BasicBlock* b1, ir::BasicBlock* b2) const {
opt::BasicBlock* DominatorAnalysisBase::CommonDominator(
opt::BasicBlock* b1, opt::BasicBlock* b2) const {
if (!b1 || !b2) return nullptr;
std::unordered_set<ir::BasicBlock*> seen;
ir::BasicBlock* block = b1;
std::unordered_set<opt::BasicBlock*> seen;
opt::BasicBlock* block = b1;
while (block && seen.insert(block).second) {
block = ImmediateDominator(block);
}
@ -39,8 +39,8 @@ ir::BasicBlock* DominatorAnalysisBase::CommonDominator(
return block;
}
bool DominatorAnalysisBase::Dominates(ir::Instruction* a,
ir::Instruction* b) const {
bool DominatorAnalysisBase::Dominates(opt::Instruction* a,
opt::Instruction* b) const {
if (!a || !b) {
return false;
}
@ -49,14 +49,14 @@ bool DominatorAnalysisBase::Dominates(ir::Instruction* a,
return true;
}
ir::BasicBlock* bb_a = a->context()->get_instr_block(a);
ir::BasicBlock* bb_b = b->context()->get_instr_block(b);
opt::BasicBlock* bb_a = a->context()->get_instr_block(a);
opt::BasicBlock* bb_b = b->context()->get_instr_block(b);
if (bb_a != bb_b) {
return tree_.Dominates(bb_a, bb_b);
}
ir::Instruction* current_inst = a;
opt::Instruction* current_inst = a;
while ((current_inst = current_inst->NextNode())) {
if (current_inst == b) {
return true;

View File

@ -30,11 +30,13 @@ class DominatorAnalysisBase {
explicit DominatorAnalysisBase(bool is_post_dom) : tree_(is_post_dom) {}
// Calculates the dominator (or postdominator) tree for given function |f|.
inline void InitializeTree(const ir::Function* f) { tree_.InitializeTree(f); }
inline void InitializeTree(const opt::Function* f) {
tree_.InitializeTree(f);
}
// Returns true if BasicBlock |a| dominates BasicBlock |b|.
inline bool Dominates(const ir::BasicBlock* a,
const ir::BasicBlock* b) const {
inline bool Dominates(const opt::BasicBlock* a,
const opt::BasicBlock* b) const {
if (!a || !b) return false;
return Dominates(a->id(), b->id());
}
@ -46,11 +48,11 @@ class DominatorAnalysisBase {
}
// Returns true if instruction |a| dominates instruction |b|.
bool Dominates(ir::Instruction* a, ir::Instruction* b) const;
bool Dominates(opt::Instruction* a, opt::Instruction* b) const;
// Returns true if BasicBlock |a| strictly dominates BasicBlock |b|.
inline bool StrictlyDominates(const ir::BasicBlock* a,
const ir::BasicBlock* b) const {
inline bool StrictlyDominates(const opt::BasicBlock* a,
const opt::BasicBlock* b) const {
if (!a || !b) return false;
return StrictlyDominates(a->id(), b->id());
}
@ -63,19 +65,20 @@ class DominatorAnalysisBase {
// Returns the immediate dominator of |node| or returns nullptr if it is has
// no dominator.
inline ir::BasicBlock* ImmediateDominator(const ir::BasicBlock* node) const {
inline opt::BasicBlock* ImmediateDominator(
const opt::BasicBlock* node) const {
if (!node) return nullptr;
return tree_.ImmediateDominator(node);
}
// Returns the immediate dominator of |node_id| or returns nullptr if it is
// has no dominator. Same as above but operates on IDs.
inline ir::BasicBlock* ImmediateDominator(uint32_t node_id) const {
inline opt::BasicBlock* ImmediateDominator(uint32_t node_id) const {
return tree_.ImmediateDominator(node_id);
}
// Returns true if |node| is reachable from the entry.
inline bool IsReachable(const ir::BasicBlock* node) const {
inline bool IsReachable(const opt::BasicBlock* node) const {
if (!node) return false;
return tree_.ReachableFromRoots(node->id());
}
@ -114,7 +117,8 @@ class DominatorAnalysisBase {
// Returns the most immediate basic block that dominates both |b1| and |b2|.
// If there is no such basic block, nullptr is returned.
ir::BasicBlock* CommonDominator(ir::BasicBlock* b1, ir::BasicBlock* b2) const;
opt::BasicBlock* CommonDominator(opt::BasicBlock* b1,
opt::BasicBlock* b2) const;
protected:
DominatorTree tree_;

View File

@ -45,7 +45,7 @@ namespace {
// depth first search on generic BasicBlock types. Will call post and pre order
// user defined functions during traversal
//
// BBType - BasicBlock type. Will either be ir::BasicBlock or DominatorTreeNode
// BBType - BasicBlock type. Will either be opt::BasicBlock or DominatorTreeNode
// SuccessorLambda - Lamdba matching the signature of 'const
// std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
// succeding BasicBlock A.
@ -66,7 +66,7 @@ static void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
// depth first search on generic BasicBlock types. This overload is for only
// performing user defined post order.
//
// BBType - BasicBlock type. Will either be ir::BasicBlock or DominatorTreeNode
// BBType - BasicBlock type. Will either be opt::BasicBlock or DominatorTreeNode
// SuccessorLambda - Lamdba matching the signature of 'const
// std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
// succeding BasicBlock A.
@ -84,7 +84,7 @@ static void DepthFirstSearchPostOrder(const BBType* bb,
// Small type trait to get the function class type.
template <typename BBType>
struct GetFunctionClass {
using FunctionType = ir::Function;
using FunctionType = opt::Function;
};
// Helper class to compute predecessors and successors for each Basic Block in a
@ -98,7 +98,7 @@ struct GetFunctionClass {
// returned by this class will be predecessors in the original CFG.
template <typename BBType>
class BasicBlockSuccessorHelper {
// This should eventually become const ir::BasicBlock.
// This should eventually become const opt::BasicBlock.
using BasicBlock = BBType;
using Function = typename GetFunctionClass<BBType>::FunctionType;
@ -219,8 +219,8 @@ bool DominatorTree::StrictlyDominates(uint32_t a, uint32_t b) const {
return Dominates(a, b);
}
bool DominatorTree::StrictlyDominates(const ir::BasicBlock* a,
const ir::BasicBlock* b) const {
bool DominatorTree::StrictlyDominates(const opt::BasicBlock* a,
const opt::BasicBlock* b) const {
return DominatorTree::StrictlyDominates(a->id(), b->id());
}
@ -248,17 +248,17 @@ bool DominatorTree::Dominates(const DominatorTreeNode* a,
a->dfs_num_post_ > b->dfs_num_post_;
}
bool DominatorTree::Dominates(const ir::BasicBlock* A,
const ir::BasicBlock* B) const {
bool DominatorTree::Dominates(const opt::BasicBlock* A,
const opt::BasicBlock* B) const {
return Dominates(A->id(), B->id());
}
ir::BasicBlock* DominatorTree::ImmediateDominator(
const ir::BasicBlock* A) const {
opt::BasicBlock* DominatorTree::ImmediateDominator(
const opt::BasicBlock* A) const {
return ImmediateDominator(A->id());
}
ir::BasicBlock* DominatorTree::ImmediateDominator(uint32_t a) const {
opt::BasicBlock* DominatorTree::ImmediateDominator(uint32_t a) const {
// Check that A is a valid node in the tree.
auto a_itr = nodes_.find(a);
if (a_itr == nodes_.end()) return nullptr;
@ -272,7 +272,7 @@ ir::BasicBlock* DominatorTree::ImmediateDominator(uint32_t a) const {
return node->parent_->bb_;
}
DominatorTreeNode* DominatorTree::GetOrInsertNode(ir::BasicBlock* bb) {
DominatorTreeNode* DominatorTree::GetOrInsertNode(opt::BasicBlock* bb) {
DominatorTreeNode* dtn = nullptr;
std::map<uint32_t, DominatorTreeNode>::iterator node_iter =
@ -287,21 +287,21 @@ DominatorTreeNode* DominatorTree::GetOrInsertNode(ir::BasicBlock* bb) {
}
void DominatorTree::GetDominatorEdges(
const ir::Function* f, const ir::BasicBlock* dummy_start_node,
std::vector<std::pair<ir::BasicBlock*, ir::BasicBlock*>>* edges) {
const opt::Function* f, const opt::BasicBlock* dummy_start_node,
std::vector<std::pair<opt::BasicBlock*, opt::BasicBlock*>>* edges) {
// Each time the depth first traversal calls the postorder callback
// std::function we push that node into the postorder vector to create our
// postorder list.
std::vector<const ir::BasicBlock*> postorder;
auto postorder_function = [&](const ir::BasicBlock* b) {
std::vector<const opt::BasicBlock*> postorder;
auto postorder_function = [&](const opt::BasicBlock* b) {
postorder.push_back(b);
};
// CFA::CalculateDominators requires std::vector<ir::BasicBlock*>
// CFA::CalculateDominators requires std::vector<opt::BasicBlock*>
// BB are derived from F, so we need to const cast it at some point
// no modification is made on F.
BasicBlockSuccessorHelper<ir::BasicBlock> helper{
*const_cast<ir::Function*>(f), dummy_start_node, postdominator_};
BasicBlockSuccessorHelper<opt::BasicBlock> helper{
*const_cast<opt::Function*>(f), dummy_start_node, postdominator_};
// The successor function tells DepthFirstTraversal how to move to successive
// nodes by providing an interface to get a list of successor nodes from any
@ -318,23 +318,23 @@ void DominatorTree::GetDominatorEdges(
DepthFirstSearchPostOrder(dummy_start_node, successor_functor,
postorder_function);
*edges =
CFA<ir::BasicBlock>::CalculateDominators(postorder, predecessor_functor);
CFA<opt::BasicBlock>::CalculateDominators(postorder, predecessor_functor);
}
void DominatorTree::InitializeTree(const ir::Function* f) {
void DominatorTree::InitializeTree(const opt::Function* f) {
ClearTree();
// Skip over empty functions.
if (f->cbegin() == f->cend()) {
return;
}
const ir::CFG& cfg = *f->context()->cfg();
const opt::CFG& cfg = *f->context()->cfg();
const ir::BasicBlock* dummy_start_node =
const opt::BasicBlock* dummy_start_node =
postdominator_ ? cfg.pseudo_exit_block() : cfg.pseudo_entry_block();
// Get the immediate dominator for each node.
std::vector<std::pair<ir::BasicBlock*, ir::BasicBlock*>> edges;
std::vector<std::pair<opt::BasicBlock*, opt::BasicBlock*>> edges;
GetDominatorEdges(f, dummy_start_node, &edges);
// Transform the vector<pair> into the tree structure which we can use to

View File

@ -31,7 +31,7 @@ namespace opt {
// children. It also contains two values, for the pre and post indexes in the
// tree which are used to compare two nodes.
struct DominatorTreeNode {
explicit DominatorTreeNode(ir::BasicBlock* bb)
explicit DominatorTreeNode(opt::BasicBlock* bb)
: bb_(bb),
parent_(nullptr),
children_({}),
@ -77,7 +77,7 @@ struct DominatorTreeNode {
inline uint32_t id() const { return bb_->id(); }
ir::BasicBlock* bb_;
opt::BasicBlock* bb_;
DominatorTreeNode* parent_;
std::vector<DominatorTreeNode*> children_;
@ -158,10 +158,10 @@ class DominatorTree {
// Build the (post-)dominator tree for the function |f|
// Any existing data will be overwritten
void InitializeTree(const ir::Function* f);
void InitializeTree(const opt::Function* f);
// Check if the basic block |a| dominates the basic block |b|.
bool Dominates(const ir::BasicBlock* a, const ir::BasicBlock* b) const;
bool Dominates(const opt::BasicBlock* a, const opt::BasicBlock* b) const;
// Check if the basic block id |a| dominates the basic block id |b|.
bool Dominates(uint32_t a, uint32_t b) const;
@ -170,8 +170,8 @@ class DominatorTree {
bool Dominates(const DominatorTreeNode* a, const DominatorTreeNode* b) const;
// Check if the basic block |a| strictly dominates the basic block |b|.
bool StrictlyDominates(const ir::BasicBlock* a,
const ir::BasicBlock* b) const;
bool StrictlyDominates(const opt::BasicBlock* a,
const opt::BasicBlock* b) const;
// Check if the basic block id |a| strictly dominates the basic block id |b|.
bool StrictlyDominates(uint32_t a, uint32_t b) const;
@ -182,15 +182,15 @@ class DominatorTree {
const DominatorTreeNode* b) const;
// Returns the immediate dominator of basic block |a|.
ir::BasicBlock* ImmediateDominator(const ir::BasicBlock* A) const;
opt::BasicBlock* ImmediateDominator(const opt::BasicBlock* A) const;
// Returns the immediate dominator of basic block id |a|.
ir::BasicBlock* ImmediateDominator(uint32_t a) const;
opt::BasicBlock* ImmediateDominator(uint32_t a) const;
// Returns true if the basic block |a| is reachable by this tree. A node would
// be unreachable if it cannot be reached by traversal from the start node or
// for a postdominator tree, cannot be reached from the exit nodes.
inline bool ReachableFromRoots(const ir::BasicBlock* a) const {
inline bool ReachableFromRoots(const opt::BasicBlock* a) const {
if (!a) return false;
return ReachableFromRoots(a->id());
}
@ -242,12 +242,12 @@ class DominatorTree {
// Returns the DominatorTreeNode associated with the basic block |bb|.
// If the |bb| is unknown to the dominator tree, it returns null.
inline DominatorTreeNode* GetTreeNode(ir::BasicBlock* bb) {
inline DominatorTreeNode* GetTreeNode(opt::BasicBlock* bb) {
return GetTreeNode(bb->id());
}
// Returns the DominatorTreeNode associated with the basic block |bb|.
// If the |bb| is unknown to the dominator tree, it returns null.
inline const DominatorTreeNode* GetTreeNode(ir::BasicBlock* bb) const {
inline const DominatorTreeNode* GetTreeNode(opt::BasicBlock* bb) const {
return GetTreeNode(bb->id());
}
@ -272,7 +272,7 @@ class DominatorTree {
// Adds the basic block |bb| to the tree structure if it doesn't already
// exist.
DominatorTreeNode* GetOrInsertNode(ir::BasicBlock* bb);
DominatorTreeNode* GetOrInsertNode(opt::BasicBlock* bb);
// Recomputes the DF numbering of the tree.
void ResetDFNumbering();
@ -287,8 +287,8 @@ class DominatorTree {
// pair is its immediate dominator.
// The root of the tree has themself as immediate dominator.
void GetDominatorEdges(
const ir::Function* f, const ir::BasicBlock* dummy_start_node,
std::vector<std::pair<ir::BasicBlock*, ir::BasicBlock*>>* edges);
const opt::Function* f, const opt::BasicBlock* dummy_start_node,
std::vector<std::pair<opt::BasicBlock*, opt::BasicBlock*>>* edges);
// The roots of the tree.
std::vector<DominatorTreeNode*> roots_;

View File

@ -26,22 +26,22 @@
namespace spvtools {
namespace opt {
Pass::Status EliminateDeadConstantPass::Process(ir::IRContext* irContext) {
std::unordered_set<ir::Instruction*> working_list;
Pass::Status EliminateDeadConstantPass::Process(opt::IRContext* irContext) {
std::unordered_set<opt::Instruction*> working_list;
// Traverse all the instructions to get the initial set of dead constants as
// working list and count number of real uses for constants. Uses in
// annotation instructions do not count.
std::unordered_map<ir::Instruction*, size_t> use_counts;
std::vector<ir::Instruction*> constants = irContext->GetConstants();
std::unordered_map<opt::Instruction*, size_t> use_counts;
std::vector<opt::Instruction*> constants = irContext->GetConstants();
for (auto* c : constants) {
uint32_t const_id = c->result_id();
size_t count = 0;
irContext->get_def_use_mgr()->ForEachUse(
const_id, [&count](ir::Instruction* user, uint32_t index) {
const_id, [&count](opt::Instruction* user, uint32_t index) {
(void)index;
SpvOp op = user->opcode();
if (!(ir::IsAnnotationInst(op) || ir::IsDebug1Inst(op) ||
ir::IsDebug2Inst(op) || ir::IsDebug3Inst(op))) {
if (!(opt::IsAnnotationInst(op) || opt::IsDebug1Inst(op) ||
opt::IsDebug2Inst(op) || opt::IsDebug3Inst(op))) {
++count;
}
});
@ -53,9 +53,9 @@ Pass::Status EliminateDeadConstantPass::Process(ir::IRContext* irContext) {
// Start from the constants with 0 uses, back trace through the def-use chain
// to find all dead constants.
std::unordered_set<ir::Instruction*> dead_consts;
std::unordered_set<opt::Instruction*> dead_consts;
while (!working_list.empty()) {
ir::Instruction* inst = *working_list.begin();
opt::Instruction* inst = *working_list.begin();
// Back propagate if the instruction contains IDs in its operands.
switch (inst->opcode()) {
case SpvOp::SpvOpConstantComposite:
@ -68,7 +68,7 @@ Pass::Status EliminateDeadConstantPass::Process(ir::IRContext* irContext) {
continue;
}
uint32_t operand_id = inst->GetSingleWordInOperand(i);
ir::Instruction* def_inst =
opt::Instruction* def_inst =
irContext->get_def_use_mgr()->GetDef(operand_id);
// If the use_count does not have any count for the def_inst,
// def_inst must not be a constant, and should be ignored here.

View File

@ -26,7 +26,7 @@ namespace opt {
class EliminateDeadConstantPass : public Pass {
public:
const char* name() const override { return "eliminate-dead-const"; }
Status Process(ir::IRContext*) override;
Status Process(opt::IRContext*) override;
};
} // namespace opt

View File

@ -20,13 +20,13 @@
namespace spvtools {
namespace opt {
Pass::Status EliminateDeadFunctionsPass::Process(ir::IRContext* c) {
Pass::Status EliminateDeadFunctionsPass::Process(opt::IRContext* c) {
InitializeProcessing(c);
// Identify live functions first. Those that are not live
// are dead.
std::unordered_set<const ir::Function*> live_function_set;
ProcessFunction mark_live = [&live_function_set](ir::Function* fp) {
std::unordered_set<const opt::Function*> live_function_set;
ProcessFunction mark_live = [&live_function_set](opt::Function* fp) {
live_function_set.insert(fp);
return false;
};
@ -48,10 +48,10 @@ Pass::Status EliminateDeadFunctionsPass::Process(ir::IRContext* c) {
: Pass::Status::SuccessWithoutChange;
}
void EliminateDeadFunctionsPass::EliminateFunction(ir::Function* func) {
void EliminateDeadFunctionsPass::EliminateFunction(opt::Function* func) {
// Remove all of the instruction in the function body
func->ForEachInst(
[this](ir::Instruction* inst) { context()->KillInst(inst); }, true);
[this](opt::Instruction* inst) { context()->KillInst(inst); }, true);
}
} // namespace opt
} // namespace spvtools

View File

@ -27,14 +27,14 @@ namespace opt {
class EliminateDeadFunctionsPass : public MemPass {
public:
const char* name() const override { return "eliminate-dead-functions"; }
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse;
}
private:
void EliminateFunction(ir::Function* func);
void EliminateFunction(opt::Function* func);
};
} // namespace opt

View File

@ -21,13 +21,13 @@
namespace spvtools {
namespace opt {
void FeatureManager::Analyze(ir::Module* module) {
void FeatureManager::Analyze(opt::Module* module) {
AddExtensions(module);
AddCapabilities(module);
AddExtInstImportIds(module);
}
void FeatureManager::AddExtensions(ir::Module* module) {
void FeatureManager::AddExtensions(opt::Module* module) {
for (auto ext : module->extensions()) {
const std::string name =
reinterpret_cast<const char*>(ext.GetInOperand(0u).words.data());
@ -51,13 +51,13 @@ void FeatureManager::AddCapability(SpvCapability cap) {
}
}
void FeatureManager::AddCapabilities(ir::Module* module) {
for (ir::Instruction& inst : module->capabilities()) {
void FeatureManager::AddCapabilities(opt::Module* module) {
for (opt::Instruction& inst : module->capabilities()) {
AddCapability(static_cast<SpvCapability>(inst.GetSingleWordInOperand(0)));
}
}
void FeatureManager::AddExtInstImportIds(ir::Module* module) {
void FeatureManager::AddExtInstImportIds(opt::Module* module) {
extinst_importid_GLSLstd450_ = module->GetExtInstImportId("GLSL.std.450");
}

View File

@ -36,7 +36,7 @@ class FeatureManager {
}
// Analyzes |module| and records enabled extensions and capabilities.
void Analyze(ir::Module* module);
void Analyze(opt::Module* module);
CapabilitySet* GetCapabilities() { return &capabilities_; }
const CapabilitySet* GetCapabilities() const { return &capabilities_; }
@ -47,17 +47,17 @@ class FeatureManager {
private:
// Analyzes |module| and records enabled extensions.
void AddExtensions(ir::Module* module);
void AddExtensions(opt::Module* module);
// Adds the given |capability| and all implied capabilities into the current
// FeatureManager.
void AddCapability(SpvCapability capability);
// Analyzes |module| and records enabled capabilities.
void AddCapabilities(ir::Module* module);
void AddCapabilities(opt::Module* module);
// Analyzes |module| and records imported external instruction sets.
void AddExtInstImportIds(ir::Module* module);
void AddExtInstImportIds(opt::Module* module);
// Auxiliary object for querying SPIR-V grammar facts.
const AssemblyGrammar& grammar_;

View File

@ -23,13 +23,13 @@
namespace spvtools {
namespace opt {
using ir::Instruction;
using ir::Operand;
using opt::Instruction;
using opt::Operand;
using Words = std::vector<uint32_t>;
using OrderedUsesMap = std::unordered_map<uint32_t, Words>;
Pass::Status FlattenDecorationPass::Process(ir::IRContext* c) {
Pass::Status FlattenDecorationPass::Process(opt::IRContext* c) {
InitializeProcessing(c);
bool modified = false;

View File

@ -26,7 +26,7 @@ namespace opt {
class FlattenDecorationPass : public Pass {
public:
const char* name() const override { return "flatten-decoration"; }
Status Process(ir::IRContext*) override;
Status Process(opt::IRContext*) override;
};
} // namespace opt

View File

@ -177,10 +177,10 @@ uint32_t InstructionFolder::OperateWords(
}
}
bool InstructionFolder::FoldInstructionInternal(ir::Instruction* inst) const {
ir::IRContext* context = inst->context();
bool InstructionFolder::FoldInstructionInternal(opt::Instruction* inst) const {
opt::IRContext* context = inst->context();
auto identity_map = [](uint32_t id) { return id; };
ir::Instruction* folded_inst = FoldInstructionToConstant(inst, identity_map);
opt::Instruction* folded_inst = FoldInstructionToConstant(inst, identity_map);
if (folded_inst != nullptr) {
inst->SetOpcode(SpvOpCopyObject);
inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {folded_inst->result_id()}}});
@ -230,16 +230,16 @@ uint32_t InstructionFolder::FoldScalars(
}
bool InstructionFolder::FoldBinaryIntegerOpToConstant(
ir::Instruction* inst, std::function<uint32_t(uint32_t)> id_map,
opt::Instruction* inst, std::function<uint32_t(uint32_t)> id_map,
uint32_t* result) const {
SpvOp opcode = inst->opcode();
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_manger = context->get_constant_mgr();
uint32_t ids[2];
const analysis::IntConstant* constants[2];
for (uint32_t i = 0; i < 2; i++) {
const ir::Operand* operand = &inst->GetInOperand(i);
const opt::Operand* operand = &inst->GetInOperand(i);
if (operand->type != SPV_OPERAND_TYPE_ID) {
return false;
}
@ -414,16 +414,16 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
}
bool InstructionFolder::FoldBinaryBooleanOpToConstant(
ir::Instruction* inst, std::function<uint32_t(uint32_t)> id_map,
opt::Instruction* inst, std::function<uint32_t(uint32_t)> id_map,
uint32_t* result) const {
SpvOp opcode = inst->opcode();
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_manger = context->get_constant_mgr();
uint32_t ids[2];
const analysis::BoolConstant* constants[2];
for (uint32_t i = 0; i < 2; i++) {
const ir::Operand* operand = &inst->GetInOperand(i);
const opt::Operand* operand = &inst->GetInOperand(i);
if (operand->type != SPV_OPERAND_TYPE_ID) {
return false;
}
@ -463,7 +463,7 @@ bool InstructionFolder::FoldBinaryBooleanOpToConstant(
}
bool InstructionFolder::FoldIntegerOpToConstant(
ir::Instruction* inst, std::function<uint32_t(uint32_t)> id_map,
opt::Instruction* inst, std::function<uint32_t(uint32_t)> id_map,
uint32_t* result) const {
assert(IsFoldableOpcode(inst->opcode()) &&
"Unhandled instruction opcode in FoldScalars");
@ -572,9 +572,9 @@ bool InstructionFolder::IsFoldableConstant(
return cst->AsNullConstant() != nullptr;
}
ir::Instruction* InstructionFolder::FoldInstructionToConstant(
ir::Instruction* inst, std::function<uint32_t(uint32_t)> id_map) const {
ir::IRContext* context = inst->context();
opt::Instruction* InstructionFolder::FoldInstructionToConstant(
opt::Instruction* inst, std::function<uint32_t(uint32_t)> id_map) const {
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
if (!inst->IsFoldableByFoldScalar() &&
@ -602,7 +602,7 @@ ir::Instruction* InstructionFolder::FoldInstructionToConstant(
GetConstantFoldingRules().GetRulesForOpcode(inst->opcode())) {
folded_const = rule(inst, constants);
if (folded_const != nullptr) {
ir::Instruction* const_inst =
opt::Instruction* const_inst =
const_mgr->GetDefiningInstruction(folded_const, inst->type_id());
assert(const_inst->type_id() == inst->type_id());
// May be a new instruction that needs to be analysed.
@ -627,14 +627,14 @@ ir::Instruction* InstructionFolder::FoldInstructionToConstant(
if (successful) {
const analysis::Constant* result_const =
const_mgr->GetConstant(const_mgr->GetType(inst), {result_val});
ir::Instruction* folded_inst =
opt::Instruction* folded_inst =
const_mgr->GetDefiningInstruction(result_const, inst->type_id());
return folded_inst;
}
return nullptr;
}
bool InstructionFolder::IsFoldableType(ir::Instruction* type_inst) const {
bool InstructionFolder::IsFoldableType(opt::Instruction* type_inst) const {
// Support 32-bit integers.
if (type_inst->opcode() == SpvOpTypeInt) {
return type_inst->GetSingleWordInOperand(0) == 32;
@ -647,9 +647,9 @@ bool InstructionFolder::IsFoldableType(ir::Instruction* type_inst) const {
return false;
}
bool InstructionFolder::FoldInstruction(ir::Instruction* inst) const {
bool InstructionFolder::FoldInstruction(opt::Instruction* inst) const {
bool modified = false;
ir::Instruction* folded_inst(inst);
opt::Instruction* folded_inst(inst);
while (folded_inst->opcode() != SpvOpCopyObject &&
FoldInstructionInternal(&*folded_inst)) {
modified = true;

View File

@ -66,7 +66,7 @@ class InstructionFolder {
// Returns true if |FoldInstructionToConstant| could fold an instruction whose
// result type is |type_inst|.
bool IsFoldableType(ir::Instruction* type_inst) const;
bool IsFoldableType(opt::Instruction* type_inst) const;
// Tries to fold |inst| to a single constant, when the input ids to |inst|
// have been substituted using |id_map|. Returns a pointer to the OpConstant*
@ -77,8 +77,8 @@ class InstructionFolder {
// can be used for things like CCP where it is known that some ids contain a
// constant, but the instruction itself has not been updated yet. This can
// map those ids to the appropriate constants.
ir::Instruction* FoldInstructionToConstant(
ir::Instruction* inst, std::function<uint32_t(uint32_t)> id_map) const;
opt::Instruction* FoldInstructionToConstant(
opt::Instruction* inst, std::function<uint32_t(uint32_t)> id_map) const;
// Returns true if |inst| can be folded into a simpler instruction.
// If |inst| can be simplified, |inst| is overwritten with the simplified
// instruction reusing the same result id.
@ -90,7 +90,7 @@ class InstructionFolder {
// 1) An OpPhi becomes and OpCopyObject - If there are OpPhi instruction after
// |inst| in a basic block then this is invalid. The caller must fix this
// up.
bool FoldInstruction(ir::Instruction* inst) const;
bool FoldInstruction(opt::Instruction* inst) const;
// Return true if this opcode has a const folding rule associtated with it.
bool HasConstFoldingRule(SpvOp opcode) const {
@ -126,7 +126,7 @@ class InstructionFolder {
uint32_t OperateWords(SpvOp opcode,
const std::vector<uint32_t>& operand_words) const;
bool FoldInstructionInternal(ir::Instruction* inst) const;
bool FoldInstructionInternal(opt::Instruction* inst) const;
// Returns true if |inst| is a binary operation that takes two integers as
// parameters and folds to a constant that can be represented as an unsigned
@ -134,7 +134,7 @@ class InstructionFolder {
// folded, the resulting value is returned in |*result|. Valid result types
// for the instruction are any integer (signed or unsigned) with 32-bits or
// less, or a boolean value.
bool FoldBinaryIntegerOpToConstant(ir::Instruction* inst,
bool FoldBinaryIntegerOpToConstant(opt::Instruction* inst,
std::function<uint32_t(uint32_t)> id_map,
uint32_t* result) const;
@ -142,7 +142,7 @@ class InstructionFolder {
// folds
// to a constant boolean value when the ids have been replaced using |id_map|.
// If |inst| can be folded, the result value is returned in |*result|.
bool FoldBinaryBooleanOpToConstant(ir::Instruction* inst,
bool FoldBinaryBooleanOpToConstant(opt::Instruction* inst,
std::function<uint32_t(uint32_t)> id_map,
uint32_t* result) const;
@ -150,7 +150,7 @@ class InstructionFolder {
// substituted using id_map. If it can, the value is returned in |result|. If
// not, |result| is unchanged. It is assumed that not all operands are
// constant. Those cases are handled by |FoldScalar|.
bool FoldIntegerOpToConstant(ir::Instruction* inst,
bool FoldIntegerOpToConstant(opt::Instruction* inst,
std::function<uint32_t(uint32_t)> id_map,
uint32_t* result) const;

View File

@ -27,17 +27,17 @@ namespace spvtools {
namespace opt {
Pass::Status FoldSpecConstantOpAndCompositePass::Process(
ir::IRContext* irContext) {
opt::IRContext* irContext) {
Initialize(irContext);
return ProcessImpl(irContext);
}
void FoldSpecConstantOpAndCompositePass::Initialize(ir::IRContext* irContext) {
void FoldSpecConstantOpAndCompositePass::Initialize(opt::IRContext* irContext) {
InitializeProcessing(irContext);
}
Pass::Status FoldSpecConstantOpAndCompositePass::ProcessImpl(
ir::IRContext* irContext) {
opt::IRContext* irContext) {
bool modified = false;
// Traverse through all the constant defining instructions. For Normal
// Constants whose values are determined and do not depend on OpUndef
@ -59,13 +59,13 @@ Pass::Status FoldSpecConstantOpAndCompositePass::ProcessImpl(
// the dependee Spec Constants, all its dependent constants must have been
// processed and all its dependent Spec Constants should have been folded if
// possible.
ir::Module::inst_iterator next_inst = irContext->types_values_begin();
for (ir::Module::inst_iterator inst_iter = next_inst;
opt::Module::inst_iterator next_inst = irContext->types_values_begin();
for (opt::Module::inst_iterator inst_iter = next_inst;
// Need to re-evaluate the end iterator since we may modify the list of
// instructions in this section of the module as the process goes.
inst_iter != irContext->types_values_end(); inst_iter = next_inst) {
++next_inst;
ir::Instruction* inst = &*inst_iter;
opt::Instruction* inst = &*inst_iter;
// Collect constant values of normal constants and process the
// OpSpecConstantOp and OpSpecConstantComposite instructions if possible.
// The constant values will be stored in analysis::Constant instances.
@ -121,9 +121,9 @@ Pass::Status FoldSpecConstantOpAndCompositePass::ProcessImpl(
}
bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp(
ir::Module::inst_iterator* pos) {
ir::Instruction* inst = &**pos;
ir::Instruction* folded_inst = nullptr;
opt::Module::inst_iterator* pos) {
opt::Instruction* inst = &**pos;
opt::Instruction* folded_inst = nullptr;
assert(inst->GetInOperand(0).type ==
SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER &&
"The first in-operand of OpSpecContantOp instruction must be of "
@ -161,16 +161,16 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp(
uint32_t FoldSpecConstantOpAndCompositePass::GetTypeComponent(
uint32_t typeId, uint32_t element) const {
ir::Instruction* type = context()->get_def_use_mgr()->GetDef(typeId);
opt::Instruction* type = context()->get_def_use_mgr()->GetDef(typeId);
uint32_t subtype = type->GetTypeComponent(element);
assert(subtype != 0);
return subtype;
}
ir::Instruction* FoldSpecConstantOpAndCompositePass::DoCompositeExtract(
ir::Module::inst_iterator* pos) {
ir::Instruction* inst = &**pos;
opt::Instruction* FoldSpecConstantOpAndCompositePass::DoCompositeExtract(
opt::Module::inst_iterator* pos) {
opt::Instruction* inst = &**pos;
assert(inst->NumInOperands() - 1 >= 2 &&
"OpSpecConstantOp CompositeExtract requires at least two non-type "
"non-opcode operands.");
@ -218,9 +218,9 @@ ir::Instruction* FoldSpecConstantOpAndCompositePass::DoCompositeExtract(
current_const, pos);
}
ir::Instruction* FoldSpecConstantOpAndCompositePass::DoVectorShuffle(
ir::Module::inst_iterator* pos) {
ir::Instruction* inst = &**pos;
opt::Instruction* FoldSpecConstantOpAndCompositePass::DoVectorShuffle(
opt::Module::inst_iterator* pos) {
opt::Instruction* inst = &**pos;
analysis::Vector* result_vec_type =
context()->get_constant_mgr()->GetType(inst)->AsVector();
assert(inst->NumInOperands() - 1 > 2 &&
@ -323,9 +323,9 @@ bool IsValidTypeForComponentWiseOperation(const analysis::Type* type) {
}
} // namespace
ir::Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation(
ir::Module::inst_iterator* pos) {
const ir::Instruction* inst = &**pos;
opt::Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation(
opt::Module::inst_iterator* pos) {
const opt::Instruction* inst = &**pos;
const analysis::Type* result_type =
context()->get_constant_mgr()->GetType(inst);
SpvOp spec_opcode = static_cast<SpvOp>(inst->GetSingleWordInOperand(0));
@ -334,7 +334,7 @@ ir::Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation(
if (!std::all_of(
inst->cbegin(), inst->cend(),
[&operands, this](const ir::Operand& o) {
[&operands, this](const opt::Operand& o) {
// skip the operands that is not an id.
if (o.type != spv_operand_type_t::SPV_OPERAND_TYPE_ID) return true;
uint32_t id = o.words.front();

View File

@ -36,19 +36,19 @@ class FoldSpecConstantOpAndCompositePass : public Pass {
const char* name() const override { return "fold-spec-const-op-composite"; }
Status Process(ir::IRContext* irContext) override;
Status Process(opt::IRContext* irContext) override;
private:
// Initializes the type manager, def-use manager and get the maximal id used
// in the module.
void Initialize(ir::IRContext* irContext);
void Initialize(opt::IRContext* irContext);
// The real entry of processing. Iterates through the types-constants-globals
// section of the given module, finds the Spec Constants defined with
// OpSpecConstantOp and OpSpecConstantComposite instructions. If the result
// value of those spec constants can be folded, fold them to their
// corresponding normal constants.
Status ProcessImpl(ir::IRContext* irContext);
Status ProcessImpl(opt::IRContext* irContext);
// Processes the OpSpecConstantOp instruction pointed by the given
// instruction iterator, folds it to normal constants if possible. Returns
@ -59,26 +59,27 @@ class FoldSpecConstantOpAndCompositePass : public Pass {
// folding is done successfully, the original OpSpecConstantOp instruction
// will be changed to Nop and new folded instruction will be inserted before
// it.
bool ProcessOpSpecConstantOp(ir::Module::inst_iterator* pos);
bool ProcessOpSpecConstantOp(opt::Module::inst_iterator* pos);
// Try to fold the OpSpecConstantOp CompositeExtract instruction pointed by
// the given instruction iterator to a normal constant defining instruction.
// Returns the pointer to the new constant defining instruction if succeeded.
// Otherwise returns nullptr.
ir::Instruction* DoCompositeExtract(ir::Module::inst_iterator* inst_iter_ptr);
opt::Instruction* DoCompositeExtract(
opt::Module::inst_iterator* inst_iter_ptr);
// Try to fold the OpSpecConstantOp VectorShuffle instruction pointed by the
// given instruction iterator to a normal constant defining instruction.
// Returns the pointer to the new constant defining instruction if succeeded.
// Otherwise return nullptr.
ir::Instruction* DoVectorShuffle(ir::Module::inst_iterator* inst_iter_ptr);
opt::Instruction* DoVectorShuffle(opt::Module::inst_iterator* inst_iter_ptr);
// Try to fold the OpSpecConstantOp <component wise operations> instruction
// pointed by the given instruction iterator to a normal constant defining
// instruction. Returns the pointer to the new constant defining instruction
// if succeeded, otherwise return nullptr.
ir::Instruction* DoComponentWiseOperation(
ir::Module::inst_iterator* inst_iter_ptr);
opt::Instruction* DoComponentWiseOperation(
opt::Module::inst_iterator* inst_iter_ptr);
// Returns the |element|'th subtype of |type|.
//

View File

@ -75,9 +75,9 @@ const analysis::Constant* ConstInput(
return constants[0] ? constants[0] : constants[1];
}
ir::Instruction* NonConstInput(ir::IRContext* context,
const analysis::Constant* c,
ir::Instruction* inst) {
opt::Instruction* NonConstInput(opt::IRContext* context,
const analysis::Constant* c,
opt::Instruction* inst) {
uint32_t in_op = c ? 1u : 0u;
return context->get_def_use_mgr()->GetDef(
inst->GetSingleWordInOperand(in_op));
@ -199,10 +199,10 @@ uint32_t Reciprocal(analysis::ConstantManager* const_mgr,
// Replaces fdiv where second operand is constant with fmul.
FoldingRule ReciprocalFDiv() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFDiv);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
@ -244,17 +244,17 @@ FoldingRule ReciprocalFDiv() {
// Elides consecutive negate instructions.
FoldingRule MergeNegateArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFNegate || inst->opcode() == SpvOpSNegate);
(void)constants;
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed())
return false;
ir::Instruction* op_inst =
opt::Instruction* op_inst =
context->get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
if (HasFloatingPoint(type) && !op_inst->IsFloatingPointFoldingAllowed())
return false;
@ -279,18 +279,18 @@ FoldingRule MergeNegateArithmetic() {
// -(x / 2) = x / -2
// -(2 / x) = -2 / x
FoldingRule MergeNegateMulDivArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFNegate || inst->opcode() == SpvOpSNegate);
(void)constants;
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed())
return false;
ir::Instruction* op_inst =
opt::Instruction* op_inst =
context->get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
if (HasFloatingPoint(type) && !op_inst->IsFloatingPointFoldingAllowed())
return false;
@ -338,18 +338,18 @@ FoldingRule MergeNegateMulDivArithmetic() {
// -(x - 2) = 2 - x
// -(2 - x) = x - 2
FoldingRule MergeNegateAddSubArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFNegate || inst->opcode() == SpvOpSNegate);
(void)constants;
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed())
return false;
ir::Instruction* op_inst =
opt::Instruction* op_inst =
context->get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
if (HasFloatingPoint(type) && !op_inst->IsFloatingPointFoldingAllowed())
return false;
@ -571,10 +571,10 @@ uint32_t PerformOperation(analysis::ConstantManager* const_mgr, SpvOp opcode,
// (x * 2) * 2 = x * 4
// (2 * x) * 2 = x * 4
FoldingRule MergeMulMulArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFMul || inst->opcode() == SpvOpIMul);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
@ -587,7 +587,7 @@ FoldingRule MergeMulMulArithmetic() {
// Determine the constant input and the variable input in |inst|.
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (HasFloatingPoint(type) && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -624,10 +624,10 @@ FoldingRule MergeMulMulArithmetic() {
// (y / x) * x = y
// x * (y / x) = y
FoldingRule MergeMulDivArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFMul);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
@ -640,7 +640,7 @@ FoldingRule MergeMulDivArithmetic() {
for (uint32_t i = 0; i < 2; i++) {
uint32_t op_id = inst->GetSingleWordInOperand(i);
ir::Instruction* op_inst = def_use_mgr->GetDef(op_id);
opt::Instruction* op_inst = def_use_mgr->GetDef(op_id);
if (op_inst->opcode() == SpvOpFDiv) {
if (op_inst->GetSingleWordInOperand(1) ==
inst->GetSingleWordInOperand(1 - i)) {
@ -654,7 +654,7 @@ FoldingRule MergeMulDivArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (!other_inst->IsFloatingPointFoldingAllowed()) return false;
if (other_inst->opcode() == SpvOpFDiv) {
@ -699,10 +699,10 @@ FoldingRule MergeMulDivArithmetic() {
// (-x) * 2 = x * -2
// 2 * (-x) = x * -2
FoldingRule MergeMulNegateArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFMul || inst->opcode() == SpvOpIMul);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
@ -714,7 +714,7 @@ FoldingRule MergeMulNegateArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -740,10 +740,10 @@ FoldingRule MergeMulNegateArithmetic() {
// (4 / x) / 2 = 2 / x
// (x / 2) / 2 = x / 4
FoldingRule MergeDivDivArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFDiv);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
@ -754,7 +754,7 @@ FoldingRule MergeDivDivArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1 || HasZero(const_input1)) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (!other_inst->IsFloatingPointFoldingAllowed()) return false;
bool first_is_variable = constants[0] == nullptr;
@ -812,10 +812,10 @@ FoldingRule MergeDivDivArithmetic() {
// (x * y) / x = y
// (y * x) / x = y
FoldingRule MergeDivMulArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFDiv);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
@ -827,7 +827,7 @@ FoldingRule MergeDivMulArithmetic() {
if (width != 32 && width != 64) return false;
uint32_t op_id = inst->GetSingleWordInOperand(0);
ir::Instruction* op_inst = def_use_mgr->GetDef(op_id);
opt::Instruction* op_inst = def_use_mgr->GetDef(op_id);
if (op_inst->opcode() == SpvOpFMul) {
for (uint32_t i = 0; i < 2; i++) {
@ -843,7 +843,7 @@ FoldingRule MergeDivMulArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1 || HasZero(const_input1)) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (!other_inst->IsFloatingPointFoldingAllowed()) return false;
bool first_is_variable = constants[0] == nullptr;
@ -885,11 +885,11 @@ FoldingRule MergeDivMulArithmetic() {
// (-x) / 2 = x / -2
// 2 / (-x) = 2 / -x
FoldingRule MergeDivNegateArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFDiv || inst->opcode() == SpvOpSDiv ||
inst->opcode() == SpvOpUDiv);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
@ -901,7 +901,7 @@ FoldingRule MergeDivNegateArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -931,10 +931,10 @@ FoldingRule MergeDivNegateArithmetic() {
// (-x) + 2 = 2 - x
// 2 + (-x) = 2 - x
FoldingRule MergeAddNegateArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
bool uses_float = HasFloatingPoint(type);
@ -942,7 +942,7 @@ FoldingRule MergeAddNegateArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -965,10 +965,10 @@ FoldingRule MergeAddNegateArithmetic() {
// (-x) - 2 = -2 - x
// 2 - (-x) = x + 2
FoldingRule MergeSubNegateArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFSub || inst->opcode() == SpvOpISub);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
@ -980,7 +980,7 @@ FoldingRule MergeSubNegateArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -1014,10 +1014,10 @@ FoldingRule MergeSubNegateArithmetic() {
// 2 + (x + 2) = x + 4
// 2 + (2 + x) = x + 4
FoldingRule MergeAddAddArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
@ -1029,7 +1029,7 @@ FoldingRule MergeAddAddArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -1040,7 +1040,7 @@ FoldingRule MergeAddAddArithmetic() {
const analysis::Constant* const_input2 = ConstInput(other_constants);
if (!const_input2) return false;
ir::Instruction* non_const_input =
opt::Instruction* non_const_input =
NonConstInput(context, other_constants[0], other_inst);
uint32_t merged_id = PerformOperation(const_mgr, inst->opcode(),
const_input1, const_input2);
@ -1062,10 +1062,10 @@ FoldingRule MergeAddAddArithmetic() {
// 2 + (x - 2) = x + 0
// 2 + (2 - x) = 4 - x
FoldingRule MergeAddSubArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
@ -1077,7 +1077,7 @@ FoldingRule MergeAddSubArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -1122,10 +1122,10 @@ FoldingRule MergeAddSubArithmetic() {
// 2 - (x + 2) = 0 - x
// 2 - (2 + x) = 0 - x
FoldingRule MergeSubAddArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFSub || inst->opcode() == SpvOpISub);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
@ -1137,7 +1137,7 @@ FoldingRule MergeSubAddArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -1148,7 +1148,7 @@ FoldingRule MergeSubAddArithmetic() {
const analysis::Constant* const_input2 = ConstInput(other_constants);
if (!const_input2) return false;
ir::Instruction* non_const_input =
opt::Instruction* non_const_input =
NonConstInput(context, other_constants[0], other_inst);
// If the first operand of the sub is not a constant, swap the constants
@ -1188,10 +1188,10 @@ FoldingRule MergeSubAddArithmetic() {
// 2 - (x - 2) = 4 - x
// 2 - (2 - x) = x + 0
FoldingRule MergeSubSubArithmetic() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFSub || inst->opcode() == SpvOpISub);
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
const analysis::Type* type =
context->get_type_mgr()->GetType(inst->type_id());
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
@ -1203,7 +1203,7 @@ FoldingRule MergeSubSubArithmetic() {
const analysis::Constant* const_input1 = ConstInput(constants);
if (!const_input1) return false;
ir::Instruction* other_inst = NonConstInput(context, constants[0], inst);
opt::Instruction* other_inst = NonConstInput(context, constants[0], inst);
if (uses_float && !other_inst->IsFloatingPointFoldingAllowed())
return false;
@ -1214,7 +1214,7 @@ FoldingRule MergeSubSubArithmetic() {
const analysis::Constant* const_input2 = ConstInput(other_constants);
if (!const_input2) return false;
ir::Instruction* non_const_input =
opt::Instruction* non_const_input =
NonConstInput(context, other_constants[0], other_inst);
// Merge the constants.
@ -1255,7 +1255,7 @@ FoldingRule MergeSubSubArithmetic() {
}
FoldingRule IntMultipleBy1() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpIMul && "Wrong opcode. Should be OpIMul.");
for (uint32_t i = 0; i < 2; i++) {
@ -1281,7 +1281,7 @@ FoldingRule IntMultipleBy1() {
}
FoldingRule CompositeConstructFeedingExtract() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>&) {
// If the input to an OpCompositeExtract is an OpCompositeConstruct,
// then we can simply use the appropriate element in the construction.
@ -1290,13 +1290,13 @@ FoldingRule CompositeConstructFeedingExtract() {
analysis::DefUseManager* def_use_mgr = inst->context()->get_def_use_mgr();
analysis::TypeManager* type_mgr = inst->context()->get_type_mgr();
uint32_t cid = inst->GetSingleWordInOperand(kExtractCompositeIdInIdx);
ir::Instruction* cinst = def_use_mgr->GetDef(cid);
opt::Instruction* cinst = def_use_mgr->GetDef(cid);
if (cinst->opcode() != SpvOpCompositeConstruct) {
return false;
}
std::vector<ir::Operand> operands;
std::vector<opt::Operand> operands;
analysis::Type* composite_type = type_mgr->GetType(cinst->type_id());
if (composite_type->AsVector() == nullptr) {
// Get the element being extracted from the OpCompositeConstruct
@ -1321,7 +1321,7 @@ FoldingRule CompositeConstructFeedingExtract() {
for (uint32_t construct_index = 0;
construct_index < cinst->NumInOperands(); ++construct_index) {
uint32_t element_id = cinst->GetSingleWordInOperand(construct_index);
ir::Instruction* element_def = def_use_mgr->GetDef(element_id);
opt::Instruction* element_def = def_use_mgr->GetDef(element_id);
analysis::Vector* element_type =
type_mgr->GetType(element_def->type_id())->AsVector();
if (element_type) {
@ -1366,7 +1366,7 @@ FoldingRule CompositeExtractFeedingConstruct() {
//
// This is a common code pattern because of the way that scalar replacement
// works.
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpCompositeConstruct &&
"Wrong opcode. Should be OpCompositeConstruct.");
@ -1379,7 +1379,7 @@ FoldingRule CompositeExtractFeedingConstruct() {
// - all extract from the same id.
for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
uint32_t element_id = inst->GetSingleWordInOperand(i);
ir::Instruction* element_inst = def_use_mgr->GetDef(element_id);
opt::Instruction* element_inst = def_use_mgr->GetDef(element_id);
if (element_inst->opcode() != SpvOpCompositeExtract) {
return false;
@ -1404,7 +1404,7 @@ FoldingRule CompositeExtractFeedingConstruct() {
// The last check it to see that the object being extracted from is the
// correct type.
ir::Instruction* original_inst = def_use_mgr->GetDef(original_id);
opt::Instruction* original_inst = def_use_mgr->GetDef(original_id);
if (original_inst->type_id() != inst->type_id()) {
return false;
}
@ -1417,13 +1417,13 @@ FoldingRule CompositeExtractFeedingConstruct() {
}
FoldingRule InsertFeedingExtract() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpCompositeExtract &&
"Wrong opcode. Should be OpCompositeExtract.");
analysis::DefUseManager* def_use_mgr = inst->context()->get_def_use_mgr();
uint32_t cid = inst->GetSingleWordInOperand(kExtractCompositeIdInIdx);
ir::Instruction* cinst = def_use_mgr->GetDef(cid);
opt::Instruction* cinst = def_use_mgr->GetDef(cid);
if (cinst->opcode() != SpvOpCompositeInsert) {
return false;
@ -1461,7 +1461,7 @@ FoldingRule InsertFeedingExtract() {
// Extracting an element of the value that was inserted. Extract from
// that value directly.
if (i + 1 == cinst->NumInOperands()) {
std::vector<ir::Operand> operands;
std::vector<opt::Operand> operands;
operands.push_back(
{SPV_OPERAND_TYPE_ID,
{cinst->GetSingleWordInOperand(kInsertObjectIdInIdx)}});
@ -1475,7 +1475,7 @@ FoldingRule InsertFeedingExtract() {
// Extracting a value that is disjoint from the element being inserted.
// Rewrite the extract to use the composite input to the insert.
std::vector<ir::Operand> operands;
std::vector<opt::Operand> operands;
operands.push_back(
{SPV_OPERAND_TYPE_ID,
{cinst->GetSingleWordInOperand(kInsertCompositeIdInIdx)}});
@ -1492,21 +1492,21 @@ FoldingRule InsertFeedingExtract() {
// operands of the VectorShuffle. We just need to adjust the index in the
// extract instruction.
FoldingRule VectorShuffleFeedingExtract() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpCompositeExtract &&
"Wrong opcode. Should be OpCompositeExtract.");
analysis::DefUseManager* def_use_mgr = inst->context()->get_def_use_mgr();
analysis::TypeManager* type_mgr = inst->context()->get_type_mgr();
uint32_t cid = inst->GetSingleWordInOperand(kExtractCompositeIdInIdx);
ir::Instruction* cinst = def_use_mgr->GetDef(cid);
opt::Instruction* cinst = def_use_mgr->GetDef(cid);
if (cinst->opcode() != SpvOpVectorShuffle) {
return false;
}
// Find the size of the first vector operand of the VectorShuffle
ir::Instruction* first_input =
opt::Instruction* first_input =
def_use_mgr->GetDef(cinst->GetSingleWordInOperand(0));
analysis::Type* first_input_type =
type_mgr->GetType(first_input->type_id());
@ -1541,16 +1541,17 @@ FoldingRule VectorShuffleFeedingExtract() {
// operands of the FMix.
FoldingRule FMixFeedingExtract() {
return
[](ir::Instruction* inst, const std::vector<const analysis::Constant*>&) {
[](opt::Instruction* inst,
const std::vector<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpCompositeExtract &&
"Wrong opcode. Should be OpCompositeExtract.");
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
uint32_t composite_id =
inst->GetSingleWordInOperand(kExtractCompositeIdInIdx);
ir::Instruction* composite_inst = def_use_mgr->GetDef(composite_id);
opt::Instruction* composite_inst = def_use_mgr->GetDef(composite_id);
if (composite_inst->opcode() != SpvOpExtInst) {
return false;
@ -1568,7 +1569,7 @@ FoldingRule FMixFeedingExtract() {
// Get the |a| for the FMix instruction.
uint32_t a_id = composite_inst->GetSingleWordInOperand(kFMixAIdInIdx);
std::unique_ptr<ir::Instruction> a(inst->Clone(inst->context()));
std::unique_ptr<opt::Instruction> a(inst->Clone(inst->context()));
a->SetInOperand(kExtractCompositeIdInIdx, {a_id});
context->get_instruction_folder().FoldInstruction(a.get());
@ -1612,42 +1613,42 @@ FoldingRule FMixFeedingExtract() {
FoldingRule RedundantPhi() {
// An OpPhi instruction where all values are the same or the result of the phi
// itself, can be replaced by the value itself.
return
[](ir::Instruction* inst, const std::vector<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpPhi && "Wrong opcode. Should be OpPhi.");
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpPhi && "Wrong opcode. Should be OpPhi.");
uint32_t incoming_value = 0;
uint32_t incoming_value = 0;
for (uint32_t i = 0; i < inst->NumInOperands(); i += 2) {
uint32_t op_id = inst->GetSingleWordInOperand(i);
if (op_id == inst->result_id()) {
continue;
}
for (uint32_t i = 0; i < inst->NumInOperands(); i += 2) {
uint32_t op_id = inst->GetSingleWordInOperand(i);
if (op_id == inst->result_id()) {
continue;
}
if (incoming_value == 0) {
incoming_value = op_id;
} else if (op_id != incoming_value) {
// Found two possible value. Can't simplify.
return false;
}
}
if (incoming_value == 0) {
incoming_value = op_id;
} else if (op_id != incoming_value) {
// Found two possible value. Can't simplify.
return false;
}
}
if (incoming_value == 0) {
// Code looks invalid. Don't do anything.
return false;
}
if (incoming_value == 0) {
// Code looks invalid. Don't do anything.
return false;
}
// We have a single incoming value. Simplify using that value.
inst->SetOpcode(SpvOpCopyObject);
inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {incoming_value}}});
return true;
};
// We have a single incoming value. Simplify using that value.
inst->SetOpcode(SpvOpCopyObject);
inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {incoming_value}}});
return true;
};
}
FoldingRule RedundantSelect() {
// An OpSelect instruction where both values are the same or the condition is
// constant can be replaced by one of the values
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpSelect &&
"Wrong opcode. Should be OpSelect.");
@ -1683,7 +1684,7 @@ FoldingRule RedundantSelect() {
return true;
} else {
// Convert to a vector shuffle.
std::vector<ir::Operand> ops;
std::vector<opt::Operand> ops;
ops.push_back({SPV_OPERAND_TYPE_ID, {true_id}});
ops.push_back({SPV_OPERAND_TYPE_ID, {false_id}});
const analysis::VectorConstant* vector_const =
@ -1763,7 +1764,7 @@ FloatConstantKind getFloatConstantKind(const analysis::Constant* constant) {
}
FoldingRule RedundantFAdd() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFAdd && "Wrong opcode. Should be OpFAdd.");
assert(constants.size() == 2);
@ -1788,7 +1789,7 @@ FoldingRule RedundantFAdd() {
}
FoldingRule RedundantFSub() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFSub && "Wrong opcode. Should be OpFSub.");
assert(constants.size() == 2);
@ -1819,7 +1820,7 @@ FoldingRule RedundantFSub() {
}
FoldingRule RedundantFMul() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFMul && "Wrong opcode. Should be OpFMul.");
assert(constants.size() == 2);
@ -1852,7 +1853,7 @@ FoldingRule RedundantFMul() {
}
FoldingRule RedundantFDiv() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpFDiv && "Wrong opcode. Should be OpFDiv.");
assert(constants.size() == 2);
@ -1883,7 +1884,7 @@ FoldingRule RedundantFDiv() {
}
FoldingRule RedundantFMix() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpExtInst &&
"Wrong opcode. Should be OpExtInst.");
@ -1920,11 +1921,11 @@ FoldingRule RedundantFMix() {
// This rule look for a dot with a constant vector containing a single 1 and
// the rest 0s. This is the same as doing an extract.
FoldingRule DotProductDoingExtract() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants) {
assert(inst->opcode() == SpvOpDot && "Wrong opcode. Should be OpDot.");
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
if (!inst->IsFloatingPointFoldingAllowed()) {
@ -1976,7 +1977,7 @@ FoldingRule DotProductDoingExtract() {
continue;
}
std::vector<ir::Operand> operands;
std::vector<opt::Operand> operands;
operands.push_back(
{SPV_OPERAND_TYPE_ID, {inst->GetSingleWordInOperand(1u - i)}});
operands.push_back(
@ -1995,11 +1996,11 @@ FoldingRule DotProductDoingExtract() {
// TODO: We can do something similar for OpImageWrite, but checking for volatile
// is complicated. Waiting to see if it is needed.
FoldingRule StoringUndef() {
return [](ir::Instruction* inst,
return [](opt::Instruction* inst,
const std::vector<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpStore && "Wrong opcode. Should be OpStore.");
ir::IRContext* context = inst->context();
opt::IRContext* context = inst->context();
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
// If this is a volatile store, the store cannot be removed.
@ -2010,7 +2011,7 @@ FoldingRule StoringUndef() {
}
uint32_t object_id = inst->GetSingleWordInOperand(kStoreObjectInIdx);
ir::Instruction* object_inst = def_use_mgr->GetDef(object_id);
opt::Instruction* object_inst = def_use_mgr->GetDef(object_id);
if (object_inst->opcode() == SpvOpUndef) {
inst->ToNop();
return true;

View File

@ -52,7 +52,7 @@ namespace opt {
// the later rules will not be attempted.
using FoldingRule = std::function<bool(
ir::Instruction* inst,
opt::Instruction* inst,
const std::vector<const analysis::Constant*>& constants)>;
class FoldingRules {

View File

@ -18,10 +18,10 @@
namespace spvtools {
namespace opt {
Pass::Status FreezeSpecConstantValuePass::Process(ir::IRContext* irContext) {
Pass::Status FreezeSpecConstantValuePass::Process(opt::IRContext* irContext) {
bool modified = false;
irContext->module()->ForEachInst(
[&modified, irContext](ir::Instruction* inst) {
[&modified, irContext](opt::Instruction* inst) {
switch (inst->opcode()) {
case SpvOp::SpvOpSpecConstant:
inst->SetOpcode(SpvOp::SpvOpConstant);

View File

@ -26,7 +26,7 @@ namespace opt {
class FreezeSpecConstantValuePass : public Pass {
public:
const char* name() const override { return "freeze-spec-const"; }
Status Process(ir::IRContext*) override;
Status Process(opt::IRContext*) override;
};
} // namespace opt

View File

@ -18,7 +18,7 @@
#include <sstream>
namespace spvtools {
namespace ir {
namespace opt {
Function* Function::Clone(IRContext* ctx) const {
Function* clone =
@ -96,7 +96,7 @@ std::ostream& operator<<(std::ostream& str, const Function& func) {
std::string Function::PrettyPrint(uint32_t options) const {
std::ostringstream str;
ForEachInst([&str, options](const ir::Instruction* inst) {
ForEachInst([&str, options](const opt::Instruction* inst) {
str << inst->PrettyPrint(options);
if (inst->opcode() != SpvOpFunctionEnd) {
str << std::endl;
@ -105,5 +105,5 @@ std::string Function::PrettyPrint(uint32_t options) const {
return str.str();
}
} // namespace ir
} // namespace opt
} // namespace spvtools

View File

@ -26,7 +26,7 @@
#include "iterator.h"
namespace spvtools {
namespace ir {
namespace opt {
class CFG;
class IRContext;
@ -102,7 +102,7 @@ class Function {
// Returns an iterator to the basic block |id|.
iterator FindBlock(uint32_t bb_id) {
return std::find_if(begin(), end(), [bb_id](const ir::BasicBlock& it_bb) {
return std::find_if(begin(), end(), [bb_id](const opt::BasicBlock& it_bb) {
return bb_id == it_bb.id();
});
}
@ -122,8 +122,8 @@ class Function {
// Returns the context of the current function.
IRContext* context() const { return def_inst_->context(); }
BasicBlock* InsertBasicBlockAfter(std::unique_ptr<ir::BasicBlock>&& new_block,
BasicBlock* position);
BasicBlock* InsertBasicBlockAfter(
std::unique_ptr<opt::BasicBlock>&& new_block, BasicBlock* position);
// Pretty-prints all the basic blocks in this function into a std::string.
//
@ -192,7 +192,7 @@ inline void Function::SetFunctionEnd(std::unique_ptr<Instruction> end_inst) {
end_inst_ = std::move(end_inst);
}
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_CONSTRUCTS_H_

View File

@ -19,18 +19,18 @@
namespace spvtools {
namespace opt {
Pass::Status IfConversion::Process(ir::IRContext* c) {
Pass::Status IfConversion::Process(opt::IRContext* c) {
InitializeProcessing(c);
const ValueNumberTable& vn_table = *context()->GetValueNumberTable();
bool modified = false;
std::vector<ir::Instruction*> to_kill;
std::vector<opt::Instruction*> to_kill;
for (auto& func : *get_module()) {
DominatorAnalysis* dominators = context()->GetDominatorAnalysis(&func);
for (auto& block : func) {
// Check if it is possible for |block| to have phis that can be
// transformed.
ir::BasicBlock* common = nullptr;
opt::BasicBlock* common = nullptr;
if (!CheckBlock(&block, dominators, &common)) continue;
// Get an insertion point.
@ -41,11 +41,11 @@ Pass::Status IfConversion::Process(ir::IRContext* c) {
InstructionBuilder builder(
context(), &*iter,
ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping);
opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping);
block.ForEachPhiInst([this, &builder, &modified, &common, &to_kill,
dominators, &block,
&vn_table](ir::Instruction* phi) {
&vn_table](opt::Instruction* phi) {
// This phi is not compatible, but subsequent phis might be.
if (!CheckType(phi->type_id())) return;
@ -59,13 +59,13 @@ Pass::Status IfConversion::Process(ir::IRContext* c) {
// branches. If |then_block| dominates |inc0| or if the true edge
// branches straight to this block and |common| is |inc0|, then |inc0|
// is on the true branch. Otherwise the |inc1| is on the true branch.
ir::BasicBlock* inc0 = GetIncomingBlock(phi, 0u);
ir::Instruction* branch = common->terminator();
opt::BasicBlock* inc0 = GetIncomingBlock(phi, 0u);
opt::Instruction* branch = common->terminator();
uint32_t condition = branch->GetSingleWordInOperand(0u);
ir::BasicBlock* then_block =
opt::BasicBlock* then_block =
GetBlock(branch->GetSingleWordInOperand(1u));
ir::Instruction* true_value = nullptr;
ir::Instruction* false_value = nullptr;
opt::Instruction* true_value = nullptr;
opt::Instruction* false_value = nullptr;
if ((then_block == &block && inc0 == common) ||
dominators->Dominates(then_block, inc0)) {
true_value = GetIncomingValue(phi, 0u);
@ -75,14 +75,15 @@ Pass::Status IfConversion::Process(ir::IRContext* c) {
false_value = GetIncomingValue(phi, 0u);
}
ir::BasicBlock* true_def_block = context()->get_instr_block(true_value);
ir::BasicBlock* false_def_block =
opt::BasicBlock* true_def_block =
context()->get_instr_block(true_value);
opt::BasicBlock* false_def_block =
context()->get_instr_block(false_value);
uint32_t true_vn = vn_table.GetValueNumber(true_value);
uint32_t false_vn = vn_table.GetValueNumber(false_value);
if (true_vn != 0 && true_vn == false_vn) {
ir::Instruction* inst_to_use = nullptr;
opt::Instruction* inst_to_use = nullptr;
// Try to pick an instruction that is not in a side node. If we can't
// pick either the true for false branch as long as they can be
@ -125,9 +126,9 @@ Pass::Status IfConversion::Process(ir::IRContext* c) {
condition = SplatCondition(vec_data_ty, condition, &builder);
}
ir::Instruction* select = builder.AddSelect(phi->type_id(), condition,
true_value->result_id(),
false_value->result_id());
opt::Instruction* select = builder.AddSelect(phi->type_id(), condition,
true_value->result_id(),
false_value->result_id());
context()->ReplaceAllUsesWith(phi->result_id(), select->result_id());
to_kill.push_back(phi);
modified = true;
@ -144,18 +145,18 @@ Pass::Status IfConversion::Process(ir::IRContext* c) {
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
bool IfConversion::CheckBlock(ir::BasicBlock* block,
bool IfConversion::CheckBlock(opt::BasicBlock* block,
DominatorAnalysis* dominators,
ir::BasicBlock** common) {
opt::BasicBlock** common) {
const std::vector<uint32_t>& preds = cfg()->preds(block->id());
// TODO(alan-baker): Extend to more than two predecessors
if (preds.size() != 2) return false;
ir::BasicBlock* inc0 = context()->get_instr_block(preds[0]);
opt::BasicBlock* inc0 = context()->get_instr_block(preds[0]);
if (dominators->Dominates(block, inc0)) return false;
ir::BasicBlock* inc1 = context()->get_instr_block(preds[1]);
opt::BasicBlock* inc1 = context()->get_instr_block(preds[1]);
if (dominators->Dominates(block, inc1)) return false;
// All phis will have the same common dominator, so cache the result
@ -163,15 +164,16 @@ bool IfConversion::CheckBlock(ir::BasicBlock* block,
// any phi in this basic block.
*common = dominators->CommonDominator(inc0, inc1);
if (!*common || cfg()->IsPseudoEntryBlock(*common)) return false;
ir::Instruction* branch = (*common)->terminator();
opt::Instruction* branch = (*common)->terminator();
if (branch->opcode() != SpvOpBranchConditional) return false;
return true;
}
bool IfConversion::CheckPhiUsers(ir::Instruction* phi, ir::BasicBlock* block) {
bool IfConversion::CheckPhiUsers(opt::Instruction* phi,
opt::BasicBlock* block) {
return get_def_use_mgr()->WhileEachUser(phi, [block,
this](ir::Instruction* user) {
this](opt::Instruction* user) {
if (user->opcode() == SpvOpPhi && context()->get_instr_block(user) == block)
return false;
return true;
@ -194,7 +196,7 @@ uint32_t IfConversion::SplatCondition(analysis::Vector* vec_data_ty,
}
bool IfConversion::CheckType(uint32_t id) {
ir::Instruction* type = get_def_use_mgr()->GetDef(id);
opt::Instruction* type = get_def_use_mgr()->GetDef(id);
SpvOp op = type->opcode();
if (spvOpcodeIsScalarType(op) || op == SpvOpTypePointer ||
op == SpvOpTypeVector)
@ -202,26 +204,26 @@ bool IfConversion::CheckType(uint32_t id) {
return false;
}
ir::BasicBlock* IfConversion::GetBlock(uint32_t id) {
opt::BasicBlock* IfConversion::GetBlock(uint32_t id) {
return context()->get_instr_block(get_def_use_mgr()->GetDef(id));
}
ir::BasicBlock* IfConversion::GetIncomingBlock(ir::Instruction* phi,
uint32_t predecessor) {
opt::BasicBlock* IfConversion::GetIncomingBlock(opt::Instruction* phi,
uint32_t predecessor) {
uint32_t in_index = 2 * predecessor + 1;
return GetBlock(phi->GetSingleWordInOperand(in_index));
}
ir::Instruction* IfConversion::GetIncomingValue(ir::Instruction* phi,
uint32_t predecessor) {
opt::Instruction* IfConversion::GetIncomingValue(opt::Instruction* phi,
uint32_t predecessor) {
uint32_t in_index = 2 * predecessor;
return get_def_use_mgr()->GetDef(phi->GetSingleWordInOperand(in_index));
}
void IfConversion::HoistInstruction(ir::Instruction* inst,
ir::BasicBlock* target_block,
void IfConversion::HoistInstruction(opt::Instruction* inst,
opt::BasicBlock* target_block,
DominatorAnalysis* dominators) {
ir::BasicBlock* inst_block = context()->get_instr_block(inst);
opt::BasicBlock* inst_block = context()->get_instr_block(inst);
if (!inst_block) {
// This is in the header, and dominates everything.
return;
@ -239,23 +241,23 @@ void IfConversion::HoistInstruction(ir::Instruction* inst,
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
inst->ForEachInId(
[this, target_block, def_use_mgr, dominators](uint32_t* id) {
ir::Instruction* operand_inst = def_use_mgr->GetDef(*id);
opt::Instruction* operand_inst = def_use_mgr->GetDef(*id);
HoistInstruction(operand_inst, target_block, dominators);
});
ir::Instruction* insertion_pos = target_block->terminator();
opt::Instruction* insertion_pos = target_block->terminator();
if ((insertion_pos)->PreviousNode()->opcode() == SpvOpSelectionMerge) {
insertion_pos = insertion_pos->PreviousNode();
}
inst->RemoveFromList();
insertion_pos->InsertBefore(std::unique_ptr<ir::Instruction>(inst));
insertion_pos->InsertBefore(std::unique_ptr<opt::Instruction>(inst));
context()->set_instr_block(inst, target_block);
}
bool IfConversion::CanHoistInstruction(ir::Instruction* inst,
ir::BasicBlock* target_block,
bool IfConversion::CanHoistInstruction(opt::Instruction* inst,
opt::BasicBlock* target_block,
DominatorAnalysis* dominators) {
ir::BasicBlock* inst_block = context()->get_instr_block(inst);
opt::BasicBlock* inst_block = context()->get_instr_block(inst);
if (!inst_block) {
// This is in the header, and dominates everything.
return true;
@ -274,7 +276,7 @@ bool IfConversion::CanHoistInstruction(ir::Instruction* inst,
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
return inst->WhileEachInId(
[this, target_block, def_use_mgr, dominators](uint32_t* id) {
ir::Instruction* operand_inst = def_use_mgr->GetDef(*id);
opt::Instruction* operand_inst = def_use_mgr->GetDef(*id);
return CanHoistInstruction(operand_inst, target_block, dominators);
});
}

View File

@ -27,13 +27,13 @@ namespace opt {
class IfConversion : public Pass {
public:
const char* name() const override { return "if-conversion"; }
Status Process(ir::IRContext* context) override;
Status Process(opt::IRContext* context) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisDominatorAnalysis |
ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisCFG | ir::IRContext::kAnalysisNameMap;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisDominatorAnalysis |
opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisCFG | opt::IRContext::kAnalysisNameMap;
}
private:
@ -42,14 +42,16 @@ class IfConversion : public Pass {
bool CheckType(uint32_t id);
// Returns the basic block containing |id|.
ir::BasicBlock* GetBlock(uint32_t id);
opt::BasicBlock* GetBlock(uint32_t id);
// Returns the basic block for the |predecessor|'th index predecessor of
// |phi|.
ir::BasicBlock* GetIncomingBlock(ir::Instruction* phi, uint32_t predecessor);
opt::BasicBlock* GetIncomingBlock(opt::Instruction* phi,
uint32_t predecessor);
// Returns the instruction defining the |predecessor|'th index of |phi|.
ir::Instruction* GetIncomingValue(ir::Instruction* phi, uint32_t predecessor);
opt::Instruction* GetIncomingValue(opt::Instruction* phi,
uint32_t predecessor);
// Returns the id of a OpCompositeConstruct boolean vector. The composite has
// the same number of elements as |vec_data_ty| and each member is |cond|.
@ -60,26 +62,27 @@ class IfConversion : public Pass {
InstructionBuilder* builder);
// Returns true if none of |phi|'s users are in |block|.
bool CheckPhiUsers(ir::Instruction* phi, ir::BasicBlock* block);
bool CheckPhiUsers(opt::Instruction* phi, opt::BasicBlock* block);
// Returns |false| if |block| is not appropriate to transform. Only
// transforms blocks with two predecessors. Neither incoming block can be
// dominated by |block|. Both predecessors must share a common dominator that
// is terminated by a conditional branch.
bool CheckBlock(ir::BasicBlock* block, DominatorAnalysis* dominators,
ir::BasicBlock** common);
bool CheckBlock(opt::BasicBlock* block, DominatorAnalysis* dominators,
opt::BasicBlock** common);
// Moves |inst| to |target_block| if it does not already dominate the block.
// Any instructions that |inst| depends on are move if necessary. It is
// assumed that |inst| can be hoisted to |target_block| as defined by
// |CanHoistInstruction|. |dominators| is the dominator analysis for the
// function that contains |target_block|.
void HoistInstruction(ir::Instruction* inst, ir::BasicBlock* target_block,
void HoistInstruction(opt::Instruction* inst, opt::BasicBlock* target_block,
DominatorAnalysis* dominators);
// Returns true if it is legal to move |inst| and the instructions it depends
// on to |target_block| if they do not already dominate |target_block|.
bool CanHoistInstruction(ir::Instruction* inst, ir::BasicBlock* target_block,
bool CanHoistInstruction(opt::Instruction* inst,
opt::BasicBlock* target_block,
DominatorAnalysis* dominators);
};

View File

@ -19,15 +19,15 @@
namespace spvtools {
namespace opt {
bool InlineExhaustivePass::InlineExhaustive(ir::Function* func) {
bool InlineExhaustivePass::InlineExhaustive(opt::Function* func) {
bool modified = false;
// Using block iterators here because of block erasures and insertions.
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end();) {
if (IsInlinableFunctionCall(&*ii)) {
// Inline call.
std::vector<std::unique_ptr<ir::BasicBlock>> newBlocks;
std::vector<std::unique_ptr<ir::Instruction>> newVars;
std::vector<std::unique_ptr<opt::BasicBlock>> newBlocks;
std::vector<std::unique_ptr<opt::Instruction>> newVars;
GenInlineCode(&newBlocks, &newVars, ii, bi);
// If call block is replaced with more than one block, point
// succeeding phis at new last block.
@ -59,11 +59,13 @@ bool InlineExhaustivePass::InlineExhaustive(ir::Function* func) {
return modified;
}
void InlineExhaustivePass::Initialize(ir::IRContext* c) { InitializeInline(c); }
void InlineExhaustivePass::Initialize(opt::IRContext* c) {
InitializeInline(c);
}
Pass::Status InlineExhaustivePass::ProcessImpl() {
// Attempt exhaustive inlining on each entry point function in module
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return InlineExhaustive(fp);
};
bool modified = ProcessEntryPointCallTree(pfn, get_module());
@ -72,7 +74,7 @@ Pass::Status InlineExhaustivePass::ProcessImpl() {
InlineExhaustivePass::InlineExhaustivePass() {}
Pass::Status InlineExhaustivePass::Process(ir::IRContext* c) {
Pass::Status InlineExhaustivePass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -34,16 +34,16 @@ namespace opt {
class InlineExhaustivePass : public InlinePass {
public:
InlineExhaustivePass();
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
const char* name() const override { return "inline-entry-points-exhaustive"; }
private:
// Exhaustively inline all function calls in func as well as in
// all code that is inlined into func. Return true if func is modified.
bool InlineExhaustive(ir::Function* func);
bool InlineExhaustive(opt::Function* func);
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
};

View File

@ -26,7 +26,7 @@ const uint32_t kTypePointerTypeIdInIdx = 1;
} // anonymous namespace
bool InlineOpaquePass::IsOpaqueType(uint32_t typeId) {
const ir::Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
const opt::Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
switch (typeInst->opcode()) {
case SpvOpTypeSampler:
case SpvOpTypeImage:
@ -47,14 +47,14 @@ bool InlineOpaquePass::IsOpaqueType(uint32_t typeId) {
});
}
bool InlineOpaquePass::HasOpaqueArgsOrReturn(const ir::Instruction* callInst) {
bool InlineOpaquePass::HasOpaqueArgsOrReturn(const opt::Instruction* callInst) {
// Check return type
if (IsOpaqueType(callInst->type_id())) return true;
// Check args
int icnt = 0;
return !callInst->WhileEachInId([&icnt, this](const uint32_t* iid) {
if (icnt > 0) {
const ir::Instruction* argInst = get_def_use_mgr()->GetDef(*iid);
const opt::Instruction* argInst = get_def_use_mgr()->GetDef(*iid);
if (IsOpaqueType(argInst->type_id())) return false;
}
++icnt;
@ -62,15 +62,15 @@ bool InlineOpaquePass::HasOpaqueArgsOrReturn(const ir::Instruction* callInst) {
});
}
bool InlineOpaquePass::InlineOpaque(ir::Function* func) {
bool InlineOpaquePass::InlineOpaque(opt::Function* func) {
bool modified = false;
// Using block iterators here because of block erasures and insertions.
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end();) {
if (IsInlinableFunctionCall(&*ii) && HasOpaqueArgsOrReturn(&*ii)) {
// Inline call.
std::vector<std::unique_ptr<ir::BasicBlock>> newBlocks;
std::vector<std::unique_ptr<ir::Instruction>> newVars;
std::vector<std::unique_ptr<opt::BasicBlock>> newBlocks;
std::vector<std::unique_ptr<opt::Instruction>> newVars;
GenInlineCode(&newBlocks, &newVars, ii, bi);
// If call block is replaced with more than one block, point
// succeeding phis at new last block.
@ -92,18 +92,18 @@ bool InlineOpaquePass::InlineOpaque(ir::Function* func) {
return modified;
}
void InlineOpaquePass::Initialize(ir::IRContext* c) { InitializeInline(c); }
void InlineOpaquePass::Initialize(opt::IRContext* c) { InitializeInline(c); }
Pass::Status InlineOpaquePass::ProcessImpl() {
// Do opaque inlining on each function in entry point call tree
ProcessFunction pfn = [this](ir::Function* fp) { return InlineOpaque(fp); };
ProcessFunction pfn = [this](opt::Function* fp) { return InlineOpaque(fp); };
bool modified = ProcessEntryPointCallTree(pfn, get_module());
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
InlineOpaquePass::InlineOpaquePass() {}
Pass::Status InlineOpaquePass::Process(ir::IRContext* c) {
Pass::Status InlineOpaquePass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -34,7 +34,7 @@ namespace opt {
class InlineOpaquePass : public InlinePass {
public:
InlineOpaquePass();
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
const char* name() const override { return "inline-entry-points-opaque"; }
@ -43,14 +43,14 @@ class InlineOpaquePass : public InlinePass {
bool IsOpaqueType(uint32_t typeId);
// Return true if function call |callInst| has opaque argument or return type
bool HasOpaqueArgsOrReturn(const ir::Instruction* callInst);
bool HasOpaqueArgsOrReturn(const opt::Instruction* callInst);
// Inline all function calls in |func| that have opaque params or return
// type. Inline similarly all code that is inlined into func. Return true
// if func is modified.
bool InlineOpaque(ir::Function* func);
bool InlineOpaque(opt::Function* func);
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
};

View File

@ -32,7 +32,7 @@ namespace opt {
uint32_t InlinePass::AddPointerToType(uint32_t type_id,
SpvStorageClass storage_class) {
uint32_t resultId = TakeNextId();
std::unique_ptr<ir::Instruction> type_inst(new ir::Instruction(
std::unique_ptr<opt::Instruction> type_inst(new opt::Instruction(
context(), SpvOpTypePointer, 0, resultId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
{uint32_t(storage_class)}},
@ -48,8 +48,8 @@ uint32_t InlinePass::AddPointerToType(uint32_t type_id,
}
void InlinePass::AddBranch(uint32_t label_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
std::unique_ptr<opt::BasicBlock>* block_ptr) {
std::unique_ptr<opt::Instruction> newBranch(new opt::Instruction(
context(), SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
(*block_ptr)->AddInstruction(std::move(newBranch));
@ -57,8 +57,8 @@ void InlinePass::AddBranch(uint32_t label_id,
void InlinePass::AddBranchCond(uint32_t cond_id, uint32_t true_id,
uint32_t false_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
std::unique_ptr<opt::BasicBlock>* block_ptr) {
std::unique_ptr<opt::Instruction> newBranch(new opt::Instruction(
context(), SpvOpBranchConditional, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
@ -67,8 +67,8 @@ void InlinePass::AddBranchCond(uint32_t cond_id, uint32_t true_id,
}
void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newLoopMerge(new ir::Instruction(
std::unique_ptr<opt::BasicBlock>* block_ptr) {
std::unique_ptr<opt::Instruction> newLoopMerge(new opt::Instruction(
context(), SpvOpLoopMerge, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}},
@ -77,8 +77,8 @@ void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
}
void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newStore(new ir::Instruction(
std::unique_ptr<opt::BasicBlock>* block_ptr) {
std::unique_ptr<opt::Instruction> newStore(new opt::Instruction(
context(), SpvOpStore, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}}));
@ -86,16 +86,16 @@ void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id,
}
void InlinePass::AddLoad(uint32_t type_id, uint32_t resultId, uint32_t ptr_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newLoad(new ir::Instruction(
std::unique_ptr<opt::BasicBlock>* block_ptr) {
std::unique_ptr<opt::Instruction> newLoad(new opt::Instruction(
context(), SpvOpLoad, type_id, resultId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}}}));
(*block_ptr)->AddInstruction(std::move(newLoad));
}
std::unique_ptr<ir::Instruction> InlinePass::NewLabel(uint32_t label_id) {
std::unique_ptr<ir::Instruction> newLabel(
new ir::Instruction(context(), SpvOpLabel, 0, label_id, {}));
std::unique_ptr<opt::Instruction> InlinePass::NewLabel(uint32_t label_id) {
std::unique_ptr<opt::Instruction> newLabel(
new opt::Instruction(context(), SpvOpLabel, 0, label_id, {}));
return newLabel;
}
@ -114,26 +114,26 @@ uint32_t InlinePass::GetFalseId() {
}
void InlinePass::MapParams(
ir::Function* calleeFn, ir::BasicBlock::iterator call_inst_itr,
opt::Function* calleeFn, opt::BasicBlock::iterator call_inst_itr,
std::unordered_map<uint32_t, uint32_t>* callee2caller) {
int param_idx = 0;
calleeFn->ForEachParam(
[&call_inst_itr, &param_idx, &callee2caller](const ir::Instruction* cpi) {
const uint32_t pid = cpi->result_id();
(*callee2caller)[pid] = call_inst_itr->GetSingleWordOperand(
kSpvFunctionCallArgumentId + param_idx);
++param_idx;
});
calleeFn->ForEachParam([&call_inst_itr, &param_idx,
&callee2caller](const opt::Instruction* cpi) {
const uint32_t pid = cpi->result_id();
(*callee2caller)[pid] = call_inst_itr->GetSingleWordOperand(
kSpvFunctionCallArgumentId + param_idx);
++param_idx;
});
}
void InlinePass::CloneAndMapLocals(
ir::Function* calleeFn,
std::vector<std::unique_ptr<ir::Instruction>>* new_vars,
opt::Function* calleeFn,
std::vector<std::unique_ptr<opt::Instruction>>* new_vars,
std::unordered_map<uint32_t, uint32_t>* callee2caller) {
auto callee_block_itr = calleeFn->begin();
auto callee_var_itr = callee_block_itr->begin();
while (callee_var_itr->opcode() == SpvOp::SpvOpVariable) {
std::unique_ptr<ir::Instruction> var_inst(
std::unique_ptr<opt::Instruction> var_inst(
callee_var_itr->Clone(callee_var_itr->context()));
uint32_t newId = TakeNextId();
get_decoration_mgr()->CloneDecorations(callee_var_itr->result_id(), newId);
@ -145,8 +145,8 @@ void InlinePass::CloneAndMapLocals(
}
uint32_t InlinePass::CreateReturnVar(
ir::Function* calleeFn,
std::vector<std::unique_ptr<ir::Instruction>>* new_vars) {
opt::Function* calleeFn,
std::vector<std::unique_ptr<opt::Instruction>>* new_vars) {
uint32_t returnVarId = 0;
const uint32_t calleeTypeId = calleeFn->type_id();
analysis::Type* calleeType = context()->get_type_mgr()->GetType(calleeTypeId);
@ -158,7 +158,7 @@ uint32_t InlinePass::CreateReturnVar(
returnVarTypeId = AddPointerToType(calleeTypeId, SpvStorageClassFunction);
// Add return var to new function scope variables.
returnVarId = TakeNextId();
std::unique_ptr<ir::Instruction> var_inst(new ir::Instruction(
std::unique_ptr<opt::Instruction> var_inst(new opt::Instruction(
context(), SpvOpVariable, returnVarTypeId, returnVarId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS,
{SpvStorageClassFunction}}}));
@ -168,15 +168,15 @@ uint32_t InlinePass::CreateReturnVar(
return returnVarId;
}
bool InlinePass::IsSameBlockOp(const ir::Instruction* inst) const {
bool InlinePass::IsSameBlockOp(const opt::Instruction* inst) const {
return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage;
}
void InlinePass::CloneSameBlockOps(
std::unique_ptr<ir::Instruction>* inst,
std::unique_ptr<opt::Instruction>* inst,
std::unordered_map<uint32_t, uint32_t>* postCallSB,
std::unordered_map<uint32_t, ir::Instruction*>* preCallSB,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unordered_map<uint32_t, opt::Instruction*>* preCallSB,
std::unique_ptr<opt::BasicBlock>* block_ptr) {
(*inst)->ForEachInId(
[&postCallSB, &preCallSB, &block_ptr, this](uint32_t* iid) {
const auto mapItr = (*postCallSB).find(*iid);
@ -184,8 +184,8 @@ void InlinePass::CloneSameBlockOps(
const auto mapItr2 = (*preCallSB).find(*iid);
if (mapItr2 != (*preCallSB).end()) {
// Clone pre-call same-block ops, map result id.
const ir::Instruction* inInst = mapItr2->second;
std::unique_ptr<ir::Instruction> sb_inst(
const opt::Instruction* inInst = mapItr2->second;
std::unique_ptr<opt::Instruction> sb_inst(
inInst->Clone(inInst->context()));
CloneSameBlockOps(&sb_inst, postCallSB, preCallSB, block_ptr);
const uint32_t rid = sb_inst->result_id();
@ -204,24 +204,24 @@ void InlinePass::CloneSameBlockOps(
}
void InlinePass::GenInlineCode(
std::vector<std::unique_ptr<ir::BasicBlock>>* new_blocks,
std::vector<std::unique_ptr<ir::Instruction>>* new_vars,
ir::BasicBlock::iterator call_inst_itr,
ir::UptrVectorIterator<ir::BasicBlock> call_block_itr) {
std::vector<std::unique_ptr<opt::BasicBlock>>* new_blocks,
std::vector<std::unique_ptr<opt::Instruction>>* new_vars,
opt::BasicBlock::iterator call_inst_itr,
opt::UptrVectorIterator<opt::BasicBlock> call_block_itr) {
// Map from all ids in the callee to their equivalent id in the caller
// as callee instructions are copied into caller.
std::unordered_map<uint32_t, uint32_t> callee2caller;
// Pre-call same-block insts
std::unordered_map<uint32_t, ir::Instruction*> preCallSB;
std::unordered_map<uint32_t, opt::Instruction*> preCallSB;
// Post-call same-block op ids
std::unordered_map<uint32_t, uint32_t> postCallSB;
// Invalidate the def-use chains. They are not kept up to date while
// inlining. However, certain calls try to keep them up-to-date if they are
// valid. These operations can fail.
context()->InvalidateAnalyses(ir::IRContext::kAnalysisDefUse);
context()->InvalidateAnalyses(opt::IRContext::kAnalysisDefUse);
ir::Function* calleeFn = id2function_[call_inst_itr->GetSingleWordOperand(
opt::Function* calleeFn = id2function_[call_inst_itr->GetSingleWordOperand(
kSpvFunctionCallFunctionId)];
// Check for multiple returns in the callee.
@ -240,7 +240,7 @@ void InlinePass::GenInlineCode(
// Create set of callee result ids. Used to detect forward references
std::unordered_set<uint32_t> callee_result_ids;
calleeFn->ForEachInst([&callee_result_ids](const ir::Instruction* cpi) {
calleeFn->ForEachInst([&callee_result_ids](const opt::Instruction* cpi) {
const uint32_t rid = cpi->result_id();
if (rid != 0) callee_result_ids.insert(rid);
});
@ -275,14 +275,15 @@ void InlinePass::GenInlineCode(
// written to it. It is created when we encounter the OpLabel
// of the first callee block. It is appended to new_blocks only when
// it is complete.
std::unique_ptr<ir::BasicBlock> new_blk_ptr;
std::unique_ptr<opt::BasicBlock> new_blk_ptr;
calleeFn->ForEachInst([&new_blocks, &callee2caller, &call_block_itr,
&call_inst_itr, &new_blk_ptr, &prevInstWasReturn,
&returnLabelId, &returnVarId, caller_is_loop_header,
callee_begins_with_structured_header, &calleeTypeId,
&multiBlocks, &postCallSB, &preCallSB, multiReturn,
&singleTripLoopHeaderId, &singleTripLoopContinueId,
&callee_result_ids, this](const ir::Instruction* cpi) {
&callee_result_ids,
this](const opt::Instruction* cpi) {
switch (cpi->opcode()) {
case SpvOpFunction:
case SpvOpFunctionParameter:
@ -305,8 +306,8 @@ void InlinePass::GenInlineCode(
// Generate a return label so that we split the block with the function
// call. Copy the terminator into the new block.
if (returnLabelId == 0) returnLabelId = this->TakeNextId();
std::unique_ptr<ir::Instruction> terminator(
new ir::Instruction(context(), cpi->opcode(), 0, 0, {}));
std::unique_ptr<opt::Instruction> terminator(
new opt::Instruction(context(), cpi->opcode(), 0, 0, {}));
new_blk_ptr->AddInstruction(std::move(terminator));
break;
}
@ -337,14 +338,14 @@ void InlinePass::GenInlineCode(
firstBlock = true;
}
// Create first/next block.
new_blk_ptr.reset(new ir::BasicBlock(NewLabel(labelId)));
new_blk_ptr.reset(new opt::BasicBlock(NewLabel(labelId)));
if (firstBlock) {
// Copy contents of original caller block up to call instruction.
for (auto cii = call_block_itr->begin(); cii != call_inst_itr;
cii = call_block_itr->begin()) {
ir::Instruction* inst = &*cii;
opt::Instruction* inst = &*cii;
inst->RemoveFromList();
std::unique_ptr<ir::Instruction> cp_inst(inst);
std::unique_ptr<opt::Instruction> cp_inst(inst);
// Remember same-block ops for possible regeneration.
if (IsSameBlockOp(&*cp_inst)) {
auto* sb_inst_ptr = cp_inst.get();
@ -363,7 +364,7 @@ void InlinePass::GenInlineCode(
AddBranch(guard_block_id, &new_blk_ptr);
new_blocks->push_back(std::move(new_blk_ptr));
// Start the next block.
new_blk_ptr.reset(new ir::BasicBlock(NewLabel(guard_block_id)));
new_blk_ptr.reset(new opt::BasicBlock(NewLabel(guard_block_id)));
// Reset the mapping of the callee's entry block to point to
// the guard block. Do this so we can fix up phis later on to
// satisfy dominance.
@ -385,14 +386,14 @@ void InlinePass::GenInlineCode(
AddBranch(singleTripLoopHeaderId, &new_blk_ptr);
new_blocks->push_back(std::move(new_blk_ptr));
new_blk_ptr.reset(
new ir::BasicBlock(NewLabel(singleTripLoopHeaderId)));
new opt::BasicBlock(NewLabel(singleTripLoopHeaderId)));
returnLabelId = this->TakeNextId();
singleTripLoopContinueId = this->TakeNextId();
AddLoopMerge(returnLabelId, singleTripLoopContinueId, &new_blk_ptr);
uint32_t postHeaderId = this->TakeNextId();
AddBranch(postHeaderId, &new_blk_ptr);
new_blocks->push_back(std::move(new_blk_ptr));
new_blk_ptr.reset(new ir::BasicBlock(NewLabel(postHeaderId)));
new_blk_ptr.reset(new opt::BasicBlock(NewLabel(postHeaderId)));
multiBlocks = true;
// Reset the mapping of the callee's entry block to point to
// the post-header block. Do this so we can fix up phis later
@ -435,13 +436,13 @@ void InlinePass::GenInlineCode(
// target block now, with a false branch back to the loop header.
new_blocks->push_back(std::move(new_blk_ptr));
new_blk_ptr.reset(
new ir::BasicBlock(NewLabel(singleTripLoopContinueId)));
new opt::BasicBlock(NewLabel(singleTripLoopContinueId)));
AddBranchCond(GetFalseId(), singleTripLoopHeaderId, returnLabelId,
&new_blk_ptr);
}
// Generate the return block.
new_blocks->push_back(std::move(new_blk_ptr));
new_blk_ptr.reset(new ir::BasicBlock(NewLabel(returnLabelId)));
new_blk_ptr.reset(new opt::BasicBlock(NewLabel(returnLabelId)));
multiBlocks = true;
}
// Load return value into result id of call, if it exists.
@ -451,10 +452,10 @@ void InlinePass::GenInlineCode(
AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr);
}
// Copy remaining instructions from caller block.
for (ir::Instruction* inst = call_inst_itr->NextNode(); inst;
for (opt::Instruction* inst = call_inst_itr->NextNode(); inst;
inst = call_inst_itr->NextNode()) {
inst->RemoveFromList();
std::unique_ptr<ir::Instruction> cp_inst(inst);
std::unique_ptr<opt::Instruction> cp_inst(inst);
// If multiple blocks generated, regenerate any same-block
// instruction that has not been seen in this last block.
if (multiBlocks) {
@ -472,7 +473,7 @@ void InlinePass::GenInlineCode(
} break;
default: {
// Copy callee instruction and remap all input Ids.
std::unique_ptr<ir::Instruction> cp_inst(cpi->Clone(context()));
std::unique_ptr<opt::Instruction> cp_inst(cpi->Clone(context()));
cp_inst->ForEachInId([&callee2caller, &callee_result_ids,
this](uint32_t* iid) {
const auto mapItr = callee2caller.find(*iid);
@ -517,7 +518,7 @@ void InlinePass::GenInlineCode(
auto loop_merge_itr = last->tail();
--loop_merge_itr;
assert(loop_merge_itr->opcode() == SpvOpLoopMerge);
std::unique_ptr<ir::Instruction> cp_inst(loop_merge_itr->Clone(context()));
std::unique_ptr<opt::Instruction> cp_inst(loop_merge_itr->Clone(context()));
if (caller_is_single_block_loop) {
// Also, update its continue target to point to the last block.
cp_inst->SetInOperand(kSpvLoopMergeContinueTargetIdInIdx, {last->id()});
@ -535,7 +536,7 @@ void InlinePass::GenInlineCode(
}
}
bool InlinePass::IsInlinableFunctionCall(const ir::Instruction* inst) {
bool InlinePass::IsInlinableFunctionCall(const opt::Instruction* inst) {
if (inst->opcode() != SpvOp::SpvOpFunctionCall) return false;
const uint32_t calleeFnId =
inst->GetSingleWordOperand(kSpvFunctionCallFunctionId);
@ -544,16 +545,16 @@ bool InlinePass::IsInlinableFunctionCall(const ir::Instruction* inst) {
}
void InlinePass::UpdateSucceedingPhis(
std::vector<std::unique_ptr<ir::BasicBlock>>& new_blocks) {
std::vector<std::unique_ptr<opt::BasicBlock>>& new_blocks) {
const auto firstBlk = new_blocks.begin();
const auto lastBlk = new_blocks.end() - 1;
const uint32_t firstId = (*firstBlk)->id();
const uint32_t lastId = (*lastBlk)->id();
const ir::BasicBlock& const_last_block = *lastBlk->get();
const opt::BasicBlock& const_last_block = *lastBlk->get();
const_last_block.ForEachSuccessorLabel(
[&firstId, &lastId, this](const uint32_t succ) {
ir::BasicBlock* sbp = this->id2block_[succ];
sbp->ForEachPhiInst([&firstId, &lastId](ir::Instruction* phi) {
opt::BasicBlock* sbp = this->id2block_[succ];
sbp->ForEachPhiInst([&firstId, &lastId](opt::Instruction* phi) {
phi->ForEachInId([&firstId, &lastId](uint32_t* id) {
if (*id == firstId) *id = lastId;
});
@ -561,7 +562,7 @@ void InlinePass::UpdateSucceedingPhis(
});
}
bool InlinePass::HasMultipleReturns(ir::Function* func) {
bool InlinePass::HasMultipleReturns(opt::Function* func) {
bool seenReturn = false;
bool multipleReturns = false;
for (auto& blk : *func) {
@ -579,7 +580,7 @@ bool InlinePass::HasMultipleReturns(ir::Function* func) {
return multipleReturns;
}
void InlinePass::ComputeStructuredSuccessors(ir::Function* func) {
void InlinePass::ComputeStructuredSuccessors(opt::Function* func) {
// If header, make merge block first successor.
for (auto& blk : *func) {
uint32_t mbid = blk.MergeBlockIdIfAny();
@ -596,12 +597,12 @@ void InlinePass::ComputeStructuredSuccessors(ir::Function* func) {
}
InlinePass::GetBlocksFunction InlinePass::StructuredSuccessorsFunction() {
return [this](const ir::BasicBlock* block) {
return [this](const opt::BasicBlock* block) {
return &(block2structured_succs_[block]);
};
}
bool InlinePass::HasNoReturnInLoop(ir::Function* func) {
bool InlinePass::HasNoReturnInLoop(opt::Function* func) {
// If control not structured, do not do loop/return analysis
// TODO: Analyze returns in non-structured control flow
if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
@ -612,8 +613,8 @@ bool InlinePass::HasNoReturnInLoop(ir::Function* func) {
ComputeStructuredSuccessors(func);
auto ignore_block = [](cbb_ptr) {};
auto ignore_edge = [](cbb_ptr, cbb_ptr) {};
std::list<const ir::BasicBlock*> structuredOrder;
CFA<ir::BasicBlock>::DepthFirstTraversal(
std::list<const opt::BasicBlock*> structuredOrder;
CFA<opt::BasicBlock>::DepthFirstTraversal(
&*func->begin(), StructuredSuccessorsFunction(), ignore_block,
[&](cbb_ptr b) { structuredOrder.push_front(b); }, ignore_edge);
// Search for returns in loops. Only need to track outermost loop
@ -643,7 +644,7 @@ bool InlinePass::HasNoReturnInLoop(ir::Function* func) {
return !return_in_loop;
}
void InlinePass::AnalyzeReturns(ir::Function* func) {
void InlinePass::AnalyzeReturns(opt::Function* func) {
// Look for multiple returns
if (!HasMultipleReturns(func)) {
no_return_in_loop_.insert(func->result_id());
@ -654,7 +655,7 @@ void InlinePass::AnalyzeReturns(ir::Function* func) {
if (HasNoReturnInLoop(func)) no_return_in_loop_.insert(func->result_id());
}
bool InlinePass::IsInlinableFunction(ir::Function* func) {
bool InlinePass::IsInlinableFunction(opt::Function* func) {
// We can only inline a function if it has blocks.
if (func->cbegin() == func->cend()) return false;
// Do not inline functions with returns in loops. Currently early return
@ -667,7 +668,7 @@ bool InlinePass::IsInlinableFunction(ir::Function* func) {
no_return_in_loop_.cend();
}
void InlinePass::InitializeInline(ir::IRContext* c) {
void InlinePass::InitializeInline(opt::IRContext* c) {
InitializeProcessing(c);
false_id_ = 0;

View File

@ -32,11 +32,11 @@ namespace opt {
// See optimizer.hpp for documentation.
class InlinePass : public Pass {
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const opt::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
std::function<std::vector<opt::BasicBlock*>*(const opt::BasicBlock*)>;
InlinePass();
virtual ~InlinePass() = default;
@ -47,60 +47,61 @@ class InlinePass : public Pass {
uint32_t AddPointerToType(uint32_t type_id, SpvStorageClass storage_class);
// Add unconditional branch to labelId to end of block block_ptr.
void AddBranch(uint32_t labelId, std::unique_ptr<ir::BasicBlock>* block_ptr);
void AddBranch(uint32_t labelId, std::unique_ptr<opt::BasicBlock>* block_ptr);
// Add conditional branch to end of block |block_ptr|.
void AddBranchCond(uint32_t cond_id, uint32_t true_id, uint32_t false_id,
std::unique_ptr<ir::BasicBlock>* block_ptr);
std::unique_ptr<opt::BasicBlock>* block_ptr);
// Add unconditional branch to labelId to end of block block_ptr.
void AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
std::unique_ptr<ir::BasicBlock>* block_ptr);
std::unique_ptr<opt::BasicBlock>* block_ptr);
// Add store of valId to ptrId to end of block block_ptr.
void AddStore(uint32_t ptrId, uint32_t valId,
std::unique_ptr<ir::BasicBlock>* block_ptr);
std::unique_ptr<opt::BasicBlock>* block_ptr);
// Add load of ptrId into resultId to end of block block_ptr.
void AddLoad(uint32_t typeId, uint32_t resultId, uint32_t ptrId,
std::unique_ptr<ir::BasicBlock>* block_ptr);
std::unique_ptr<opt::BasicBlock>* block_ptr);
// Return new label.
std::unique_ptr<ir::Instruction> NewLabel(uint32_t label_id);
std::unique_ptr<opt::Instruction> NewLabel(uint32_t label_id);
// Returns the id for the boolean false value. Looks in the module first
// and creates it if not found. Remembers it for future calls.
uint32_t GetFalseId();
// Map callee params to caller args
void MapParams(ir::Function* calleeFn, ir::BasicBlock::iterator call_inst_itr,
void MapParams(opt::Function* calleeFn,
opt::BasicBlock::iterator call_inst_itr,
std::unordered_map<uint32_t, uint32_t>* callee2caller);
// Clone and map callee locals
void CloneAndMapLocals(
ir::Function* calleeFn,
std::vector<std::unique_ptr<ir::Instruction>>* new_vars,
opt::Function* calleeFn,
std::vector<std::unique_ptr<opt::Instruction>>* new_vars,
std::unordered_map<uint32_t, uint32_t>* callee2caller);
// Create return variable for callee clone code if needed. Return id
// if created, otherwise 0.
uint32_t CreateReturnVar(
ir::Function* calleeFn,
std::vector<std::unique_ptr<ir::Instruction>>* new_vars);
opt::Function* calleeFn,
std::vector<std::unique_ptr<opt::Instruction>>* new_vars);
// Return true if instruction must be in the same block that its result
// is used.
bool IsSameBlockOp(const ir::Instruction* inst) const;
bool IsSameBlockOp(const opt::Instruction* inst) const;
// Clone operands which must be in same block as consumer instructions.
// Look in preCallSB for instructions that need cloning. Look in
// postCallSB for instructions already cloned. Add cloned instruction
// to postCallSB.
void CloneSameBlockOps(
std::unique_ptr<ir::Instruction>* inst,
std::unique_ptr<opt::Instruction>* inst,
std::unordered_map<uint32_t, uint32_t>* postCallSB,
std::unordered_map<uint32_t, ir::Instruction*>* preCallSB,
std::unique_ptr<ir::BasicBlock>* block_ptr);
std::unordered_map<uint32_t, opt::Instruction*>* preCallSB,
std::unique_ptr<opt::BasicBlock>* block_ptr);
// Return in new_blocks the result of inlining the call at call_inst_itr
// within its block at call_block_itr. The block at call_block_itr can
@ -116,13 +117,13 @@ class InlinePass : public Pass {
// Also return in new_vars additional OpVariable instructions required by
// and to be inserted into the caller function after the block at
// call_block_itr is replaced with new_blocks.
void GenInlineCode(std::vector<std::unique_ptr<ir::BasicBlock>>* new_blocks,
std::vector<std::unique_ptr<ir::Instruction>>* new_vars,
ir::BasicBlock::iterator call_inst_itr,
ir::UptrVectorIterator<ir::BasicBlock> call_block_itr);
void GenInlineCode(std::vector<std::unique_ptr<opt::BasicBlock>>* new_blocks,
std::vector<std::unique_ptr<opt::Instruction>>* new_vars,
opt::BasicBlock::iterator call_inst_itr,
opt::UptrVectorIterator<opt::BasicBlock> call_block_itr);
// Return true if |inst| is a function call that can be inlined.
bool IsInlinableFunctionCall(const ir::Instruction* inst);
bool IsInlinableFunctionCall(const opt::Instruction* inst);
// Compute structured successors for function |func|.
// A block's structured successors are the blocks it branches to
@ -131,39 +132,39 @@ class InlinePass : public Pass {
// This assures correct depth first search in the presence of early
// returns and kills. If the successor vector contain duplicates
// if the merge block, they are safely ignored by DFS.
void ComputeStructuredSuccessors(ir::Function* func);
void ComputeStructuredSuccessors(opt::Function* func);
// Return function to return ordered structure successors for a given block
// Assumes ComputeStructuredSuccessors() has been called.
GetBlocksFunction StructuredSuccessorsFunction();
// Return true if |func| has multiple returns
bool HasMultipleReturns(ir::Function* func);
bool HasMultipleReturns(opt::Function* func);
// Return true if |func| has no return in a loop. The current analysis
// requires structured control flow, so return false if control flow not
// structured ie. module is not a shader.
bool HasNoReturnInLoop(ir::Function* func);
bool HasNoReturnInLoop(opt::Function* func);
// Find all functions with multiple returns and no returns in loops
void AnalyzeReturns(ir::Function* func);
void AnalyzeReturns(opt::Function* func);
// Return true if |func| is a function that can be inlined.
bool IsInlinableFunction(ir::Function* func);
bool IsInlinableFunction(opt::Function* func);
// Update phis in succeeding blocks to point to new last block
void UpdateSucceedingPhis(
std::vector<std::unique_ptr<ir::BasicBlock>>& new_blocks);
std::vector<std::unique_ptr<opt::BasicBlock>>& new_blocks);
// Initialize state for optimization of |module|
void InitializeInline(ir::IRContext* c);
void InitializeInline(opt::IRContext* c);
// Map from function's result id to function.
std::unordered_map<uint32_t, ir::Function*> id2function_;
std::unordered_map<uint32_t, opt::Function*> id2function_;
// Map from block's label id to block. TODO(dnovillo): This is superfluous wrt
// opt::CFG. It has functionality not present in opt::CFG. Consolidate.
std::unordered_map<uint32_t, ir::BasicBlock*> id2block_;
std::unordered_map<uint32_t, opt::BasicBlock*> id2block_;
// Set of ids of functions with multiple returns.
std::set<uint32_t> multi_return_funcs_;
@ -181,7 +182,7 @@ class InlinePass : public Pass {
// ComputeStructuredSuccessors() for definition. TODO(dnovillo): This is
// superfluous wrt opt::CFG, but it seems to be computed in a slightly
// different way in the inliner. Can these be consolidated?
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
std::unordered_map<const opt::BasicBlock*, std::vector<opt::BasicBlock*>>
block2structured_succs_;
};

View File

@ -22,7 +22,7 @@
#include "reflect.h"
namespace spvtools {
namespace ir {
namespace opt {
namespace {
// Indices used to get particular operands out of instructions using InOperand.
@ -145,7 +145,7 @@ void Instruction::ReplaceOperands(const OperandList& new_operands) {
bool Instruction::IsReadOnlyLoad() const {
if (IsLoad()) {
ir::Instruction* address_def = GetBaseAddress();
opt::Instruction* address_def = GetBaseAddress();
if (!address_def || address_def->opcode() != SpvOpVariable) {
return false;
}
@ -161,7 +161,7 @@ Instruction* Instruction::GetBaseAddress() const {
"GetBaseAddress should only be called on instructions that take a "
"pointer or image.");
uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
ir::Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
opt::Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
bool done = false;
while (!done) {
switch (base_inst->opcode()) {
@ -217,7 +217,7 @@ bool Instruction::IsVulkanStorageImage() const {
return false;
}
ir::Instruction* base_type =
opt::Instruction* base_type =
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
if (base_type->opcode() != SpvOpTypeImage) {
return false;
@ -243,7 +243,7 @@ bool Instruction::IsVulkanSampledImage() const {
return false;
}
ir::Instruction* base_type =
opt::Instruction* base_type =
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
if (base_type->opcode() != SpvOpTypeImage) {
return false;
@ -269,7 +269,7 @@ bool Instruction::IsVulkanStorageTexelBuffer() const {
return false;
}
ir::Instruction* base_type =
opt::Instruction* base_type =
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
if (base_type->opcode() != SpvOpTypeImage) {
return false;
@ -291,7 +291,7 @@ bool Instruction::IsVulkanStorageBuffer() const {
return false;
}
ir::Instruction* base_type =
opt::Instruction* base_type =
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
if (base_type->opcode() != SpvOpTypeStruct) {
@ -303,13 +303,15 @@ bool Instruction::IsVulkanStorageBuffer() const {
bool is_buffer_block = false;
context()->get_decoration_mgr()->ForEachDecoration(
base_type->result_id(), SpvDecorationBufferBlock,
[&is_buffer_block](const ir::Instruction&) { is_buffer_block = true; });
[&is_buffer_block](const opt::Instruction&) {
is_buffer_block = true;
});
return is_buffer_block;
} else if (storage_class == SpvStorageClassStorageBuffer) {
bool is_block = false;
context()->get_decoration_mgr()->ForEachDecoration(
base_type->result_id(), SpvDecorationBlock,
[&is_block](const ir::Instruction&) { is_block = true; });
[&is_block](const opt::Instruction&) { is_block = true; });
return is_block;
}
return false;
@ -325,7 +327,7 @@ bool Instruction::IsVulkanUniformBuffer() const {
return false;
}
ir::Instruction* base_type =
opt::Instruction* base_type =
context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
if (base_type->opcode() != SpvOpTypeStruct) {
return false;
@ -334,7 +336,7 @@ bool Instruction::IsVulkanUniformBuffer() const {
bool is_block = false;
context()->get_decoration_mgr()->ForEachDecoration(
base_type->result_id(), SpvDecorationBlock,
[&is_block](const ir::Instruction&) { is_block = true; });
[&is_block](const opt::Instruction&) { is_block = true; });
return is_block;
}
@ -414,7 +416,7 @@ bool Instruction::IsValidBasePointer() const {
return false;
}
ir::Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
opt::Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
if (type->opcode() != SpvOpTypePointer) {
return false;
}
@ -429,7 +431,7 @@ bool Instruction::IsValidBasePointer() const {
}
uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
ir::Instruction* pointee_type_inst =
opt::Instruction* pointee_type_inst =
context()->get_def_use_mgr()->GetDef(pointee_type_id);
if (pointee_type_inst->IsOpaqueType()) {
@ -444,7 +446,7 @@ bool Instruction::IsValidBaseImage() const {
return false;
}
ir::Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
opt::Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
return (type->opcode() == SpvOpTypeImage ||
type->opcode() == SpvOpTypeSampledImage);
}
@ -453,13 +455,14 @@ bool Instruction::IsOpaqueType() const {
if (opcode() == SpvOpTypeStruct) {
bool is_opaque = false;
ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
ir::Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
opt::Instruction* type_inst =
context()->get_def_use_mgr()->GetDef(*op_id);
is_opaque |= type_inst->IsOpaqueType();
});
return is_opaque;
} else if (opcode() == SpvOpTypeArray) {
uint32_t sub_type_id = GetSingleWordInOperand(0);
ir::Instruction* sub_type_inst =
opt::Instruction* sub_type_inst =
context()->get_def_use_mgr()->GetDef(sub_type_id);
return sub_type_inst->IsOpaqueType();
} else {
@ -491,7 +494,7 @@ bool Instruction::IsFloatingPointFoldingAllowed() const {
bool is_nocontract = false;
context_->get_decoration_mgr()->WhileEachDecoration(
opcode_, SpvDecorationNoContraction,
[&is_nocontract](const ir::Instruction&) {
[&is_nocontract](const opt::Instruction&) {
is_nocontract = true;
return false;
});
@ -515,7 +518,7 @@ std::string Instruction::PrettyPrint(uint32_t options) const {
options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
}
std::ostream& operator<<(std::ostream& str, const ir::Instruction& inst) {
std::ostream& operator<<(std::ostream& str, const opt::Instruction& inst) {
str << inst.PrettyPrint();
return str;
}
@ -722,5 +725,5 @@ bool Instruction::IsOpcodeSafeToDelete() const {
}
}
} // namespace ir
} // namespace opt
} // namespace spvtools

View File

@ -31,7 +31,7 @@
#include "spirv-tools/libspirv.h"
namespace spvtools {
namespace ir {
namespace opt {
class Function;
class IRContext;
@ -458,7 +458,7 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
// to provide the correct interpretation of types, constants, etc.
//
// Disassembly uses raw ids (not pretty printed names).
std::ostream& operator<<(std::ostream& str, const ir::Instruction& inst);
std::ostream& operator<<(std::ostream& str, const opt::Instruction& inst);
inline bool Instruction::operator==(const Instruction& other) const {
return unique_id() == other.unique_id();
@ -709,7 +709,7 @@ bool Instruction::IsAtomicOp() const { return spvOpcodeIsAtomicOp(opcode()); }
bool Instruction::IsConstant() const {
return IsCompileTimeConstantInst(opcode());
}
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_INSTRUCTION_H_

View File

@ -15,7 +15,7 @@
#include "instruction_list.h"
namespace spvtools {
namespace ir {
namespace opt {
InstructionList::iterator InstructionList::iterator::InsertBefore(
std::vector<std::unique_ptr<Instruction>>&& list) {
@ -32,5 +32,5 @@ InstructionList::iterator InstructionList::iterator::InsertBefore(
i.get()->InsertBefore(node_);
return iterator(i.release());
}
} // namespace ir
} // namespace spvtools
} // namespace opt
} // namespace spvtools

View File

@ -29,7 +29,7 @@
#include "spirv-tools/libspirv.h"
namespace spvtools {
namespace ir {
namespace opt {
// This class is intended to be the container for Instructions. This container
// owns the instructions that are in it. When removing an Instruction from the
@ -124,7 +124,7 @@ void InstructionList::clear() {
}
}
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_INSTRUCTION_LIST_H_

View File

@ -34,31 +34,31 @@ const uint32_t kInvalidId = std::numeric_limits<uint32_t>::max();
// - Instruction to block analysis
class InstructionBuilder {
public:
using InsertionPointTy = ir::BasicBlock::iterator;
using InsertionPointTy = opt::BasicBlock::iterator;
// Creates an InstructionBuilder, all new instructions will be inserted before
// the instruction |insert_before|.
InstructionBuilder(
ir::IRContext* context, ir::Instruction* insert_before,
ir::IRContext::Analysis preserved_analyses = ir::IRContext::kAnalysisNone)
InstructionBuilder(opt::IRContext* context, opt::Instruction* insert_before,
opt::IRContext::Analysis preserved_analyses =
opt::IRContext::kAnalysisNone)
: InstructionBuilder(context, context->get_instr_block(insert_before),
InsertionPointTy(insert_before),
preserved_analyses) {}
// Creates an InstructionBuilder, all new instructions will be inserted at the
// end of the basic block |parent_block|.
InstructionBuilder(
ir::IRContext* context, ir::BasicBlock* parent_block,
ir::IRContext::Analysis preserved_analyses = ir::IRContext::kAnalysisNone)
InstructionBuilder(opt::IRContext* context, opt::BasicBlock* parent_block,
opt::IRContext::Analysis preserved_analyses =
opt::IRContext::kAnalysisNone)
: InstructionBuilder(context, parent_block, parent_block->end(),
preserved_analyses) {}
// Creates a new selection merge instruction.
// The id |merge_id| is the merge basic block id.
ir::Instruction* AddSelectionMerge(
opt::Instruction* AddSelectionMerge(
uint32_t merge_id,
uint32_t selection_control = SpvSelectionControlMaskNone) {
std::unique_ptr<ir::Instruction> new_branch_merge(new ir::Instruction(
std::unique_ptr<opt::Instruction> new_branch_merge(new opt::Instruction(
GetContext(), SpvOpSelectionMerge, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_SELECTION_CONTROL,
@ -69,8 +69,8 @@ class InstructionBuilder {
// Creates a new branch instruction to |label_id|.
// Note that the user must make sure the final basic block is
// well formed.
ir::Instruction* AddBranch(uint32_t label_id) {
std::unique_ptr<ir::Instruction> new_branch(new ir::Instruction(
opt::Instruction* AddBranch(uint32_t label_id) {
std::unique_ptr<opt::Instruction> new_branch(new opt::Instruction(
GetContext(), SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
return AddInstruction(std::move(new_branch));
@ -91,14 +91,14 @@ class InstructionBuilder {
// selection merge instruction.
// Note that the user must make sure the final basic block is
// well formed.
ir::Instruction* AddConditionalBranch(
opt::Instruction* AddConditionalBranch(
uint32_t cond_id, uint32_t true_id, uint32_t false_id,
uint32_t merge_id = kInvalidId,
uint32_t selection_control = SpvSelectionControlMaskNone) {
if (merge_id != kInvalidId) {
AddSelectionMerge(merge_id, selection_control);
}
std::unique_ptr<ir::Instruction> new_branch(new ir::Instruction(
std::unique_ptr<opt::Instruction> new_branch(new opt::Instruction(
GetContext(), SpvOpBranchConditional, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
@ -119,28 +119,29 @@ class InstructionBuilder {
// selection merge instruction.
// Note that the user must make sure the final basic block is
// well formed.
ir::Instruction* AddSwitch(
opt::Instruction* AddSwitch(
uint32_t selector_id, uint32_t default_id,
const std::vector<std::pair<ir::Operand::OperandData, uint32_t>>& targets,
const std::vector<std::pair<opt::Operand::OperandData, uint32_t>>&
targets,
uint32_t merge_id = kInvalidId,
uint32_t selection_control = SpvSelectionControlMaskNone) {
if (merge_id != kInvalidId) {
AddSelectionMerge(merge_id, selection_control);
}
std::vector<ir::Operand> operands;
std::vector<opt::Operand> operands;
operands.emplace_back(
ir::Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {selector_id}});
opt::Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {selector_id}});
operands.emplace_back(
ir::Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {default_id}});
opt::Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {default_id}});
for (auto& target : targets) {
operands.emplace_back(
ir::Operand{spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
target.first});
operands.emplace_back(ir::Operand{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
{target.second}});
operands.emplace_back(opt::Operand{
spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
target.first});
operands.emplace_back(opt::Operand{
spv_operand_type_t::SPV_OPERAND_TYPE_ID, {target.second}});
}
std::unique_ptr<ir::Instruction> new_switch(
new ir::Instruction(GetContext(), SpvOpSwitch, 0, 0, operands));
std::unique_ptr<opt::Instruction> new_switch(
new opt::Instruction(GetContext(), SpvOpSwitch, 0, 0, operands));
return AddInstruction(std::move(new_switch));
}
@ -148,14 +149,14 @@ class InstructionBuilder {
// The id |type| must be the id of the phi instruction's type.
// The vector |incomings| must be a sequence of pairs of <definition id,
// parent id>.
ir::Instruction* AddPhi(uint32_t type,
const std::vector<uint32_t>& incomings) {
opt::Instruction* AddPhi(uint32_t type,
const std::vector<uint32_t>& incomings) {
assert(incomings.size() % 2 == 0 && "A sequence of pairs is expected");
std::vector<ir::Operand> phi_ops;
std::vector<opt::Operand> phi_ops;
for (size_t i = 0; i < incomings.size(); i++) {
phi_ops.push_back({SPV_OPERAND_TYPE_ID, {incomings[i]}});
}
std::unique_ptr<ir::Instruction> phi_inst(new ir::Instruction(
std::unique_ptr<opt::Instruction> phi_inst(new opt::Instruction(
GetContext(), SpvOpPhi, type, GetContext()->TakeNextId(), phi_ops));
return AddInstruction(std::move(phi_inst));
}
@ -165,8 +166,8 @@ class InstructionBuilder {
// |op1| and |op2| types.
// The id |op1| is the left hand side of the operation.
// The id |op2| is the right hand side of the operation.
ir::Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) {
std::unique_ptr<ir::Instruction> inst(new ir::Instruction(
opt::Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) {
std::unique_ptr<opt::Instruction> inst(new opt::Instruction(
GetContext(), SpvOpIAdd, type, GetContext()->TakeNextId(),
{{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
return AddInstruction(std::move(inst));
@ -176,10 +177,10 @@ class InstructionBuilder {
// The id |op1| is the left hand side of the operation.
// The id |op2| is the right hand side of the operation.
// It is assumed that |op1| and |op2| have the same underlying type.
ir::Instruction* AddULessThan(uint32_t op1, uint32_t op2) {
opt::Instruction* AddULessThan(uint32_t op1, uint32_t op2) {
analysis::Bool bool_type;
uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
std::unique_ptr<ir::Instruction> inst(new ir::Instruction(
std::unique_ptr<opt::Instruction> inst(new opt::Instruction(
GetContext(), SpvOpULessThan, type, GetContext()->TakeNextId(),
{{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
return AddInstruction(std::move(inst));
@ -189,10 +190,10 @@ class InstructionBuilder {
// The id |op1| is the left hand side of the operation.
// The id |op2| is the right hand side of the operation.
// It is assumed that |op1| and |op2| have the same underlying type.
ir::Instruction* AddSLessThan(uint32_t op1, uint32_t op2) {
opt::Instruction* AddSLessThan(uint32_t op1, uint32_t op2) {
analysis::Bool bool_type;
uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type);
std::unique_ptr<ir::Instruction> inst(new ir::Instruction(
std::unique_ptr<opt::Instruction> inst(new opt::Instruction(
GetContext(), SpvOpSLessThan, type, GetContext()->TakeNextId(),
{{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}}));
return AddInstruction(std::move(inst));
@ -202,8 +203,8 @@ class InstructionBuilder {
// |op1|. The id |op1| is the left hand side of the operation. The id |op2| is
// the right hand side of the operation. It is assumed that |op1| and |op2|
// have the same underlying type.
ir::Instruction* AddLessThan(uint32_t op1, uint32_t op2) {
ir::Instruction* op1_insn = context_->get_def_use_mgr()->GetDef(op1);
opt::Instruction* AddLessThan(uint32_t op1, uint32_t op2) {
opt::Instruction* op1_insn = context_->get_def_use_mgr()->GetDef(op1);
analysis::Type* type =
GetContext()->get_type_mgr()->GetType(op1_insn->type_id());
analysis::Integer* int_type = type->AsInteger();
@ -219,11 +220,11 @@ class InstructionBuilder {
// |type| must match the types of |true_value| and |false_value|. It is up to
// the caller to ensure that |cond| is a correct type (bool or vector of
// bool) for |type|.
ir::Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value,
uint32_t false_value) {
std::unique_ptr<ir::Instruction> select(new ir::Instruction(
opt::Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value,
uint32_t false_value) {
std::unique_ptr<opt::Instruction> select(new opt::Instruction(
GetContext(), SpvOpSelect, type, GetContext()->TakeNextId(),
std::initializer_list<ir::Operand>{
std::initializer_list<opt::Operand>{
{SPV_OPERAND_TYPE_ID, {cond}},
{SPV_OPERAND_TYPE_ID, {true_value}},
{SPV_OPERAND_TYPE_ID, {false_value}}}));
@ -232,28 +233,28 @@ class InstructionBuilder {
// Adds a signed int32 constant to the binary.
// The |value| parameter is the constant value to be added.
ir::Instruction* Add32BitSignedIntegerConstant(int32_t value) {
opt::Instruction* Add32BitSignedIntegerConstant(int32_t value) {
return Add32BitConstantInteger<int32_t>(value, true);
}
// Create a composite construct.
// |type| should be a composite type and the number of elements it has should
// match the size od |ids|.
ir::Instruction* AddCompositeConstruct(uint32_t type,
const std::vector<uint32_t>& ids) {
std::vector<ir::Operand> ops;
opt::Instruction* AddCompositeConstruct(uint32_t type,
const std::vector<uint32_t>& ids) {
std::vector<opt::Operand> ops;
for (auto id : ids) {
ops.emplace_back(SPV_OPERAND_TYPE_ID,
std::initializer_list<uint32_t>{id});
}
std::unique_ptr<ir::Instruction> construct(
new ir::Instruction(GetContext(), SpvOpCompositeConstruct, type,
GetContext()->TakeNextId(), ops));
std::unique_ptr<opt::Instruction> construct(
new opt::Instruction(GetContext(), SpvOpCompositeConstruct, type,
GetContext()->TakeNextId(), ops));
return AddInstruction(std::move(construct));
}
// Adds an unsigned int32 constant to the binary.
// The |value| parameter is the constant value to be added.
ir::Instruction* Add32BitUnsignedIntegerConstant(uint32_t value) {
opt::Instruction* Add32BitUnsignedIntegerConstant(uint32_t value) {
return Add32BitConstantInteger<uint32_t>(value, false);
}
@ -262,7 +263,7 @@ class InstructionBuilder {
// signed constant otherwise as an unsigned constant. If |sign| is false the
// value must not be a negative number.
template <typename T>
ir::Instruction* Add32BitConstantInteger(T value, bool sign) {
opt::Instruction* Add32BitConstantInteger(T value, bool sign) {
// Assert that we are not trying to store a negative number in an unsigned
// type.
if (!sign)
@ -293,58 +294,58 @@ class InstructionBuilder {
return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
}
ir::Instruction* AddCompositeExtract(
opt::Instruction* AddCompositeExtract(
uint32_t type, uint32_t id_of_composite,
const std::vector<uint32_t>& index_list) {
std::vector<ir::Operand> operands;
std::vector<opt::Operand> operands;
operands.push_back({SPV_OPERAND_TYPE_ID, {id_of_composite}});
for (uint32_t index : index_list) {
operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}});
}
std::unique_ptr<ir::Instruction> new_inst(
new ir::Instruction(GetContext(), SpvOpCompositeExtract, type,
GetContext()->TakeNextId(), operands));
std::unique_ptr<opt::Instruction> new_inst(
new opt::Instruction(GetContext(), SpvOpCompositeExtract, type,
GetContext()->TakeNextId(), operands));
return AddInstruction(std::move(new_inst));
}
// Creates an unreachable instruction.
ir::Instruction* AddUnreachable() {
std::unique_ptr<ir::Instruction> select(
new ir::Instruction(GetContext(), SpvOpUnreachable, 0, 0,
std::initializer_list<ir::Operand>{}));
opt::Instruction* AddUnreachable() {
std::unique_ptr<opt::Instruction> select(
new opt::Instruction(GetContext(), SpvOpUnreachable, 0, 0,
std::initializer_list<opt::Operand>{}));
return AddInstruction(std::move(select));
}
ir::Instruction* AddAccessChain(uint32_t type_id, uint32_t base_ptr_id,
std::vector<uint32_t> ids) {
std::vector<ir::Operand> operands;
opt::Instruction* AddAccessChain(uint32_t type_id, uint32_t base_ptr_id,
std::vector<uint32_t> ids) {
std::vector<opt::Operand> operands;
operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
for (uint32_t index_id : ids) {
operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}});
}
std::unique_ptr<ir::Instruction> new_inst(
new ir::Instruction(GetContext(), SpvOpAccessChain, type_id,
GetContext()->TakeNextId(), operands));
std::unique_ptr<opt::Instruction> new_inst(
new opt::Instruction(GetContext(), SpvOpAccessChain, type_id,
GetContext()->TakeNextId(), operands));
return AddInstruction(std::move(new_inst));
}
ir::Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) {
std::vector<ir::Operand> operands;
opt::Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) {
std::vector<opt::Operand> operands;
operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
std::unique_ptr<ir::Instruction> new_inst(
new ir::Instruction(GetContext(), SpvOpLoad, type_id,
GetContext()->TakeNextId(), operands));
std::unique_ptr<opt::Instruction> new_inst(
new opt::Instruction(GetContext(), SpvOpLoad, type_id,
GetContext()->TakeNextId(), operands));
return AddInstruction(std::move(new_inst));
}
// Inserts the new instruction before the insertion point.
ir::Instruction* AddInstruction(std::unique_ptr<ir::Instruction>&& insn) {
ir::Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
opt::Instruction* AddInstruction(std::unique_ptr<opt::Instruction>&& insn) {
opt::Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
UpdateInstrToBlockMapping(insn_ptr);
UpdateDefUseMgr(insn_ptr);
return insn_ptr;
@ -355,65 +356,65 @@ class InstructionBuilder {
// Change the insertion point to insert before the instruction
// |insert_before|.
void SetInsertPoint(ir::Instruction* insert_before) {
void SetInsertPoint(opt::Instruction* insert_before) {
parent_ = context_->get_instr_block(insert_before);
insert_before_ = InsertionPointTy(insert_before);
}
// Change the insertion point to insert at the end of the basic block
// |parent_block|.
void SetInsertPoint(ir::BasicBlock* parent_block) {
void SetInsertPoint(opt::BasicBlock* parent_block) {
parent_ = parent_block;
insert_before_ = parent_block->end();
}
// Returns the context which instructions are constructed for.
ir::IRContext* GetContext() const { return context_; }
opt::IRContext* GetContext() const { return context_; }
// Returns the set of preserved analyses.
inline ir::IRContext::Analysis GetPreservedAnalysis() const {
inline opt::IRContext::Analysis GetPreservedAnalysis() const {
return preserved_analyses_;
}
private:
InstructionBuilder(ir::IRContext* context, ir::BasicBlock* parent,
InstructionBuilder(opt::IRContext* context, opt::BasicBlock* parent,
InsertionPointTy insert_before,
ir::IRContext::Analysis preserved_analyses)
opt::IRContext::Analysis preserved_analyses)
: context_(context),
parent_(parent),
insert_before_(insert_before),
preserved_analyses_(preserved_analyses) {
assert(!(preserved_analyses_ &
~(ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping)));
~(opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping)));
}
// Returns true if the users requested to update |analysis|.
inline bool IsAnalysisUpdateRequested(
ir::IRContext::Analysis analysis) const {
opt::IRContext::Analysis analysis) const {
return preserved_analyses_ & analysis;
}
// Updates the def/use manager if the user requested it. If he did not request
// an update, this function does nothing.
inline void UpdateDefUseMgr(ir::Instruction* insn) {
if (IsAnalysisUpdateRequested(ir::IRContext::kAnalysisDefUse))
inline void UpdateDefUseMgr(opt::Instruction* insn) {
if (IsAnalysisUpdateRequested(opt::IRContext::kAnalysisDefUse))
GetContext()->get_def_use_mgr()->AnalyzeInstDefUse(insn);
}
// Updates the instruction to block analysis if the user requested it. If he
// did not request an update, this function does nothing.
inline void UpdateInstrToBlockMapping(ir::Instruction* insn) {
inline void UpdateInstrToBlockMapping(opt::Instruction* insn) {
if (IsAnalysisUpdateRequested(
ir::IRContext::kAnalysisInstrToBlockMapping) &&
opt::IRContext::kAnalysisInstrToBlockMapping) &&
parent_)
GetContext()->set_instr_block(insn, parent_);
}
ir::IRContext* context_;
ir::BasicBlock* parent_;
opt::IRContext* context_;
opt::BasicBlock* parent_;
InsertionPointTy insert_before_;
const ir::IRContext::Analysis preserved_analyses_;
const opt::IRContext::Analysis preserved_analyses_;
};
} // namespace opt

View File

@ -21,7 +21,7 @@
#include <cstring>
namespace spvtools {
namespace ir {
namespace opt {
void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
if (set & kAnalysisDefUse) {
@ -92,7 +92,7 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
}
Instruction* IRContext::KillInst(ir::Instruction* inst) {
Instruction* IRContext::KillInst(opt::Instruction* inst) {
if (!inst) {
return nullptr;
}
@ -114,11 +114,11 @@ Instruction* IRContext::KillInst(ir::Instruction* inst) {
}
}
if (type_mgr_ && ir::IsTypeInst(inst->opcode())) {
if (type_mgr_ && opt::IsTypeInst(inst->opcode())) {
type_mgr_->RemoveId(inst->result_id());
}
if (constant_mgr_ && ir::IsConstantInst(inst->opcode())) {
if (constant_mgr_ && opt::IsConstantInst(inst->opcode())) {
constant_mgr_->RemoveId(inst->result_id());
}
@ -138,7 +138,7 @@ Instruction* IRContext::KillInst(ir::Instruction* inst) {
}
bool IRContext::KillDef(uint32_t id) {
ir::Instruction* def = get_def_use_mgr()->GetDef(id);
opt::Instruction* def = get_def_use_mgr()->GetDef(id);
if (def != nullptr) {
KillInst(def);
return true;
@ -153,15 +153,15 @@ bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
assert(get_def_use_mgr()->GetDef(after) &&
"'after' is not a registered def.");
std::vector<std::pair<ir::Instruction*, uint32_t>> uses_to_update;
std::vector<std::pair<opt::Instruction*, uint32_t>> uses_to_update;
get_def_use_mgr()->ForEachUse(
before, [&uses_to_update](ir::Instruction* user, uint32_t index) {
before, [&uses_to_update](opt::Instruction* user, uint32_t index) {
uses_to_update.emplace_back(user, index);
});
ir::Instruction* prev = nullptr;
opt::Instruction* prev = nullptr;
for (auto p : uses_to_update) {
ir::Instruction* user = p.first;
opt::Instruction* user = p.first;
uint32_t index = p.second;
if (prev == nullptr || prev != user) {
ForgetUses(user);
@ -211,7 +211,7 @@ bool IRContext::IsConsistent() {
if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
for (auto& func : *module()) {
for (auto& block : func) {
if (!block.WhileEachInst([this, &block](ir::Instruction* inst) {
if (!block.WhileEachInst([this, &block](opt::Instruction* inst) {
if (get_instr_block(inst) != &block) {
return false;
}
@ -257,18 +257,18 @@ void IRContext::AnalyzeUses(Instruction* inst) {
}
void IRContext::KillNamesAndDecorates(uint32_t id) {
std::vector<ir::Instruction*> decorations =
std::vector<opt::Instruction*> decorations =
get_decoration_mgr()->GetDecorationsFor(id, true);
for (Instruction* inst : decorations) {
KillInst(inst);
}
std::vector<ir::Instruction*> name_to_kill;
std::vector<opt::Instruction*> name_to_kill;
for (auto name : GetNames(id)) {
name_to_kill.push_back(name.second);
}
for (ir::Instruction* name_inst : name_to_kill) {
for (opt::Instruction* name_inst : name_to_kill) {
KillInst(name_inst);
}
}
@ -442,7 +442,7 @@ void IRContext::AddCombinatorsForCapability(uint32_t capability) {
}
}
void IRContext::AddCombinatorsForExtension(ir::Instruction* extension) {
void IRContext::AddCombinatorsForExtension(opt::Instruction* extension) {
assert(extension->opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
const char* extension_name =
@ -557,15 +557,15 @@ void IRContext::RemoveFromIdToName(const Instruction* inst) {
}
}
ir::LoopDescriptor* IRContext::GetLoopDescriptor(const ir::Function* f) {
opt::LoopDescriptor* IRContext::GetLoopDescriptor(const opt::Function* f) {
if (!AreAnalysesValid(kAnalysisLoopAnalysis)) {
ResetLoopAnalysis();
}
std::unordered_map<const ir::Function*, ir::LoopDescriptor>::iterator it =
std::unordered_map<const opt::Function*, opt::LoopDescriptor>::iterator it =
loop_descriptors_.find(f);
if (it == loop_descriptors_.end()) {
return &loop_descriptors_.emplace(std::make_pair(f, ir::LoopDescriptor(f)))
return &loop_descriptors_.emplace(std::make_pair(f, opt::LoopDescriptor(f)))
.first->second;
}
@ -573,7 +573,8 @@ ir::LoopDescriptor* IRContext::GetLoopDescriptor(const ir::Function* f) {
}
// Gets the dominator analysis for function |f|.
opt::DominatorAnalysis* IRContext::GetDominatorAnalysis(const ir::Function* f) {
opt::DominatorAnalysis* IRContext::GetDominatorAnalysis(
const opt::Function* f) {
if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
ResetDominatorAnalysis();
}
@ -587,7 +588,7 @@ opt::DominatorAnalysis* IRContext::GetDominatorAnalysis(const ir::Function* f) {
// Gets the postdominator analysis for function |f|.
opt::PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(
const ir::Function* f) {
const opt::Function* f) {
if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
ResetDominatorAnalysis();
}
@ -599,13 +600,13 @@ opt::PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(
return &post_dominator_trees_[f];
}
bool ir::IRContext::CheckCFG() {
bool opt::IRContext::CheckCFG() {
std::unordered_map<uint32_t, std::vector<uint32_t>> real_preds;
if (!AreAnalysesValid(kAnalysisCFG)) {
return true;
}
for (ir::Function& function : *module()) {
for (opt::Function& function : *module()) {
for (const auto& bb : function) {
bb.ForEachSuccessorLabel([&bb, &real_preds](const uint32_t lab_id) {
real_preds[lab_id].push_back(bb.id());
@ -650,5 +651,5 @@ bool ir::IRContext::CheckCFG() {
return true;
}
} // namespace ir
} // namespace opt
} // namespace spvtools

View File

@ -36,7 +36,7 @@
#include <unordered_set>
namespace spvtools {
namespace ir {
namespace opt {
class IRContext {
public:
@ -126,8 +126,8 @@ class IRContext {
inline IteratorRange<Module::const_inst_iterator> capabilities() const;
// Iterators for types, constants and global variables instructions.
inline ir::Module::inst_iterator types_values_begin();
inline ir::Module::inst_iterator types_values_end();
inline opt::Module::inst_iterator types_values_begin();
inline opt::Module::inst_iterator types_values_end();
inline IteratorRange<Module::inst_iterator> types_values();
inline IteratorRange<Module::const_inst_iterator> types_values() const;
@ -230,7 +230,7 @@ class IRContext {
// Returns the basic block for instruction |instr|. Re-builds the instruction
// block map, if needed.
ir::BasicBlock* get_instr_block(ir::Instruction* instr) {
opt::BasicBlock* get_instr_block(opt::Instruction* instr) {
if (!AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
BuildInstrToBlockMapping();
}
@ -242,14 +242,14 @@ class IRContext {
// needed.
//
// |id| must be a registered definition.
ir::BasicBlock* get_instr_block(uint32_t id) {
ir::Instruction* def = get_def_use_mgr()->GetDef(id);
opt::BasicBlock* get_instr_block(uint32_t id) {
opt::Instruction* def = get_def_use_mgr()->GetDef(id);
return get_instr_block(def);
}
// Sets the basic block for |inst|. Re-builds the mapping if it has become
// invalid.
void set_instr_block(ir::Instruction* inst, ir::BasicBlock* block) {
void set_instr_block(opt::Instruction* inst, opt::BasicBlock* block) {
if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
instr_to_block_[inst] = block;
}
@ -337,7 +337,7 @@ class IRContext {
//
// Returns a pointer to the instruction after |inst| or |nullptr| if no such
// instruction exists.
Instruction* KillInst(ir::Instruction* inst);
Instruction* KillInst(opt::Instruction* inst);
// Returns true if all of the given analyses are valid.
bool AreAnalysesValid(Analysis set) { return (set & valid_analyses_) == set; }
@ -371,7 +371,7 @@ class IRContext {
void KillNamesAndDecorates(uint32_t id);
// Kill all name and decorate ops targeting the result id of |inst|.
void KillNamesAndDecorates(ir::Instruction* inst);
void KillNamesAndDecorates(opt::Instruction* inst);
// Returns the next unique id for use by an instruction.
inline uint32_t TakeNextUniqueId() {
@ -400,7 +400,7 @@ class IRContext {
}
// Returns a pointer to the CFG for all the functions in |module_|.
ir::CFG* cfg() {
opt::CFG* cfg() {
if (!AreAnalysesValid(kAnalysisCFG)) {
BuildCFG();
}
@ -408,21 +408,21 @@ class IRContext {
}
// Gets the loop descriptor for function |f|.
ir::LoopDescriptor* GetLoopDescriptor(const ir::Function* f);
opt::LoopDescriptor* GetLoopDescriptor(const opt::Function* f);
// Gets the dominator analysis for function |f|.
opt::DominatorAnalysis* GetDominatorAnalysis(const ir::Function* f);
opt::DominatorAnalysis* GetDominatorAnalysis(const opt::Function* f);
// Gets the postdominator analysis for function |f|.
opt::PostDominatorAnalysis* GetPostDominatorAnalysis(const ir::Function* f);
opt::PostDominatorAnalysis* GetPostDominatorAnalysis(const opt::Function* f);
// Remove the dominator tree of |f| from the cache.
inline void RemoveDominatorAnalysis(const ir::Function* f) {
inline void RemoveDominatorAnalysis(const opt::Function* f) {
dominator_trees_.erase(f);
}
// Remove the postdominator tree of |f| from the cache.
inline void RemovePostDominatorAnalysis(const ir::Function* f) {
inline void RemovePostDominatorAnalysis(const opt::Function* f) {
post_dominator_trees_.erase(f);
}
@ -462,7 +462,7 @@ class IRContext {
instr_to_block_.clear();
for (auto& fn : *module_) {
for (auto& block : fn) {
block.ForEachInst([this, &block](ir::Instruction* inst) {
block.ForEachInst([this, &block](opt::Instruction* inst) {
instr_to_block_[inst] = &block;
});
}
@ -476,7 +476,7 @@ class IRContext {
}
void BuildCFG() {
cfg_.reset(new ir::CFG(module()));
cfg_.reset(new opt::CFG(module()));
valid_analyses_ = valid_analyses_ | kAnalysisCFG;
}
@ -528,7 +528,7 @@ class IRContext {
void AddCombinatorsForCapability(uint32_t capability);
// Add the combinator opcode for the given extension to combinator_ops_.
void AddCombinatorsForExtension(ir::Instruction* extension);
void AddCombinatorsForExtension(opt::Instruction* extension);
// Remove |inst| from |id_to_name_| if it is in map.
void RemoveFromIdToName(const Instruction* inst);
@ -569,7 +569,7 @@ class IRContext {
//
// NOTE: Do not traverse this map. Ever. Use the function and basic block
// iterators to traverse instructions.
std::unordered_map<ir::Instruction*, ir::BasicBlock*> instr_to_block_;
std::unordered_map<opt::Instruction*, opt::BasicBlock*> instr_to_block_;
// A bitset indicating which analyes are currently valid.
Analysis valid_analyses_;
@ -579,16 +579,17 @@ class IRContext {
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> combinator_ops_;
// The CFG for all the functions in |module_|.
std::unique_ptr<ir::CFG> cfg_;
std::unique_ptr<opt::CFG> cfg_;
// Each function in the module will create its own dominator tree. We cache
// the result so it doesn't need to be rebuilt each time.
std::map<const ir::Function*, opt::DominatorAnalysis> dominator_trees_;
std::map<const ir::Function*, opt::PostDominatorAnalysis>
std::map<const opt::Function*, opt::DominatorAnalysis> dominator_trees_;
std::map<const opt::Function*, opt::PostDominatorAnalysis>
post_dominator_trees_;
// Cache of loop descriptors for each function.
std::unordered_map<const ir::Function*, ir::LoopDescriptor> loop_descriptors_;
std::unordered_map<const opt::Function*, opt::LoopDescriptor>
loop_descriptors_;
// Constant manager for |module_|.
std::unique_ptr<opt::analysis::ConstantManager> constant_mgr_;
@ -610,27 +611,27 @@ class IRContext {
std::unique_ptr<opt::InstructionFolder> inst_folder_;
};
inline ir::IRContext::Analysis operator|(ir::IRContext::Analysis lhs,
ir::IRContext::Analysis rhs) {
return static_cast<ir::IRContext::Analysis>(static_cast<int>(lhs) |
static_cast<int>(rhs));
inline opt::IRContext::Analysis operator|(opt::IRContext::Analysis lhs,
opt::IRContext::Analysis rhs) {
return static_cast<opt::IRContext::Analysis>(static_cast<int>(lhs) |
static_cast<int>(rhs));
}
inline ir::IRContext::Analysis& operator|=(ir::IRContext::Analysis& lhs,
ir::IRContext::Analysis rhs) {
lhs = static_cast<ir::IRContext::Analysis>(static_cast<int>(lhs) |
static_cast<int>(rhs));
inline opt::IRContext::Analysis& operator|=(opt::IRContext::Analysis& lhs,
opt::IRContext::Analysis rhs) {
lhs = static_cast<opt::IRContext::Analysis>(static_cast<int>(lhs) |
static_cast<int>(rhs));
return lhs;
}
inline ir::IRContext::Analysis operator<<(ir::IRContext::Analysis a,
int shift) {
return static_cast<ir::IRContext::Analysis>(static_cast<int>(a) << shift);
inline opt::IRContext::Analysis operator<<(opt::IRContext::Analysis a,
int shift) {
return static_cast<opt::IRContext::Analysis>(static_cast<int>(a) << shift);
}
inline ir::IRContext::Analysis& operator<<=(ir::IRContext::Analysis& a,
int shift) {
a = static_cast<ir::IRContext::Analysis>(static_cast<int>(a) << shift);
inline opt::IRContext::Analysis& operator<<=(opt::IRContext::Analysis& a,
int shift) {
a = static_cast<opt::IRContext::Analysis>(static_cast<int>(a) << shift);
return a;
}
@ -674,11 +675,11 @@ IteratorRange<Module::const_inst_iterator> IRContext::capabilities() const {
return ((const Module*)module())->capabilities();
}
ir::Module::inst_iterator IRContext::types_values_begin() {
opt::Module::inst_iterator IRContext::types_values_begin() {
return module()->types_values_begin();
}
ir::Module::inst_iterator IRContext::types_values_end() {
opt::Module::inst_iterator IRContext::types_values_end() {
return module()->types_values_end();
}
@ -849,7 +850,7 @@ IRContext::GetNames(uint32_t id) {
return make_range(std::move(result.first), std::move(result.second));
}
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // SPIRV_TOOLS_IR_CONTEXT_H

View File

@ -18,7 +18,7 @@
#include "reflect.h"
namespace spvtools {
namespace ir {
namespace opt {
IrLoader::IrLoader(const MessageConsumer& consumer, Module* m)
: consumer_(consumer),
@ -157,5 +157,5 @@ void IrLoader::EndModule() {
}
}
} // namespace ir
} // namespace opt
} // namespace spvtools

View File

@ -23,7 +23,7 @@
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
namespace ir {
namespace opt {
// Loader class for constructing SPIR-V in-memory IR representation. Methods in
// this class are designed to work with the interface for spvBinaryParse() in
@ -78,7 +78,7 @@ class IrLoader {
std::vector<Instruction> dbg_line_info_;
};
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_IR_LOADER_H_

View File

@ -22,7 +22,7 @@
#include <vector>
namespace spvtools {
namespace ir {
namespace opt {
// An ad hoc iterator class for std::vector<std::unique_ptr<|ValueType|>>. The
// purpose of this iterator class is to provide transparent access to those
@ -351,7 +351,7 @@ inline
return UptrVectorIterator(container_, container_->begin() + index);
}
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_ITERATOR_H_

View File

@ -22,7 +22,7 @@
namespace spvtools {
namespace opt {
Pass::Status LICMPass::Process(ir::IRContext* c) {
Pass::Status LICMPass::Process(opt::IRContext* c) {
InitializeProcessing(c);
bool modified = false;
@ -35,21 +35,21 @@ Pass::Status LICMPass::Process(ir::IRContext* c) {
bool LICMPass::ProcessIRContext() {
bool modified = false;
ir::Module* module = get_module();
opt::Module* module = get_module();
// Process each function in the module
for (ir::Function& f : *module) {
for (opt::Function& f : *module) {
modified |= ProcessFunction(&f);
}
return modified;
}
bool LICMPass::ProcessFunction(ir::Function* f) {
bool LICMPass::ProcessFunction(opt::Function* f) {
bool modified = false;
ir::LoopDescriptor* loop_descriptor = context()->GetLoopDescriptor(f);
opt::LoopDescriptor* loop_descriptor = context()->GetLoopDescriptor(f);
// Process each loop in the function
for (ir::Loop& loop : *loop_descriptor) {
for (opt::Loop& loop : *loop_descriptor) {
// Ignore nested loops, as we will process them in order in ProcessLoop
if (loop.IsNested()) {
continue;
@ -59,19 +59,19 @@ bool LICMPass::ProcessFunction(ir::Function* f) {
return modified;
}
bool LICMPass::ProcessLoop(ir::Loop* loop, ir::Function* f) {
bool LICMPass::ProcessLoop(opt::Loop* loop, opt::Function* f) {
bool modified = false;
// Process all nested loops first
for (ir::Loop* nested_loop : *loop) {
for (opt::Loop* nested_loop : *loop) {
modified |= ProcessLoop(nested_loop, f);
}
std::vector<ir::BasicBlock*> loop_bbs{};
std::vector<opt::BasicBlock*> loop_bbs{};
modified |= AnalyseAndHoistFromBB(loop, f, loop->GetHeaderBlock(), &loop_bbs);
for (size_t i = 0; i < loop_bbs.size(); ++i) {
ir::BasicBlock* bb = loop_bbs[i];
opt::BasicBlock* bb = loop_bbs[i];
// do not delete the element
modified |= AnalyseAndHoistFromBB(loop, f, bb, &loop_bbs);
}
@ -79,12 +79,12 @@ bool LICMPass::ProcessLoop(ir::Loop* loop, ir::Function* f) {
return modified;
}
bool LICMPass::AnalyseAndHoistFromBB(ir::Loop* loop, ir::Function* f,
ir::BasicBlock* bb,
std::vector<ir::BasicBlock*>* loop_bbs) {
bool LICMPass::AnalyseAndHoistFromBB(opt::Loop* loop, opt::Function* f,
opt::BasicBlock* bb,
std::vector<opt::BasicBlock*>* loop_bbs) {
bool modified = false;
std::function<void(ir::Instruction*)> hoist_inst =
[this, &loop, &modified](ir::Instruction* inst) {
std::function<void(opt::Instruction*)> hoist_inst =
[this, &loop, &modified](opt::Instruction* inst) {
if (loop->ShouldHoistInstruction(this->context(), inst)) {
HoistInstruction(loop, inst);
modified = true;
@ -108,14 +108,14 @@ bool LICMPass::AnalyseAndHoistFromBB(ir::Loop* loop, ir::Function* f,
return modified;
}
bool LICMPass::IsImmediatelyContainedInLoop(ir::Loop* loop, ir::Function* f,
ir::BasicBlock* bb) {
ir::LoopDescriptor* loop_descriptor = context()->GetLoopDescriptor(f);
bool LICMPass::IsImmediatelyContainedInLoop(opt::Loop* loop, opt::Function* f,
opt::BasicBlock* bb) {
opt::LoopDescriptor* loop_descriptor = context()->GetLoopDescriptor(f);
return loop == (*loop_descriptor)[bb->id()];
}
void LICMPass::HoistInstruction(ir::Loop* loop, ir::Instruction* inst) {
ir::BasicBlock* pre_header_bb = loop->GetOrCreatePreHeaderBlock();
void LICMPass::HoistInstruction(opt::Loop* loop, opt::Instruction* inst) {
opt::BasicBlock* pre_header_bb = loop->GetOrCreatePreHeaderBlock();
inst->InsertBefore(std::move(&(*pre_header_bb->tail())));
context()->set_instr_block(inst, pre_header_bb);
}

View File

@ -30,7 +30,7 @@ class LICMPass : public Pass {
LICMPass() {}
const char* name() const override { return "loop-invariant-code-motion"; }
Status Process(ir::IRContext*) override;
Status Process(opt::IRContext*) override;
private:
// Searches the IRContext for functions and processes each, moving invariants
@ -40,26 +40,26 @@ class LICMPass : public Pass {
// Checks the function for loops, calling ProcessLoop on each one found.
// Returns true if a change was made to the function, false otherwise.
bool ProcessFunction(ir::Function* f);
bool ProcessFunction(opt::Function* f);
// Checks for invariants in the loop and attempts to move them to the loops
// preheader. Works from inner loop to outer when nested loops are found.
// Returns true if a change was made to the loop, false otherwise.
bool ProcessLoop(ir::Loop* loop, ir::Function* f);
bool ProcessLoop(opt::Loop* loop, opt::Function* f);
// Analyses each instruction in |bb|, hoisting invariants to |pre_header_bb|.
// Each child of |bb| wrt to |dom_tree| is pushed to |loop_bbs|
bool AnalyseAndHoistFromBB(ir::Loop* loop, ir::Function* f,
ir::BasicBlock* bb,
std::vector<ir::BasicBlock*>* loop_bbs);
bool AnalyseAndHoistFromBB(opt::Loop* loop, opt::Function* f,
opt::BasicBlock* bb,
std::vector<opt::BasicBlock*>* loop_bbs);
// Returns true if |bb| is immediately contained in |loop|
bool IsImmediatelyContainedInLoop(ir::Loop* loop, ir::Function* f,
ir::BasicBlock* bb);
bool IsImmediatelyContainedInLoop(opt::Loop* loop, opt::Function* f,
opt::BasicBlock* bb);
// Move the instruction to the given BasicBlock
// This method will update the instruction to block mapping for the context
void HoistInstruction(ir::Loop* loop, ir::Instruction* inst);
void HoistInstruction(opt::Loop* loop, opt::Instruction* inst);
};
} // namespace opt

View File

@ -33,20 +33,20 @@ const uint32_t kTypeIntWidthInIdx = 0;
void LocalAccessChainConvertPass::BuildAndAppendInst(
SpvOp opcode, uint32_t typeId, uint32_t resultId,
const std::vector<ir::Operand>& in_opnds,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
std::unique_ptr<ir::Instruction> newInst(
new ir::Instruction(context(), opcode, typeId, resultId, in_opnds));
const std::vector<opt::Operand>& in_opnds,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts) {
std::unique_ptr<opt::Instruction> newInst(
new opt::Instruction(context(), opcode, typeId, resultId, in_opnds));
get_def_use_mgr()->AnalyzeInstDefUse(&*newInst);
newInsts->emplace_back(std::move(newInst));
}
uint32_t LocalAccessChainConvertPass::BuildAndAppendVarLoad(
const ir::Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
const opt::Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts) {
const uint32_t ldResultId = TakeNextId();
*varId = ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx);
const ir::Instruction* varInst = get_def_use_mgr()->GetDef(*varId);
const opt::Instruction* varInst = get_def_use_mgr()->GetDef(*varId);
assert(varInst->opcode() == SpvOpVariable);
*varPteTypeId = GetPointeeTypeId(varInst);
BuildAndAppendInst(SpvOpLoad, *varPteTypeId, ldResultId,
@ -56,11 +56,11 @@ uint32_t LocalAccessChainConvertPass::BuildAndAppendVarLoad(
}
void LocalAccessChainConvertPass::AppendConstantOperands(
const ir::Instruction* ptrInst, std::vector<ir::Operand>* in_opnds) {
const opt::Instruction* ptrInst, std::vector<opt::Operand>* in_opnds) {
uint32_t iidIdx = 0;
ptrInst->ForEachInId([&iidIdx, &in_opnds, this](const uint32_t* iid) {
if (iidIdx > 0) {
const ir::Instruction* cInst = get_def_use_mgr()->GetDef(*iid);
const opt::Instruction* cInst = get_def_use_mgr()->GetDef(*iid);
uint32_t val = cInst->GetSingleWordInOperand(kConstantValueInIdx);
in_opnds->push_back(
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {val}});
@ -70,8 +70,8 @@ void LocalAccessChainConvertPass::AppendConstantOperands(
}
uint32_t LocalAccessChainConvertPass::GenAccessChainLoadReplacement(
const ir::Instruction* ptrInst,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
const opt::Instruction* ptrInst,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts) {
// Build and append load of variable in ptrInst
uint32_t varId;
uint32_t varPteTypeId;
@ -81,7 +81,7 @@ uint32_t LocalAccessChainConvertPass::GenAccessChainLoadReplacement(
// Build and append Extract
const uint32_t extResultId = TakeNextId();
const uint32_t ptrPteTypeId = GetPointeeTypeId(ptrInst);
std::vector<ir::Operand> ext_in_opnds = {
std::vector<opt::Operand> ext_in_opnds = {
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}}};
AppendConstantOperands(ptrInst, &ext_in_opnds);
BuildAndAppendInst(SpvOpCompositeExtract, ptrPteTypeId, extResultId,
@ -90,8 +90,8 @@ uint32_t LocalAccessChainConvertPass::GenAccessChainLoadReplacement(
}
void LocalAccessChainConvertPass::GenAccessChainStoreReplacement(
const ir::Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
const opt::Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts) {
// Build and append load of variable in ptrInst
uint32_t varId;
uint32_t varPteTypeId;
@ -100,7 +100,7 @@ void LocalAccessChainConvertPass::GenAccessChainStoreReplacement(
// Build and append Insert
const uint32_t insResultId = TakeNextId();
std::vector<ir::Operand> ins_in_opnds = {
std::vector<opt::Operand> ins_in_opnds = {
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {valId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}}};
AppendConstantOperands(ptrInst, &ins_in_opnds);
@ -115,11 +115,11 @@ void LocalAccessChainConvertPass::GenAccessChainStoreReplacement(
}
bool LocalAccessChainConvertPass::IsConstantIndexAccessChain(
const ir::Instruction* acp) const {
const opt::Instruction* acp) const {
uint32_t inIdx = 0;
return acp->WhileEachInId([&inIdx, this](const uint32_t* tid) {
if (inIdx > 0) {
ir::Instruction* opInst = get_def_use_mgr()->GetDef(*tid);
opt::Instruction* opInst = get_def_use_mgr()->GetDef(*tid);
if (opInst->opcode() != SpvOpConstant) return false;
}
++inIdx;
@ -129,7 +129,7 @@ bool LocalAccessChainConvertPass::IsConstantIndexAccessChain(
bool LocalAccessChainConvertPass::HasOnlySupportedRefs(uint32_t ptrId) {
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
if (get_def_use_mgr()->WhileEachUser(ptrId, [this](ir::Instruction* user) {
if (get_def_use_mgr()->WhileEachUser(ptrId, [this](opt::Instruction* user) {
SpvOp op = user->opcode();
if (IsNonPtrAccessChain(op) || op == SpvOpCopyObject) {
if (!HasOnlySupportedRefs(user->result_id())) {
@ -147,14 +147,14 @@ bool LocalAccessChainConvertPass::HasOnlySupportedRefs(uint32_t ptrId) {
return false;
}
void LocalAccessChainConvertPass::FindTargetVars(ir::Function* func) {
void LocalAccessChainConvertPass::FindTargetVars(opt::Function* func) {
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
switch (ii->opcode()) {
case SpvOpStore:
case SpvOpLoad: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
opt::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId)) break;
const SpvOp op = ptrInst->opcode();
// Rule out variables with non-supported refs eg function calls
@ -185,21 +185,22 @@ void LocalAccessChainConvertPass::FindTargetVars(ir::Function* func) {
}
}
bool LocalAccessChainConvertPass::ConvertLocalAccessChains(ir::Function* func) {
bool LocalAccessChainConvertPass::ConvertLocalAccessChains(
opt::Function* func) {
FindTargetVars(func);
// Replace access chains of all targeted variables with equivalent
// extract and insert sequences
bool modified = false;
for (auto bi = func->begin(); bi != func->end(); ++bi) {
std::vector<ir::Instruction*> dead_instructions;
std::vector<opt::Instruction*> dead_instructions;
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
switch (ii->opcode()) {
case SpvOpLoad: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
opt::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsNonPtrAccessChain(ptrInst->opcode())) break;
if (!IsTargetVar(varId)) break;
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
std::vector<std::unique_ptr<opt::Instruction>> newInsts;
uint32_t replId = GenAccessChainLoadReplacement(ptrInst, &newInsts);
context()->KillNamesAndDecorates(&*ii);
context()->ReplaceAllUsesWith(ii->result_id(), replId);
@ -211,10 +212,10 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(ir::Function* func) {
} break;
case SpvOpStore: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
opt::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsNonPtrAccessChain(ptrInst->opcode())) break;
if (!IsTargetVar(varId)) break;
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
std::vector<std::unique_ptr<opt::Instruction>> newInsts;
uint32_t valId = ii->GetSingleWordInOperand(kStoreValIdInIdx);
GenAccessChainStoreReplacement(ptrInst, valId, &newInsts);
dead_instructions.push_back(&*ii);
@ -230,9 +231,9 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(ir::Function* func) {
}
while (!dead_instructions.empty()) {
ir::Instruction* inst = dead_instructions.back();
opt::Instruction* inst = dead_instructions.back();
dead_instructions.pop_back();
DCEInst(inst, [&dead_instructions](ir::Instruction* other_inst) {
DCEInst(inst, [&dead_instructions](opt::Instruction* other_inst) {
auto i = std::find(dead_instructions.begin(), dead_instructions.end(),
other_inst);
if (i != dead_instructions.end()) {
@ -244,7 +245,7 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(ir::Function* func) {
return modified;
}
void LocalAccessChainConvertPass::Initialize(ir::IRContext* c) {
void LocalAccessChainConvertPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
// Initialize Target Variable Caches
@ -272,7 +273,7 @@ bool LocalAccessChainConvertPass::AllExtensionsSupported() const {
Pass::Status LocalAccessChainConvertPass::ProcessImpl() {
// If non-32-bit integer type in module, terminate processing
// TODO(): Handle non-32-bit integer constants in access chains
for (const ir::Instruction& inst : get_module()->types_values())
for (const opt::Instruction& inst : get_module()->types_values())
if (inst.opcode() == SpvOpTypeInt &&
inst.GetSingleWordInOperand(kTypeIntWidthInIdx) != 32)
return Status::SuccessWithoutChange;
@ -284,7 +285,7 @@ Pass::Status LocalAccessChainConvertPass::ProcessImpl() {
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return ConvertLocalAccessChains(fp);
};
bool modified = ProcessEntryPointCallTree(pfn, get_module());
@ -293,7 +294,7 @@ Pass::Status LocalAccessChainConvertPass::ProcessImpl() {
LocalAccessChainConvertPass::LocalAccessChainConvertPass() {}
Pass::Status LocalAccessChainConvertPass::Process(ir::IRContext* c) {
Pass::Status LocalAccessChainConvertPass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -37,13 +37,13 @@ class LocalAccessChainConvertPass : public MemPass {
public:
LocalAccessChainConvertPass();
const char* name() const override { return "convert-local-access-chains"; }
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse;
}
using ProcessFunction = std::function<bool(ir::Function*)>;
using ProcessFunction = std::function<bool(opt::Function*)>;
private:
// Return true if all refs through |ptrId| are only loads or stores and
@ -55,42 +55,42 @@ class LocalAccessChainConvertPass : public MemPass {
// Search |func| and cache function scope variables of target type that are
// not accessed with non-constant-index access chains. Also cache non-target
// variables.
void FindTargetVars(ir::Function* func);
void FindTargetVars(opt::Function* func);
// Build instruction from |opcode|, |typeId|, |resultId|, and |in_opnds|.
// Append to |newInsts|.
void BuildAndAppendInst(
SpvOp opcode, uint32_t typeId, uint32_t resultId,
const std::vector<ir::Operand>& in_opnds,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
const std::vector<opt::Operand>& in_opnds,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts);
// Build load of variable in |ptrInst| and append to |newInsts|.
// Return var in |varId| and its pointee type in |varPteTypeId|.
uint32_t BuildAndAppendVarLoad(
const ir::Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
const opt::Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts);
// Append literal integer operands to |in_opnds| corresponding to constant
// integer operands from access chain |ptrInst|. Assumes all indices in
// access chains are OpConstant.
void AppendConstantOperands(const ir::Instruction* ptrInst,
std::vector<ir::Operand>* in_opnds);
void AppendConstantOperands(const opt::Instruction* ptrInst,
std::vector<opt::Operand>* in_opnds);
// Create a load/insert/store equivalent to a store of
// |valId| through (constant index) access chaing |ptrInst|.
// Append to |newInsts|.
void GenAccessChainStoreReplacement(
const ir::Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
const opt::Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts);
// For the (constant index) access chain |ptrInst|, create an
// equivalent load and extract. Append to |newInsts|.
uint32_t GenAccessChainLoadReplacement(
const ir::Instruction* ptrInst,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
const opt::Instruction* ptrInst,
std::vector<std::unique_ptr<opt::Instruction>>* newInsts);
// Return true if all indices of access chain |acp| are OpConstant integers
bool IsConstantIndexAccessChain(const ir::Instruction* acp) const;
bool IsConstantIndexAccessChain(const opt::Instruction* acp) const;
// Identify all function scope variables of target type which are
// accessed only with loads, stores and access chains with constant
@ -101,7 +101,7 @@ class LocalAccessChainConvertPass : public MemPass {
//
// Nested access chains and pointer access chains are not currently
// converted.
bool ConvertLocalAccessChains(ir::Function* func);
bool ConvertLocalAccessChains(opt::Function* func);
// Initialize extensions whitelist
void InitExtensions();
@ -109,7 +109,7 @@ class LocalAccessChainConvertPass : public MemPass {
// Return true if all extensions in this module are allowed by this pass.
bool AllExtensionsSupported() const;
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
// Variables with only supported references, ie. loads and stores using

View File

@ -19,7 +19,7 @@
namespace spvtools {
namespace opt {
Pass::Status LocalRedundancyEliminationPass::Process(ir::IRContext* c) {
Pass::Status LocalRedundancyEliminationPass::Process(opt::IRContext* c) {
InitializeProcessing(c);
bool modified = false;
@ -39,11 +39,12 @@ Pass::Status LocalRedundancyEliminationPass::Process(ir::IRContext* c) {
}
bool LocalRedundancyEliminationPass::EliminateRedundanciesInBB(
ir::BasicBlock* block, const ValueNumberTable& vnTable,
opt::BasicBlock* block, const ValueNumberTable& vnTable,
std::map<uint32_t, uint32_t>* value_to_ids) {
bool modified = false;
auto func = [this, &vnTable, &modified, value_to_ids](ir::Instruction* inst) {
auto func = [this, &vnTable, &modified,
value_to_ids](opt::Instruction* inst) {
if (inst->result_id() == 0) {
return;
}

View File

@ -32,14 +32,14 @@ namespace opt {
class LocalRedundancyEliminationPass : public Pass {
public:
const char* name() const override { return "local-redundancy-elimination"; }
Status Process(ir::IRContext*) override;
virtual ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping |
ir::IRContext::kAnalysisDecorations |
ir::IRContext::kAnalysisCombinators | ir::IRContext::kAnalysisCFG |
ir::IRContext::kAnalysisDominatorAnalysis |
ir::IRContext::kAnalysisNameMap;
Status Process(opt::IRContext*) override;
virtual opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping |
opt::IRContext::kAnalysisDecorations |
opt::IRContext::kAnalysisCombinators | opt::IRContext::kAnalysisCFG |
opt::IRContext::kAnalysisDominatorAnalysis |
opt::IRContext::kAnalysisNameMap;
}
protected:
@ -54,7 +54,7 @@ class LocalRedundancyEliminationPass : public Pass {
// dominates |bb|.
//
// Returns true if the module is changed.
bool EliminateRedundanciesInBB(ir::BasicBlock* block,
bool EliminateRedundanciesInBB(opt::BasicBlock* block,
const ValueNumberTable& vnTable,
std::map<uint32_t, uint32_t>* value_to_ids);
};

View File

@ -29,7 +29,7 @@ const uint32_t kStoreValIdInIdx = 1;
bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
if (get_def_use_mgr()->WhileEachUser(ptrId, [this](ir::Instruction* user) {
if (get_def_use_mgr()->WhileEachUser(ptrId, [this](opt::Instruction* user) {
SpvOp op = user->opcode();
if (IsNonPtrAccessChain(op) || op == SpvOpCopyObject) {
if (!HasOnlySupportedRefs(user->result_id())) {
@ -48,12 +48,12 @@ bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
}
bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim(
ir::Function* func) {
opt::Function* func) {
// Perform local store/load, load/load and store/store elimination
// on each block
bool modified = false;
std::vector<ir::Instruction*> instructions_to_kill;
std::unordered_set<ir::Instruction*> instructions_to_save;
std::vector<opt::Instruction*> instructions_to_kill;
std::unordered_set<opt::Instruction*> instructions_to_save;
for (auto bi = func->begin(); bi != func->end(); ++bi) {
var2store_.clear();
var2load_.clear();
@ -64,7 +64,7 @@ bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim(
case SpvOpStore: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
opt::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId)) continue;
if (!HasOnlySupportedRefs(varId)) continue;
// If a store to the whole variable, remember it for succeeding
@ -106,7 +106,7 @@ bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim(
case SpvOpLoad: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
opt::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId)) continue;
if (!HasOnlySupportedRefs(varId)) continue;
uint32_t replId = 0;
@ -151,14 +151,14 @@ bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim(
}
}
for (ir::Instruction* inst : instructions_to_kill) {
for (opt::Instruction* inst : instructions_to_kill) {
context()->KillInst(inst);
}
return modified;
}
void LocalSingleBlockLoadStoreElimPass::Initialize(ir::IRContext* c) {
void LocalSingleBlockLoadStoreElimPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
// Initialize Target Type Caches
@ -196,7 +196,7 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::ProcessImpl() {
// return unmodified.
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return LocalSingleBlockLoadStoreElim(fp);
};
@ -206,7 +206,7 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::ProcessImpl() {
LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElimPass() {}
Pass::Status LocalSingleBlockLoadStoreElimPass::Process(ir::IRContext* c) {
Pass::Status LocalSingleBlockLoadStoreElimPass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -37,11 +37,11 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass {
public:
LocalSingleBlockLoadStoreElimPass();
const char* name() const override { return "eliminate-local-single-block"; }
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping;
}
private:
@ -58,7 +58,7 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass {
// load id with previous id and delete load. Finally, check if
// remaining stores are useless, and delete store and variable
// where possible. Assumes logical addressing.
bool LocalSingleBlockLoadStoreElim(ir::Function* func);
bool LocalSingleBlockLoadStoreElim(opt::Function* func);
// Initialize extensions whitelist
void InitExtensions();
@ -66,7 +66,7 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass {
// Return true if all extensions in this module are supported by this pass.
bool AllExtensionsSupported() const;
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
// Map from function scope variable to a store of that variable in the
@ -74,14 +74,14 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass {
// at the start of each block and incrementally updated as the block
// is scanned. The stores are candidates for elimination. The map is
// conservatively cleared when a function call is encountered.
std::unordered_map<uint32_t, ir::Instruction*> var2store_;
std::unordered_map<uint32_t, opt::Instruction*> var2store_;
// Map from function scope variable to a load of that variable in the
// current block whose value is currently valid. This map is cleared
// at the start of each block and incrementally updated as the block
// is scanned. The stores are candidates for elimination. The map is
// conservatively cleared when a function call is encountered.
std::unordered_map<uint32_t, ir::Instruction*> var2load_;
std::unordered_map<uint32_t, opt::Instruction*> var2load_;
// Set of variables whose most recent store in the current block cannot be
// deleted, for example, if there is a load of the variable which is

View File

@ -30,12 +30,12 @@ const uint32_t kVariableInitIdInIdx = 1;
} // anonymous namespace
bool LocalSingleStoreElimPass::LocalSingleStoreElim(ir::Function* func) {
bool LocalSingleStoreElimPass::LocalSingleStoreElim(opt::Function* func) {
bool modified = false;
// Check all function scope variables in |func|.
ir::BasicBlock* entry_block = &*func->begin();
for (ir::Instruction& inst : *entry_block) {
opt::BasicBlock* entry_block = &*func->begin();
for (opt::Instruction& inst : *entry_block) {
if (inst.opcode() != SpvOpVariable) {
break;
}
@ -45,7 +45,7 @@ bool LocalSingleStoreElimPass::LocalSingleStoreElim(ir::Function* func) {
return modified;
}
void LocalSingleStoreElimPass::Initialize(ir::IRContext* irContext) {
void LocalSingleStoreElimPass::Initialize(opt::IRContext* irContext) {
InitializeProcessing(irContext);
InitExtensionWhiteList();
}
@ -69,7 +69,7 @@ Pass::Status LocalSingleStoreElimPass::ProcessImpl() {
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return LocalSingleStoreElim(fp);
};
bool modified = ProcessEntryPointCallTree(pfn, get_module());
@ -78,7 +78,7 @@ Pass::Status LocalSingleStoreElimPass::ProcessImpl() {
LocalSingleStoreElimPass::LocalSingleStoreElimPass() {}
Pass::Status LocalSingleStoreElimPass::Process(ir::IRContext* irContext) {
Pass::Status LocalSingleStoreElimPass::Process(opt::IRContext* irContext) {
Initialize(irContext);
return ProcessImpl();
}
@ -120,11 +120,11 @@ void LocalSingleStoreElimPass::InitExtensionWhiteList() {
"SPV_EXT_descriptor_indexing",
});
}
bool LocalSingleStoreElimPass::ProcessVariable(ir::Instruction* var_inst) {
vector<ir::Instruction*> users;
bool LocalSingleStoreElimPass::ProcessVariable(opt::Instruction* var_inst) {
vector<opt::Instruction*> users;
FindUses(var_inst, &users);
ir::Instruction* store_inst = FindSingleStoreAndCheckUses(var_inst, users);
opt::Instruction* store_inst = FindSingleStoreAndCheckUses(var_inst, users);
if (store_inst == nullptr) {
return false;
@ -133,17 +133,17 @@ bool LocalSingleStoreElimPass::ProcessVariable(ir::Instruction* var_inst) {
return RewriteLoads(store_inst, users);
}
ir::Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
ir::Instruction* var_inst, const vector<ir::Instruction*>& users) const {
opt::Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
opt::Instruction* var_inst, const vector<opt::Instruction*>& users) const {
// Make sure there is exactly 1 store.
ir::Instruction* store_inst = nullptr;
opt::Instruction* store_inst = nullptr;
// If |var_inst| has an initializer, then that will count as a store.
if (var_inst->NumInOperands() > 1) {
store_inst = var_inst;
}
for (ir::Instruction* user : users) {
for (opt::Instruction* user : users) {
switch (user->opcode()) {
case SpvOpStore:
// Since we are in the relaxed addressing mode, the use has to be the
@ -182,10 +182,10 @@ ir::Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
}
void LocalSingleStoreElimPass::FindUses(
const ir::Instruction* var_inst,
std::vector<ir::Instruction*>* users) const {
const opt::Instruction* var_inst,
std::vector<opt::Instruction*>* users) const {
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
def_use_mgr->ForEachUser(var_inst, [users, this](ir::Instruction* user) {
def_use_mgr->ForEachUser(var_inst, [users, this](opt::Instruction* user) {
users->push_back(user);
if (user->opcode() == SpvOpCopyObject) {
FindUses(user, users);
@ -193,9 +193,9 @@ void LocalSingleStoreElimPass::FindUses(
});
}
bool LocalSingleStoreElimPass::FeedsAStore(ir::Instruction* inst) const {
bool LocalSingleStoreElimPass::FeedsAStore(opt::Instruction* inst) const {
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
return !def_use_mgr->WhileEachUser(inst, [this](ir::Instruction* user) {
return !def_use_mgr->WhileEachUser(inst, [this](opt::Instruction* user) {
switch (user->opcode()) {
case SpvOpStore:
return false;
@ -216,8 +216,8 @@ bool LocalSingleStoreElimPass::FeedsAStore(ir::Instruction* inst) const {
}
bool LocalSingleStoreElimPass::RewriteLoads(
ir::Instruction* store_inst, const std::vector<ir::Instruction*>& uses) {
ir::BasicBlock* store_block = context()->get_instr_block(store_inst);
opt::Instruction* store_inst, const std::vector<opt::Instruction*>& uses) {
opt::BasicBlock* store_block = context()->get_instr_block(store_inst);
opt::DominatorAnalysis* dominator_analysis =
context()->GetDominatorAnalysis(store_block->GetParent());
@ -227,9 +227,9 @@ bool LocalSingleStoreElimPass::RewriteLoads(
else
stored_id = store_inst->GetSingleWordInOperand(kVariableInitIdInIdx);
std::vector<ir::Instruction*> uses_in_store_block;
std::vector<opt::Instruction*> uses_in_store_block;
bool modified = false;
for (ir::Instruction* use : uses) {
for (opt::Instruction* use : uses) {
if (use->opcode() == SpvOpLoad) {
if (dominator_analysis->Dominates(store_inst, use)) {
modified = true;

View File

@ -34,16 +34,16 @@ namespace opt {
// See optimizer.hpp for documentation.
class LocalSingleStoreElimPass : public Pass {
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const opt::BasicBlock*;
public:
LocalSingleStoreElimPass();
const char* name() const override { return "eliminate-local-single-store"; }
Status Process(ir::IRContext* irContext) override;
Status Process(opt::IRContext* irContext) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping;
}
private:
@ -51,7 +51,7 @@ class LocalSingleStoreElimPass : public Pass {
// with a single non-access-chain store in |func|. Replace all their
// non-access-chain loads with the value that is stored and eliminate
// any resulting dead code.
bool LocalSingleStoreElim(ir::Function* func);
bool LocalSingleStoreElim(opt::Function* func);
// Initialize extensions whitelist
void InitExtensionWhiteList();
@ -59,37 +59,37 @@ class LocalSingleStoreElimPass : public Pass {
// Return true if all extensions in this module are allowed by this pass.
bool AllExtensionsSupported() const;
void Initialize(ir::IRContext* irContext);
void Initialize(opt::IRContext* irContext);
Pass::Status ProcessImpl();
// If there is a single store to |var_inst|, and it covers the entire
// variable, then replace all of the loads of the entire variable that are
// dominated by the store by the value that was stored. Returns true if the
// module was changed.
bool ProcessVariable(ir::Instruction* var_inst);
bool ProcessVariable(opt::Instruction* var_inst);
// Collects all of the uses of |var_inst| into |uses|. This looks through
// OpObjectCopy's that copy the address of the variable, and collects those
// uses as well.
void FindUses(const ir::Instruction* var_inst,
std::vector<ir::Instruction*>* uses) const;
void FindUses(const opt::Instruction* var_inst,
std::vector<opt::Instruction*>* uses) const;
// Returns a store to |var_inst| if
// - it is a store to the entire variable,
// - and there are no other instructions that may modify |var_inst|.
ir::Instruction* FindSingleStoreAndCheckUses(
ir::Instruction* var_inst,
const std::vector<ir::Instruction*>& users) const;
opt::Instruction* FindSingleStoreAndCheckUses(
opt::Instruction* var_inst,
const std::vector<opt::Instruction*>& users) const;
// Returns true if the address that results from |inst| may be used as a base
// address in a store instruction or may be used to compute the base address
// of a store instruction.
bool FeedsAStore(ir::Instruction* inst) const;
bool FeedsAStore(opt::Instruction* inst) const;
// Replaces all of the loads in |uses| by the value stored in |store_inst|.
// The load instructions are then killed.
bool RewriteLoads(ir::Instruction* store_inst,
const std::vector<ir::Instruction*>& uses);
bool RewriteLoads(opt::Instruction* store_inst,
const std::vector<opt::Instruction*>& uses);
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;

View File

@ -23,7 +23,7 @@
namespace spvtools {
namespace opt {
void LocalMultiStoreElimPass::Initialize(ir::IRContext* c) {
void LocalMultiStoreElimPass::Initialize(opt::IRContext* c) {
InitializeProcessing(c);
// Initialize extension whitelist
@ -54,7 +54,7 @@ Pass::Status LocalMultiStoreElimPass::ProcessImpl() {
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process functions
ProcessFunction pfn = [this](ir::Function* fp) {
ProcessFunction pfn = [this](opt::Function* fp) {
return SSARewriter(this).RewriteFunctionIntoSSA(fp);
};
bool modified = ProcessEntryPointCallTree(pfn, get_module());
@ -63,7 +63,7 @@ Pass::Status LocalMultiStoreElimPass::ProcessImpl() {
LocalMultiStoreElimPass::LocalMultiStoreElimPass() {}
Pass::Status LocalMultiStoreElimPass::Process(ir::IRContext* c) {
Pass::Status LocalMultiStoreElimPass::Process(opt::IRContext* c) {
Initialize(c);
return ProcessImpl();
}

View File

@ -34,19 +34,19 @@ namespace opt {
// See optimizer.hpp for documentation.
class LocalMultiStoreElimPass : public MemPass {
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const opt::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
std::function<std::vector<opt::BasicBlock*>*(const opt::BasicBlock*)>;
LocalMultiStoreElimPass();
const char* name() const override { return "eliminate-local-multi-store"; }
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping;
opt::IRContext::Analysis GetPreservedAnalyses() override {
return opt::IRContext::kAnalysisDefUse |
opt::IRContext::kAnalysisInstrToBlockMapping;
}
private:
@ -56,7 +56,7 @@ class LocalMultiStoreElimPass : public MemPass {
// Return true if all extensions in this module are allowed by this pass.
bool AllExtensionsSupported() const;
void Initialize(ir::IRContext* c);
void Initialize(opt::IRContext* c);
Pass::Status ProcessImpl();
// Extensions supported by this pass.

View File

@ -181,15 +181,15 @@ bool NormalizeAndCompareFractions(int64_t numerator_0, int64_t denominator_0,
} // namespace
bool LoopDependenceAnalysis::GetDependence(const ir::Instruction* source,
const ir::Instruction* destination,
bool LoopDependenceAnalysis::GetDependence(const opt::Instruction* source,
const opt::Instruction* destination,
DistanceVector* distance_vector) {
// Start off by finding and marking all the loops in |loops_| that are
// irrelevant to the dependence analysis.
MarkUnsusedDistanceEntriesAsIrrelevant(source, destination, distance_vector);
ir::Instruction* source_access_chain = GetOperandDefinition(source, 0);
ir::Instruction* destination_access_chain =
opt::Instruction* source_access_chain = GetOperandDefinition(source, 0);
opt::Instruction* destination_access_chain =
GetOperandDefinition(destination, 0);
auto num_access_chains =
@ -234,8 +234,8 @@ bool LoopDependenceAnalysis::GetDependence(const ir::Instruction* source,
// If the access chains aren't collecting from the same structure there is no
// dependence.
ir::Instruction* source_array = GetOperandDefinition(source_access_chain, 0);
ir::Instruction* destination_array =
opt::Instruction* source_array = GetOperandDefinition(source_access_chain, 0);
opt::Instruction* destination_array =
GetOperandDefinition(destination_access_chain, 0);
// Nested access chains are not supported yet, bail out.
@ -254,8 +254,8 @@ bool LoopDependenceAnalysis::GetDependence(const ir::Instruction* source,
// To handle multiple subscripts we must get every operand in the access
// chains past the first.
std::vector<ir::Instruction*> source_subscripts = GetSubscripts(source);
std::vector<ir::Instruction*> destination_subscripts =
std::vector<opt::Instruction*> source_subscripts = GetSubscripts(source);
std::vector<opt::Instruction*> destination_subscripts =
GetSubscripts(destination);
auto sets_of_subscripts =
@ -263,7 +263,7 @@ bool LoopDependenceAnalysis::GetDependence(const ir::Instruction* source,
auto first_coupled = std::partition(
std::begin(sets_of_subscripts), std::end(sets_of_subscripts),
[](const std::set<std::pair<ir::Instruction*, ir::Instruction*>>& set) {
[](const std::set<std::pair<opt::Instruction*, opt::Instruction*>>& set) {
return set.size() == 1;
});
@ -284,7 +284,7 @@ bool LoopDependenceAnalysis::GetDependence(const ir::Instruction* source,
// Check the loops are in a form we support.
auto subscript_pair = std::make_pair(source_node, destination_node);
const ir::Loop* loop = GetLoopForSubscriptPair(subscript_pair);
const opt::Loop* loop = GetLoopForSubscriptPair(subscript_pair);
if (loop) {
if (!IsSupportedLoop(loop)) {
PrintDebug(
@ -371,9 +371,9 @@ bool LoopDependenceAnalysis::GetDependence(const ir::Instruction* source,
for (const auto& subscript : coupled_subscripts) {
auto loops = CollectLoops(std::get<0>(subscript), std::get<1>(subscript));
auto is_subscript_supported =
std::all_of(std::begin(loops), std::end(loops),
[this](const ir::Loop* l) { return IsSupportedLoop(l); });
auto is_subscript_supported = std::all_of(
std::begin(loops), std::end(loops),
[this](const opt::Loop* l) { return IsSupportedLoop(l); });
supported = supported && is_subscript_supported;
}
@ -541,7 +541,7 @@ bool LoopDependenceAnalysis::StrongSIVTest(SENode* source, SENode* destination,
// Build an SENode for distance.
std::pair<SENode*, SENode*> subscript_pair =
std::make_pair(source, destination);
const ir::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
const opt::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
SENode* source_constant_term =
GetConstantTerm(subscript_loop, source->AsSERecurrentNode());
SENode* destination_constant_term =
@ -676,7 +676,7 @@ bool LoopDependenceAnalysis::SymbolicStrongSIVTest(
// outwith the bounds.
std::pair<SENode*, SENode*> subscript_pair =
std::make_pair(source, destination);
const ir::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
const opt::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
if (IsProvablyOutsideOfLoopBounds(subscript_loop, source_destination_delta,
coefficient)) {
PrintDebug(
@ -701,7 +701,7 @@ bool LoopDependenceAnalysis::WeakZeroSourceSIVTest(
PrintDebug("Performing WeakZeroSourceSIVTest.");
std::pair<SENode*, SENode*> subscript_pair =
std::make_pair(source, destination);
const ir::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
const opt::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
// Build an SENode for distance.
SENode* destination_constant_term =
GetConstantTerm(subscript_loop, destination);
@ -855,7 +855,7 @@ bool LoopDependenceAnalysis::WeakZeroDestinationSIVTest(
// Build an SENode for distance.
std::pair<SENode*, SENode*> subscript_pair =
std::make_pair(source, destination);
const ir::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
const opt::Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
SENode* source_constant_term = GetConstantTerm(subscript_loop, source);
SENode* delta = scalar_evolution_.SimplifyExpression(
scalar_evolution_.CreateSubtraction(destination, source_constant_term));
@ -1115,10 +1115,10 @@ bool LoopDependenceAnalysis::GCDMIVTest(
}
using PartitionedSubscripts =
std::vector<std::set<std::pair<ir::Instruction*, ir::Instruction*>>>;
std::vector<std::set<std::pair<opt::Instruction*, opt::Instruction*>>>;
PartitionedSubscripts LoopDependenceAnalysis::PartitionSubscripts(
const std::vector<ir::Instruction*>& source_subscripts,
const std::vector<ir::Instruction*>& destination_subscripts) {
const std::vector<opt::Instruction*>& source_subscripts,
const std::vector<opt::Instruction*>& destination_subscripts) {
PartitionedSubscripts partitions{};
auto num_subscripts = source_subscripts.size();
@ -1139,7 +1139,7 @@ PartitionedSubscripts LoopDependenceAnalysis::PartitionSubscripts(
auto it = std::find_if(
current_partition.begin(), current_partition.end(),
[loop,
this](const std::pair<ir::Instruction*, ir::Instruction*>& elem)
this](const std::pair<opt::Instruction*, opt::Instruction*>& elem)
-> bool {
auto source_recurrences =
scalar_evolution_.AnalyzeInstruction(std::get<0>(elem))
@ -1177,7 +1177,7 @@ PartitionedSubscripts LoopDependenceAnalysis::PartitionSubscripts(
partitions.erase(
std::remove_if(
partitions.begin(), partitions.end(),
[](const std::set<std::pair<ir::Instruction*, ir::Instruction*>>&
[](const std::set<std::pair<opt::Instruction*, opt::Instruction*>>&
partition) { return partition.empty(); }),
partitions.end());

View File

@ -167,7 +167,7 @@ class DependenceEmpty;
class Constraint {
public:
explicit Constraint(const ir::Loop* loop) : loop_(loop) {}
explicit Constraint(const opt::Loop* loop) : loop_(loop) {}
enum ConstraintType { Line, Distance, Point, None, Empty };
virtual ConstraintType GetType() const = 0;
@ -175,7 +175,7 @@ class Constraint {
virtual ~Constraint() {}
// Get the loop this constraint belongs to.
const ir::Loop* GetLoop() const { return loop_; }
const opt::Loop* GetLoop() const { return loop_; }
bool operator==(const Constraint& other) const;
@ -192,12 +192,12 @@ class Constraint {
#undef DeclareCastMethod
protected:
const ir::Loop* loop_;
const opt::Loop* loop_;
};
class DependenceLine : public Constraint {
public:
DependenceLine(SENode* a, SENode* b, SENode* c, const ir::Loop* loop)
DependenceLine(SENode* a, SENode* b, SENode* c, const opt::Loop* loop)
: Constraint(loop), a_(a), b_(b), c_(c) {}
ConstraintType GetType() const final { return Line; }
@ -217,7 +217,7 @@ class DependenceLine : public Constraint {
class DependenceDistance : public Constraint {
public:
DependenceDistance(SENode* distance, const ir::Loop* loop)
DependenceDistance(SENode* distance, const opt::Loop* loop)
: Constraint(loop), distance_(distance) {}
ConstraintType GetType() const final { return Distance; }
@ -233,7 +233,7 @@ class DependenceDistance : public Constraint {
class DependencePoint : public Constraint {
public:
DependencePoint(SENode* source, SENode* destination, const ir::Loop* loop)
DependencePoint(SENode* source, SENode* destination, const opt::Loop* loop)
: Constraint(loop), source_(source), destination_(destination) {}
ConstraintType GetType() const final { return Point; }
@ -294,8 +294,8 @@ class DependenceEmpty : public Constraint {
// is present in the pair.
class LoopDependenceAnalysis {
public:
LoopDependenceAnalysis(ir::IRContext* context,
std::vector<const ir::Loop*> loops)
LoopDependenceAnalysis(opt::IRContext* context,
std::vector<const opt::Loop*> loops)
: context_(context),
loops_(loops),
scalar_evolution_(context),
@ -308,8 +308,8 @@ class LoopDependenceAnalysis {
// Any direction and distance information found will be stored in
// |distance_vector|.
// Returns true if independence is found, false otherwise.
bool GetDependence(const ir::Instruction* source,
const ir::Instruction* destination,
bool GetDependence(const opt::Instruction* source,
const opt::Instruction* destination,
DistanceVector* distance_vector);
// Returns true if |subscript_pair| represents a Zero Index Variable pair
@ -326,11 +326,11 @@ class LoopDependenceAnalysis {
// Finds the lower bound of |loop| as an SENode* and returns the result.
// The lower bound is the starting value of the loops induction variable
SENode* GetLowerBound(const ir::Loop* loop);
SENode* GetLowerBound(const opt::Loop* loop);
// Finds the upper bound of |loop| as an SENode* and returns the result.
// The upper bound is the last value before the loop exit condition is met.
SENode* GetUpperBound(const ir::Loop* loop);
SENode* GetUpperBound(const opt::Loop* loop);
// Returns true if |value| is between |bound_one| and |bound_two| (inclusive).
bool IsWithinBounds(int64_t value, int64_t bound_one, int64_t bound_two);
@ -338,32 +338,32 @@ class LoopDependenceAnalysis {
// Finds the bounds of |loop| as upper_bound - lower_bound and returns the
// resulting SENode.
// If the operations can not be completed a nullptr is returned.
SENode* GetTripCount(const ir::Loop* loop);
SENode* GetTripCount(const opt::Loop* loop);
// Returns the SENode* produced by building an SENode from the result of
// calling GetInductionInitValue on |loop|.
// If the operation can not be completed a nullptr is returned.
SENode* GetFirstTripInductionNode(const ir::Loop* loop);
SENode* GetFirstTripInductionNode(const opt::Loop* loop);
// Returns the SENode* produced by building an SENode from the result of
// GetFirstTripInductionNode + (GetTripCount - 1) * induction_coefficient.
// If the operation can not be completed a nullptr is returned.
SENode* GetFinalTripInductionNode(const ir::Loop* loop,
SENode* GetFinalTripInductionNode(const opt::Loop* loop,
SENode* induction_coefficient);
// Returns all the distinct loops that appear in |nodes|.
std::set<const ir::Loop*> CollectLoops(
std::set<const opt::Loop*> CollectLoops(
const std::vector<SERecurrentNode*>& nodes);
// Returns all the distinct loops that appear in |source| and |destination|.
std::set<const ir::Loop*> CollectLoops(SENode* source, SENode* destination);
std::set<const opt::Loop*> CollectLoops(SENode* source, SENode* destination);
// Returns true if |distance| is provably outside the loop bounds.
// |coefficient| must be an SENode representing the coefficient of the
// induction variable of |loop|.
// This method is able to handle some symbolic cases which IsWithinBounds
// can't handle.
bool IsProvablyOutsideOfLoopBounds(const ir::Loop* loop, SENode* distance,
bool IsProvablyOutsideOfLoopBounds(const opt::Loop* loop, SENode* distance,
SENode* coefficient);
// Sets the ostream for debug information for the analysis.
@ -393,14 +393,14 @@ class LoopDependenceAnalysis {
// Returns the partitioning of subscript pairs. Sets of size 1 indicates an
// independent subscript-pair and others indicate coupled sets.
using PartitionedSubscripts =
std::vector<std::set<std::pair<ir::Instruction*, ir::Instruction*>>>;
std::vector<std::set<std::pair<opt::Instruction*, opt::Instruction*>>>;
PartitionedSubscripts PartitionSubscripts(
const std::vector<ir::Instruction*>& source_subscripts,
const std::vector<ir::Instruction*>& destination_subscripts);
const std::vector<opt::Instruction*>& source_subscripts,
const std::vector<opt::Instruction*>& destination_subscripts);
// Returns the ir::Loop* matching the loop for |subscript_pair|.
// Returns the opt::Loop* matching the loop for |subscript_pair|.
// |subscript_pair| must be an SIV pair.
const ir::Loop* GetLoopForSubscriptPair(
const opt::Loop* GetLoopForSubscriptPair(
const std::pair<SENode*, SENode*>& subscript_pair);
// Returns the DistanceEntry matching the loop for |subscript_pair|.
@ -410,13 +410,13 @@ class LoopDependenceAnalysis {
DistanceVector* distance_vector);
// Returns the DistanceEntry matching |loop|.
DistanceEntry* GetDistanceEntryForLoop(const ir::Loop* loop,
DistanceEntry* GetDistanceEntryForLoop(const opt::Loop* loop,
DistanceVector* distance_vector);
// Returns a vector of Instruction* which form the subscripts of the array
// access defined by the access chain |instruction|.
std::vector<ir::Instruction*> GetSubscripts(
const ir::Instruction* instruction);
std::vector<opt::Instruction*> GetSubscripts(
const opt::Instruction* instruction);
// Delta test as described in Figure 3 of 'Practical Dependence
// Testing' by Gina Goff, Ken Kennedy, and Chau-Wen Tseng from PLDI '91.
@ -441,18 +441,18 @@ class LoopDependenceAnalysis {
// analysis.
// A loop is supported if it has a single induction variable and that
// induction variable has a step of +1 or -1 per loop iteration.
bool CheckSupportedLoops(std::vector<const ir::Loop*> loops);
bool CheckSupportedLoops(std::vector<const opt::Loop*> loops);
// Returns true if |loop| is in a form supported by this analysis.
// A loop is supported if it has a single induction variable and that
// induction variable has a step of +1 or -1 per loop iteration.
bool IsSupportedLoop(const ir::Loop* loop);
bool IsSupportedLoop(const opt::Loop* loop);
private:
ir::IRContext* context_;
opt::IRContext* context_;
// The loop nest we are analysing the dependence of.
std::vector<const ir::Loop*> loops_;
std::vector<const opt::Loop*> loops_;
// The ScalarEvolutionAnalysis used by this analysis to store and perform much
// of its logic.
@ -514,8 +514,8 @@ class LoopDependenceAnalysis {
// Uses the def_use_mgr to get the instruction referenced by
// SingleWordInOperand(|id|) when called on |instruction|.
ir::Instruction* GetOperandDefinition(const ir::Instruction* instruction,
int id);
opt::Instruction* GetOperandDefinition(const opt::Instruction* instruction,
int id);
// Perform the GCD test if both, the source and the destination nodes, are in
// the form a0*i0 + a1*i1 + ... an*in + c.
@ -533,13 +533,13 @@ class LoopDependenceAnalysis {
// Takes the offset from the induction variable and subtracts the lower bound
// from it to get the constant term added to the induction.
// Returns the resuting constant term, or nullptr if it could not be produced.
SENode* GetConstantTerm(const ir::Loop* loop, SERecurrentNode* induction);
SENode* GetConstantTerm(const opt::Loop* loop, SERecurrentNode* induction);
// Marks all the distance entries in |distance_vector| that were relate to
// loops in |loops_| but were not used in any subscripts as irrelevant to the
// to the dependence test.
void MarkUnsusedDistanceEntriesAsIrrelevant(
const ir::Instruction* source, const ir::Instruction* destination,
const opt::Instruction* source, const opt::Instruction* destination,
DistanceVector* distance_vector);
// Converts |value| to a std::string and returns the result.

View File

@ -47,12 +47,12 @@ bool LoopDependenceAnalysis::IsMIV(
1;
}
SENode* LoopDependenceAnalysis::GetLowerBound(const ir::Loop* loop) {
ir::Instruction* cond_inst = loop->GetConditionInst();
SENode* LoopDependenceAnalysis::GetLowerBound(const opt::Loop* loop) {
opt::Instruction* cond_inst = loop->GetConditionInst();
if (!cond_inst) {
return nullptr;
}
ir::Instruction* lower_inst = GetOperandDefinition(cond_inst, 0);
opt::Instruction* lower_inst = GetOperandDefinition(cond_inst, 0);
switch (cond_inst->opcode()) {
case SpvOpULessThan:
case SpvOpSLessThan:
@ -79,12 +79,12 @@ SENode* LoopDependenceAnalysis::GetLowerBound(const ir::Loop* loop) {
}
}
SENode* LoopDependenceAnalysis::GetUpperBound(const ir::Loop* loop) {
ir::Instruction* cond_inst = loop->GetConditionInst();
SENode* LoopDependenceAnalysis::GetUpperBound(const opt::Loop* loop) {
opt::Instruction* cond_inst = loop->GetConditionInst();
if (!cond_inst) {
return nullptr;
}
ir::Instruction* upper_inst = GetOperandDefinition(cond_inst, 1);
opt::Instruction* upper_inst = GetOperandDefinition(cond_inst, 1);
switch (cond_inst->opcode()) {
case SpvOpULessThan:
case SpvOpSLessThan: {
@ -135,7 +135,7 @@ bool LoopDependenceAnalysis::IsWithinBounds(int64_t value, int64_t bound_one,
}
bool LoopDependenceAnalysis::IsProvablyOutsideOfLoopBounds(
const ir::Loop* loop, SENode* distance, SENode* coefficient) {
const opt::Loop* loop, SENode* distance, SENode* coefficient) {
// We test to see if we can reduce the coefficient to an integral constant.
SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
if (!coefficient_constant) {
@ -196,7 +196,7 @@ bool LoopDependenceAnalysis::IsProvablyOutsideOfLoopBounds(
return false;
}
const ir::Loop* LoopDependenceAnalysis::GetLoopForSubscriptPair(
const opt::Loop* LoopDependenceAnalysis::GetLoopForSubscriptPair(
const std::pair<SENode*, SENode*>& subscript_pair) {
// Collect all the SERecurrentNodes.
std::vector<SERecurrentNode*> source_nodes =
@ -205,7 +205,7 @@ const ir::Loop* LoopDependenceAnalysis::GetLoopForSubscriptPair(
std::get<1>(subscript_pair)->CollectRecurrentNodes();
// Collect all the loops stored by the SERecurrentNodes.
std::unordered_set<const ir::Loop*> loops{};
std::unordered_set<const opt::Loop*> loops{};
for (auto source_nodes_it = source_nodes.begin();
source_nodes_it != source_nodes.end(); ++source_nodes_it) {
loops.insert((*source_nodes_it)->GetLoop());
@ -226,7 +226,7 @@ const ir::Loop* LoopDependenceAnalysis::GetLoopForSubscriptPair(
}
DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForLoop(
const ir::Loop* loop, DistanceVector* distance_vector) {
const opt::Loop* loop, DistanceVector* distance_vector) {
if (!loop) {
return nullptr;
}
@ -245,22 +245,22 @@ DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForLoop(
DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForSubscriptPair(
const std::pair<SENode*, SENode*>& subscript_pair,
DistanceVector* distance_vector) {
const ir::Loop* loop = GetLoopForSubscriptPair(subscript_pair);
const opt::Loop* loop = GetLoopForSubscriptPair(subscript_pair);
return GetDistanceEntryForLoop(loop, distance_vector);
}
SENode* LoopDependenceAnalysis::GetTripCount(const ir::Loop* loop) {
ir::BasicBlock* condition_block = loop->FindConditionBlock();
SENode* LoopDependenceAnalysis::GetTripCount(const opt::Loop* loop) {
opt::BasicBlock* condition_block = loop->FindConditionBlock();
if (!condition_block) {
return nullptr;
}
ir::Instruction* induction_instr =
opt::Instruction* induction_instr =
loop->FindConditionVariable(condition_block);
if (!induction_instr) {
return nullptr;
}
ir::Instruction* cond_instr = loop->GetConditionInst();
opt::Instruction* cond_instr = loop->GetConditionInst();
if (!cond_instr) {
return nullptr;
}
@ -281,12 +281,12 @@ SENode* LoopDependenceAnalysis::GetTripCount(const ir::Loop* loop) {
}
SENode* LoopDependenceAnalysis::GetFirstTripInductionNode(
const ir::Loop* loop) {
ir::BasicBlock* condition_block = loop->FindConditionBlock();
const opt::Loop* loop) {
opt::BasicBlock* condition_block = loop->FindConditionBlock();
if (!condition_block) {
return nullptr;
}
ir::Instruction* induction_instr =
opt::Instruction* induction_instr =
loop->FindConditionVariable(condition_block);
if (!induction_instr) {
return nullptr;
@ -302,7 +302,7 @@ SENode* LoopDependenceAnalysis::GetFirstTripInductionNode(
}
SENode* LoopDependenceAnalysis::GetFinalTripInductionNode(
const ir::Loop* loop, SENode* induction_coefficient) {
const opt::Loop* loop, SENode* induction_coefficient) {
SENode* first_trip_induction_node = GetFirstTripInductionNode(loop);
if (!first_trip_induction_node) {
return nullptr;
@ -319,12 +319,12 @@ SENode* LoopDependenceAnalysis::GetFinalTripInductionNode(
scalar_evolution_.CreateMultiplyNode(trip_count, induction_coefficient)));
}
std::set<const ir::Loop*> LoopDependenceAnalysis::CollectLoops(
std::set<const opt::Loop*> LoopDependenceAnalysis::CollectLoops(
const std::vector<SERecurrentNode*>& recurrent_nodes) {
// We don't handle loops with more than one induction variable. Therefore we
// can identify the number of induction variables by collecting all of the
// loops the collected recurrent nodes belong to.
std::set<const ir::Loop*> loops{};
std::set<const opt::Loop*> loops{};
for (auto recurrent_nodes_it = recurrent_nodes.begin();
recurrent_nodes_it != recurrent_nodes.end(); ++recurrent_nodes_it) {
loops.insert((*recurrent_nodes_it)->GetLoop());
@ -343,23 +343,24 @@ int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* node) {
// We don't handle loops with more than one induction variable. Therefore we
// can identify the number of induction variables by collecting all of the
// loops the collected recurrent nodes belong to.
std::set<const ir::Loop*> loops = CollectLoops(recurrent_nodes);
std::set<const opt::Loop*> loops = CollectLoops(recurrent_nodes);
return static_cast<int64_t>(loops.size());
}
std::set<const ir::Loop*> LoopDependenceAnalysis::CollectLoops(
std::set<const opt::Loop*> LoopDependenceAnalysis::CollectLoops(
SENode* source, SENode* destination) {
if (!source || !destination) {
return std::set<const ir::Loop*>{};
return std::set<const opt::Loop*>{};
}
std::vector<SERecurrentNode*> source_nodes = source->CollectRecurrentNodes();
std::vector<SERecurrentNode*> destination_nodes =
destination->CollectRecurrentNodes();
std::set<const ir::Loop*> loops = CollectLoops(source_nodes);
std::set<const ir::Loop*> destination_loops = CollectLoops(destination_nodes);
std::set<const opt::Loop*> loops = CollectLoops(source_nodes);
std::set<const opt::Loop*> destination_loops =
CollectLoops(destination_nodes);
loops.insert(std::begin(destination_loops), std::end(destination_loops));
@ -372,22 +373,22 @@ int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* source,
return -1;
}
std::set<const ir::Loop*> loops = CollectLoops(source, destination);
std::set<const opt::Loop*> loops = CollectLoops(source, destination);
return static_cast<int64_t>(loops.size());
}
ir::Instruction* LoopDependenceAnalysis::GetOperandDefinition(
const ir::Instruction* instruction, int id) {
opt::Instruction* LoopDependenceAnalysis::GetOperandDefinition(
const opt::Instruction* instruction, int id) {
return context_->get_def_use_mgr()->GetDef(
instruction->GetSingleWordInOperand(id));
}
std::vector<ir::Instruction*> LoopDependenceAnalysis::GetSubscripts(
const ir::Instruction* instruction) {
ir::Instruction* access_chain = GetOperandDefinition(instruction, 0);
std::vector<opt::Instruction*> LoopDependenceAnalysis::GetSubscripts(
const opt::Instruction* instruction) {
opt::Instruction* access_chain = GetOperandDefinition(instruction, 0);
std::vector<ir::Instruction*> subscripts;
std::vector<opt::Instruction*> subscripts;
for (auto i = 1u; i < access_chain->NumInOperandWords(); ++i) {
subscripts.push_back(GetOperandDefinition(access_chain, i));
@ -396,7 +397,7 @@ std::vector<ir::Instruction*> LoopDependenceAnalysis::GetSubscripts(
return subscripts;
}
SENode* LoopDependenceAnalysis::GetConstantTerm(const ir::Loop* loop,
SENode* LoopDependenceAnalysis::GetConstantTerm(const opt::Loop* loop,
SERecurrentNode* induction) {
SENode* offset = induction->GetOffset();
SENode* lower_bound = GetLowerBound(loop);
@ -409,7 +410,7 @@ SENode* LoopDependenceAnalysis::GetConstantTerm(const ir::Loop* loop,
}
bool LoopDependenceAnalysis::CheckSupportedLoops(
std::vector<const ir::Loop*> loops) {
std::vector<const opt::Loop*> loops) {
for (auto loop : loops) {
if (!IsSupportedLoop(loop)) {
return false;
@ -419,15 +420,15 @@ bool LoopDependenceAnalysis::CheckSupportedLoops(
}
void LoopDependenceAnalysis::MarkUnsusedDistanceEntriesAsIrrelevant(
const ir::Instruction* source, const ir::Instruction* destination,
const opt::Instruction* source, const opt::Instruction* destination,
DistanceVector* distance_vector) {
std::vector<ir::Instruction*> source_subscripts = GetSubscripts(source);
std::vector<ir::Instruction*> destination_subscripts =
std::vector<opt::Instruction*> source_subscripts = GetSubscripts(source);
std::vector<opt::Instruction*> destination_subscripts =
GetSubscripts(destination);
std::set<const ir::Loop*> used_loops{};
std::set<const opt::Loop*> used_loops{};
for (ir::Instruction* source_inst : source_subscripts) {
for (opt::Instruction* source_inst : source_subscripts) {
SENode* source_node = scalar_evolution_.SimplifyExpression(
scalar_evolution_.AnalyzeInstruction(source_inst));
std::vector<SERecurrentNode*> recurrent_nodes =
@ -437,7 +438,7 @@ void LoopDependenceAnalysis::MarkUnsusedDistanceEntriesAsIrrelevant(
}
}
for (ir::Instruction* destination_inst : destination_subscripts) {
for (opt::Instruction* destination_inst : destination_subscripts) {
SENode* destination_node = scalar_evolution_.SimplifyExpression(
scalar_evolution_.AnalyzeInstruction(destination_inst));
std::vector<SERecurrentNode*> recurrent_nodes =
@ -455,13 +456,13 @@ void LoopDependenceAnalysis::MarkUnsusedDistanceEntriesAsIrrelevant(
}
}
bool LoopDependenceAnalysis::IsSupportedLoop(const ir::Loop* loop) {
std::vector<ir::Instruction*> inductions{};
bool LoopDependenceAnalysis::IsSupportedLoop(const opt::Loop* loop) {
std::vector<opt::Instruction*> inductions{};
loop->GetInductionVariables(inductions);
if (inductions.size() != 1) {
return false;
}
ir::Instruction* induction = inductions[0];
opt::Instruction* induction = inductions[0];
SENode* induction_node = scalar_evolution_.SimplifyExpression(
scalar_evolution_.AnalyzeInstruction(induction));
if (!induction_node->AsSERecurrentNode()) {

View File

@ -29,16 +29,16 @@
#include "opt/tree_iterator.h"
namespace spvtools {
namespace ir {
namespace opt {
// Takes in a phi instruction |induction| and the loop |header| and returns the
// step operation of the loop.
ir::Instruction* Loop::GetInductionStepOperation(
const ir::Instruction* induction) const {
opt::Instruction* Loop::GetInductionStepOperation(
const opt::Instruction* induction) const {
// Induction must be a phi instruction.
assert(induction->opcode() == SpvOpPhi);
ir::Instruction* step = nullptr;
opt::Instruction* step = nullptr;
opt::analysis::DefUseManager* def_use_manager = context_->get_def_use_mgr();
@ -46,7 +46,7 @@ ir::Instruction* Loop::GetInductionStepOperation(
for (uint32_t operand_id = 1; operand_id < induction->NumInOperands();
operand_id += 2) {
// Incoming edge.
ir::BasicBlock* incoming_block =
opt::BasicBlock* incoming_block =
context_->cfg()->block(induction->GetSingleWordInOperand(operand_id));
// Check if the block is dominated by header, and thus coming from within
@ -142,17 +142,17 @@ int64_t Loop::GetResidualConditionValue(SpvOp condition, int64_t initial_value,
return remainder;
}
ir::Instruction* Loop::GetConditionInst() const {
ir::BasicBlock* condition_block = FindConditionBlock();
opt::Instruction* Loop::GetConditionInst() const {
opt::BasicBlock* condition_block = FindConditionBlock();
if (!condition_block) {
return nullptr;
}
ir::Instruction* branch_conditional = &*condition_block->tail();
opt::Instruction* branch_conditional = &*condition_block->tail();
if (!branch_conditional ||
branch_conditional->opcode() != SpvOpBranchConditional) {
return nullptr;
}
ir::Instruction* condition_inst = context_->get_def_use_mgr()->GetDef(
opt::Instruction* condition_inst = context_->get_def_use_mgr()->GetDef(
branch_conditional->GetSingleWordInOperand(0));
if (IsSupportedCondition(condition_inst->opcode())) {
return condition_inst;
@ -164,14 +164,14 @@ ir::Instruction* Loop::GetConditionInst() const {
// Extract the initial value from the |induction| OpPhi instruction and store it
// in |value|. If the function couldn't find the initial value of |induction|
// return false.
bool Loop::GetInductionInitValue(const ir::Instruction* induction,
bool Loop::GetInductionInitValue(const opt::Instruction* induction,
int64_t* value) const {
ir::Instruction* constant_instruction = nullptr;
opt::Instruction* constant_instruction = nullptr;
opt::analysis::DefUseManager* def_use_manager = context_->get_def_use_mgr();
for (uint32_t operand_id = 0; operand_id < induction->NumInOperands();
operand_id += 2) {
ir::BasicBlock* bb = context_->cfg()->block(
opt::BasicBlock* bb = context_->cfg()->block(
induction->GetSingleWordInOperand(operand_id + 1));
if (!IsInsideLoop(bb)) {
@ -327,8 +327,8 @@ void Loop::SetPreHeaderBlock(BasicBlock* preheader) {
loop_preheader_ = preheader;
}
ir::BasicBlock* Loop::FindLatchBlock() {
ir::CFG* cfg = context_->cfg();
opt::BasicBlock* Loop::FindLatchBlock() {
opt::CFG* cfg = context_->cfg();
opt::DominatorAnalysis* dominator_analysis =
context_->GetDominatorAnalysis(loop_header_->GetParent());
@ -350,7 +350,7 @@ ir::BasicBlock* Loop::FindLatchBlock() {
}
void Loop::GetExitBlocks(std::unordered_set<uint32_t>* exit_blocks) const {
ir::CFG* cfg = context_->cfg();
opt::CFG* cfg = context_->cfg();
exit_blocks->clear();
for (uint32_t bb_id : GetBlocks()) {
@ -366,13 +366,13 @@ void Loop::GetExitBlocks(std::unordered_set<uint32_t>* exit_blocks) const {
void Loop::GetMergingBlocks(
std::unordered_set<uint32_t>* merging_blocks) const {
assert(GetMergeBlock() && "This loop is not structured");
ir::CFG* cfg = context_->cfg();
opt::CFG* cfg = context_->cfg();
merging_blocks->clear();
std::stack<const ir::BasicBlock*> to_visit;
std::stack<const opt::BasicBlock*> to_visit;
to_visit.push(GetMergeBlock());
while (!to_visit.empty()) {
const ir::BasicBlock* bb = to_visit.top();
const opt::BasicBlock* bb = to_visit.top();
to_visit.pop();
merging_blocks->insert(bb->id());
for (uint32_t pred_id : cfg->preds(bb->id())) {
@ -386,7 +386,7 @@ void Loop::GetMergingBlocks(
namespace {
static inline bool IsBasicBlockSafeToClone(IRContext* context, BasicBlock* bb) {
for (ir::Instruction& inst : *bb) {
for (opt::Instruction& inst : *bb) {
if (!inst.IsBranch() && !context->IsCombinatorInstruction(&inst))
return false;
}
@ -397,7 +397,7 @@ static inline bool IsBasicBlockSafeToClone(IRContext* context, BasicBlock* bb) {
} // namespace
bool Loop::IsSafeToClone() const {
ir::CFG& cfg = *context_->cfg();
opt::CFG& cfg = *context_->cfg();
for (uint32_t bb_id : GetBlocks()) {
BasicBlock* bb = cfg.block(bb_id);
@ -421,14 +421,14 @@ bool Loop::IsSafeToClone() const {
}
bool Loop::IsLCSSA() const {
ir::CFG* cfg = context_->cfg();
opt::CFG* cfg = context_->cfg();
opt::analysis::DefUseManager* def_use_mgr = context_->get_def_use_mgr();
std::unordered_set<uint32_t> exit_blocks;
GetExitBlocks(&exit_blocks);
// Declare ir_context so we can capture context_ in the below lambda
ir::IRContext* ir_context = context_;
opt::IRContext* ir_context = context_;
for (uint32_t bb_id : GetBlocks()) {
for (Instruction& insn : *cfg->block(bb_id)) {
@ -437,7 +437,7 @@ bool Loop::IsLCSSA() const {
// - In an exit block and in a phi instruction.
if (!def_use_mgr->WhileEachUser(
&insn,
[&exit_blocks, ir_context, this](ir::Instruction* use) -> bool {
[&exit_blocks, ir_context, this](opt::Instruction* use) -> bool {
BasicBlock* parent = ir_context->get_instr_block(use);
assert(parent && "Invalid analysis");
if (IsInsideLoop(parent)) return true;
@ -472,9 +472,9 @@ bool Loop::AreAllOperandsOutsideLoop(IRContext* context, Instruction* inst) {
}
void Loop::ComputeLoopStructuredOrder(
std::vector<ir::BasicBlock*>* ordered_loop_blocks, bool include_pre_header,
std::vector<opt::BasicBlock*>* ordered_loop_blocks, bool include_pre_header,
bool include_merge) const {
ir::CFG& cfg = *context_->cfg();
opt::CFG& cfg = *context_->cfg();
// Reserve the memory: all blocks in the loop + extra if needed.
ordered_loop_blocks->reserve(GetBlocks().size() + include_pre_header +
@ -508,7 +508,7 @@ void LoopDescriptor::PopulateList(const Function* f) {
// instructions.
opt::DominatorTree& dom_tree = dom_analysis->GetDomTree();
for (opt::DominatorTreeNode& node :
ir::make_range(dom_tree.post_begin(), dom_tree.post_end())) {
opt::make_range(dom_tree.post_begin(), dom_tree.post_end())) {
Instruction* merge_inst = node.bb_->GetLoopMergeInst();
if (merge_inst) {
bool all_backedge_unreachable = true;
@ -578,14 +578,14 @@ void LoopDescriptor::PopulateList(const Function* f) {
}
}
std::vector<ir::Loop*> LoopDescriptor::GetLoopsInBinaryLayoutOrder() {
std::vector<opt::Loop*> LoopDescriptor::GetLoopsInBinaryLayoutOrder() {
std::vector<uint32_t> ids{};
for (size_t i = 0; i < NumLoops(); ++i) {
ids.push_back(GetLoopByIndex(i).GetHeaderBlock()->id());
}
std::vector<ir::Loop*> loops{};
std::vector<opt::Loop*> loops{};
if (!ids.empty()) {
auto function = GetLoopByIndex(0).GetHeaderBlock()->GetParent();
for (const auto& block : *function) {
@ -601,11 +601,11 @@ std::vector<ir::Loop*> LoopDescriptor::GetLoopsInBinaryLayoutOrder() {
return loops;
}
ir::BasicBlock* Loop::FindConditionBlock() const {
opt::BasicBlock* Loop::FindConditionBlock() const {
if (!loop_merge_) {
return nullptr;
}
ir::BasicBlock* condition_block = nullptr;
opt::BasicBlock* condition_block = nullptr;
uint32_t in_loop_pred = 0;
for (uint32_t p : context_->cfg()->preds(loop_merge_->id())) {
@ -622,11 +622,11 @@ ir::BasicBlock* Loop::FindConditionBlock() const {
return nullptr;
}
ir::BasicBlock* bb = context_->cfg()->block(in_loop_pred);
opt::BasicBlock* bb = context_->cfg()->block(in_loop_pred);
if (!bb) return nullptr;
const ir::Instruction& branch = *bb->ctail();
const opt::Instruction& branch = *bb->ctail();
// Make sure the branch is a conditional branch.
if (branch.opcode() != SpvOpBranchConditional) return nullptr;
@ -640,8 +640,8 @@ ir::BasicBlock* Loop::FindConditionBlock() const {
return condition_block;
}
bool Loop::FindNumberOfIterations(const ir::Instruction* induction,
const ir::Instruction* branch_inst,
bool Loop::FindNumberOfIterations(const opt::Instruction* induction,
const opt::Instruction* branch_inst,
size_t* iterations_out,
int64_t* step_value_out,
int64_t* init_value_out) const {
@ -649,7 +649,7 @@ bool Loop::FindNumberOfIterations(const ir::Instruction* induction,
opt::analysis::DefUseManager* def_use_manager = context_->get_def_use_mgr();
// Condition instruction from the OpConditionalBranch.
ir::Instruction* condition =
opt::Instruction* condition =
def_use_manager->GetDef(branch_inst->GetSingleWordOperand(0));
assert(IsSupportedCondition(condition->opcode()));
@ -680,7 +680,7 @@ bool Loop::FindNumberOfIterations(const ir::Instruction* induction,
}
// Find the instruction which is stepping through the loop.
ir::Instruction* step_inst = GetInductionStepOperation(induction);
opt::Instruction* step_inst = GetInductionStepOperation(induction);
if (!step_inst) return false;
// Find the constant value used by the condition variable.
@ -833,20 +833,20 @@ int64_t Loop::GetIterations(SpvOp condition, int64_t condition_value,
// Returns the list of induction variables within the loop.
void Loop::GetInductionVariables(
std::vector<ir::Instruction*>& induction_variables) const {
for (ir::Instruction& inst : *loop_header_) {
std::vector<opt::Instruction*>& induction_variables) const {
for (opt::Instruction& inst : *loop_header_) {
if (inst.opcode() == SpvOp::SpvOpPhi) {
induction_variables.push_back(&inst);
}
}
}
ir::Instruction* Loop::FindConditionVariable(
const ir::BasicBlock* condition_block) const {
opt::Instruction* Loop::FindConditionVariable(
const opt::BasicBlock* condition_block) const {
// Find the branch instruction.
const ir::Instruction& branch_inst = *condition_block->ctail();
const opt::Instruction& branch_inst = *condition_block->ctail();
ir::Instruction* induction = nullptr;
opt::Instruction* induction = nullptr;
// Verify that the branch instruction is a conditional branch.
if (branch_inst.opcode() == SpvOp::SpvOpBranchConditional) {
// From the branch instruction find the branch condition.
@ -854,13 +854,13 @@ ir::Instruction* Loop::FindConditionVariable(
// Find the instruction representing the condition used in the conditional
// branch.
ir::Instruction* condition =
opt::Instruction* condition =
def_use_manager->GetDef(branch_inst.GetSingleWordOperand(0));
// Ensure that the condition is a less than operation.
if (condition && IsSupportedCondition(condition->opcode())) {
// The left hand side operand of the operation.
ir::Instruction* variable_inst =
opt::Instruction* variable_inst =
def_use_manager->GetDef(condition->GetSingleWordOperand(2));
// Make sure the variable instruction used is a phi.
@ -924,7 +924,7 @@ bool LoopDescriptor::CreatePreHeaderBlocksIfMissing() {
// maintain the state of the loop descriptor class.
void LoopDescriptor::PostModificationCleanup() {
LoopContainerType loops_to_remove_;
for (ir::Loop* loop : loops_) {
for (opt::Loop* loop : loops_) {
if (loop->IsMarkedForRemoval()) {
loops_to_remove_.push_back(loop);
if (loop->HasParent()) {
@ -933,13 +933,13 @@ void LoopDescriptor::PostModificationCleanup() {
}
}
for (ir::Loop* loop : loops_to_remove_) {
for (opt::Loop* loop : loops_to_remove_) {
loops_.erase(std::find(loops_.begin(), loops_.end(), loop));
}
for (auto& pair : loops_to_add_) {
ir::Loop* parent = pair.first;
ir::Loop* loop = pair.second;
opt::Loop* parent = pair.first;
opt::Loop* loop = pair.second;
if (parent) {
loop->SetParent(nullptr);
@ -964,12 +964,12 @@ void LoopDescriptor::ClearLoops() {
}
// Adds a new loop nest to the descriptor set.
ir::Loop* LoopDescriptor::AddLoopNest(std::unique_ptr<ir::Loop> new_loop) {
ir::Loop* loop = new_loop.release();
opt::Loop* LoopDescriptor::AddLoopNest(std::unique_ptr<opt::Loop> new_loop) {
opt::Loop* loop = new_loop.release();
if (!loop->HasParent()) dummy_top_loop_.nested_loops_.push_back(loop);
// Iterate from inner to outer most loop, adding basic block to loop mapping
// as we go.
for (ir::Loop& current_loop :
for (opt::Loop& current_loop :
make_range(iterator::begin(loop), iterator::end(nullptr))) {
loops_.push_back(&current_loop);
for (uint32_t bb_id : current_loop.GetBlocks())
@ -979,18 +979,18 @@ ir::Loop* LoopDescriptor::AddLoopNest(std::unique_ptr<ir::Loop> new_loop) {
return loop;
}
void LoopDescriptor::RemoveLoop(ir::Loop* loop) {
ir::Loop* parent = loop->GetParent() ? loop->GetParent() : &dummy_top_loop_;
void LoopDescriptor::RemoveLoop(opt::Loop* loop) {
opt::Loop* parent = loop->GetParent() ? loop->GetParent() : &dummy_top_loop_;
parent->nested_loops_.erase(std::find(parent->nested_loops_.begin(),
parent->nested_loops_.end(), loop));
std::for_each(
loop->nested_loops_.begin(), loop->nested_loops_.end(),
[loop](ir::Loop* sub_loop) { sub_loop->SetParent(loop->GetParent()); });
[loop](opt::Loop* sub_loop) { sub_loop->SetParent(loop->GetParent()); });
parent->nested_loops_.insert(parent->nested_loops_.end(),
loop->nested_loops_.begin(),
loop->nested_loops_.end());
for (uint32_t bb_id : loop->GetBlocks()) {
ir::Loop* l = FindLoopForBasicBlock(bb_id);
opt::Loop* l = FindLoopForBasicBlock(bb_id);
if (l == loop) {
SetBasicBlockToLoop(bb_id, l->GetParent());
} else {
@ -1005,5 +1005,5 @@ void LoopDescriptor::RemoveLoop(ir::Loop* loop) {
loops_.erase(it);
}
} // namespace ir
} // namespace opt
} // namespace spvtools

View File

@ -24,15 +24,13 @@
#include <vector>
#include "opt/basic_block.h"
#include "opt/dominator_analysis.h"
#include "opt/module.h"
#include "opt/tree_iterator.h"
namespace spvtools {
namespace opt {
class DominatorAnalysis;
struct DominatorTreeNode;
} // namespace opt
namespace ir {
class IRContext;
class CFG;
class LoopDescriptor;
@ -79,7 +77,7 @@ class Loop {
inline void UpdateLoopMergeInst() {
assert(GetHeaderBlock()->GetLoopMergeInst() &&
"The loop is not structured");
ir::Instruction* merge_inst = GetHeaderBlock()->GetLoopMergeInst();
opt::Instruction* merge_inst = GetHeaderBlock()->GetLoopMergeInst();
merge_inst->SetInOperand(0, {GetMergeBlock()->id()});
}
@ -234,20 +232,21 @@ class Loop {
}
// Returns the list of induction variables within the loop.
void GetInductionVariables(std::vector<ir::Instruction*>& inductions) const;
void GetInductionVariables(std::vector<opt::Instruction*>& inductions) const;
// This function uses the |condition| to find the induction variable which is
// used by the loop condition within the loop. This only works if the loop is
// bound by a single condition and single induction variable.
ir::Instruction* FindConditionVariable(const ir::BasicBlock* condition) const;
opt::Instruction* FindConditionVariable(
const opt::BasicBlock* condition) const;
// Returns the number of iterations within a loop when given the |induction|
// variable and the loop |condition| check. It stores the found number of
// iterations in the output parameter |iterations| and optionally, the step
// value in |step_value| and the initial value of the induction variable in
// |init_value|.
bool FindNumberOfIterations(const ir::Instruction* induction,
const ir::Instruction* condition,
bool FindNumberOfIterations(const opt::Instruction* induction,
const opt::Instruction* condition,
size_t* iterations,
int64_t* step_amount = nullptr,
int64_t* init_value = nullptr) const;
@ -264,7 +263,7 @@ class Loop {
// Finds the conditional block with a branch to the merge and continue blocks
// within the loop body.
ir::BasicBlock* FindConditionBlock() const;
opt::BasicBlock* FindConditionBlock() const;
// Remove the child loop form this loop.
inline void RemoveChildLoop(Loop* loop) {
@ -308,13 +307,13 @@ class Loop {
// Extract the initial value from the |induction| variable and store it in
// |value|. If the function couldn't find the initial value of |induction|
// return false.
bool GetInductionInitValue(const ir::Instruction* induction,
bool GetInductionInitValue(const opt::Instruction* induction,
int64_t* value) const;
// Takes in a phi instruction |induction| and the loop |header| and returns
// the step operation of the loop.
ir::Instruction* GetInductionStepOperation(
const ir::Instruction* induction) const;
opt::Instruction* GetInductionStepOperation(
const opt::Instruction* induction) const;
// Returns true if we can deduce the number of loop iterations in the step
// operation |step|. IsSupportedCondition must also be true for the condition
@ -332,7 +331,7 @@ class Loop {
// exist. If |include_merge| is true, the merge block will also be included at
// the end of the list if it exist.
void ComputeLoopStructuredOrder(
std::vector<ir::BasicBlock*>* ordered_loop_blocks,
std::vector<opt::BasicBlock*>* ordered_loop_blocks,
bool include_pre_header = false, bool include_merge = false) const;
// Given the loop |condition|, |initial_value|, |step_value|, the trip count
@ -346,7 +345,7 @@ class Loop {
// Returns the condition instruction for entry into the loop
// Returns nullptr if it can't be found.
ir::Instruction* GetConditionInst() const;
opt::Instruction* GetConditionInst() const;
// Returns the context associated this loop.
IRContext* GetContext() const { return context_; }
@ -355,7 +354,7 @@ class Loop {
// which is also dominated by the loop continue block. This block is the latch
// block. The specification mandates that this block should exist, therefore
// this function will assert if it is not found.
ir::BasicBlock* FindLatchBlock();
opt::BasicBlock* FindLatchBlock();
private:
IRContext* context_;
@ -459,7 +458,7 @@ class LoopDescriptor {
// Returns the loops in |this| in the order their headers appear in the
// binary.
std::vector<ir::Loop*> GetLoopsInBinaryLayoutOrder();
std::vector<opt::Loop*> GetLoopsInBinaryLayoutOrder();
// Returns the inner most loop that contains the basic block id |block_id|.
inline Loop* operator[](uint32_t block_id) const {
@ -502,7 +501,7 @@ class LoopDescriptor {
// Mark the loop |loop_to_add| as needing to be added when the user calls
// PostModificationCleanup. |parent| may be null.
inline void AddLoop(ir::Loop* loop_to_add, ir::Loop* parent) {
inline void AddLoop(opt::Loop* loop_to_add, opt::Loop* parent) {
loops_to_add_.emplace_back(std::make_pair(parent, loop_to_add));
}
@ -521,12 +520,12 @@ class LoopDescriptor {
// Adds the loop |new_loop| and all its nested loops to the descriptor set.
// The object takes ownership of all the loops.
ir::Loop* AddLoopNest(std::unique_ptr<ir::Loop> new_loop);
opt::Loop* AddLoopNest(std::unique_ptr<opt::Loop> new_loop);
// Remove the loop |loop|.
void RemoveLoop(ir::Loop* loop);
void RemoveLoop(opt::Loop* loop);
void SetAsTopLoop(ir::Loop* loop) {
void SetAsTopLoop(opt::Loop* loop) {
assert(std::find(dummy_top_loop_.begin(), dummy_top_loop_.end(), loop) ==
dummy_top_loop_.end() &&
"already registered");
@ -569,7 +568,7 @@ class LoopDescriptor {
LoopsToAddContainerType loops_to_add_;
};
} // namespace ir
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_LOOP_DESCRIPTORS_H_

View File

@ -55,7 +55,7 @@ namespace opt {
class LoopFissionImpl {
public:
LoopFissionImpl(ir::IRContext* context, ir::Loop* loop)
LoopFissionImpl(opt::IRContext* context, opt::Loop* loop)
: context_(context), loop_(loop), load_used_in_condition_(false) {}
// Group each instruction in the loop into sets of instructions related by
@ -69,37 +69,37 @@ class LoopFissionImpl {
bool CanPerformSplit();
// Split the loop and return a pointer to the new loop.
ir::Loop* SplitLoop();
opt::Loop* SplitLoop();
// Checks if |inst| is safe to move. We can only move instructions which don't
// have any side effects and OpLoads and OpStores.
bool MovableInstruction(const ir::Instruction& inst) const;
bool MovableInstruction(const opt::Instruction& inst) const;
private:
// Traverse the def use chain of |inst| and add the users and uses of |inst|
// which are in the same loop to the |returned_set|.
void TraverseUseDef(ir::Instruction* inst,
std::set<ir::Instruction*>* returned_set,
void TraverseUseDef(opt::Instruction* inst,
std::set<opt::Instruction*>* returned_set,
bool ignore_phi_users = false, bool report_loads = false);
// We group the instructions in the block into two different groups, the
// instructions to be kept in the original loop and the ones to be cloned into
// the new loop. As the cloned loop is attached to the preheader it will be
// the first loop and the second loop will be the original.
std::set<ir::Instruction*> cloned_loop_instructions_;
std::set<ir::Instruction*> original_loop_instructions_;
std::set<opt::Instruction*> cloned_loop_instructions_;
std::set<opt::Instruction*> original_loop_instructions_;
// We need a set of all the instructions to be seen so we can break any
// recursion and also so we can ignore certain instructions by preemptively
// adding them to this set.
std::set<ir::Instruction*> seen_instructions_;
std::set<opt::Instruction*> seen_instructions_;
// A map of instructions to their relative position in the function.
std::map<ir::Instruction*, size_t> instruction_order_;
std::map<opt::Instruction*, size_t> instruction_order_;
ir::IRContext* context_;
opt::IRContext* context_;
ir::Loop* loop_;
opt::Loop* loop_;
// This is set to true by TraverseUseDef when traversing the instructions
// related to the loop condition and any if conditions should any of those
@ -107,27 +107,27 @@ class LoopFissionImpl {
bool load_used_in_condition_;
};
bool LoopFissionImpl::MovableInstruction(const ir::Instruction& inst) const {
bool LoopFissionImpl::MovableInstruction(const opt::Instruction& inst) const {
return inst.opcode() == SpvOp::SpvOpLoad ||
inst.opcode() == SpvOp::SpvOpStore ||
inst.opcode() == SpvOp::SpvOpSelectionMerge ||
inst.opcode() == SpvOp::SpvOpPhi || inst.IsOpcodeCodeMotionSafe();
}
void LoopFissionImpl::TraverseUseDef(ir::Instruction* inst,
std::set<ir::Instruction*>* returned_set,
void LoopFissionImpl::TraverseUseDef(opt::Instruction* inst,
std::set<opt::Instruction*>* returned_set,
bool ignore_phi_users, bool report_loads) {
assert(returned_set && "Set to be returned cannot be null.");
opt::analysis::DefUseManager* def_use = context_->get_def_use_mgr();
std::set<ir::Instruction*>& inst_set = *returned_set;
std::set<opt::Instruction*>& inst_set = *returned_set;
// We create this functor to traverse the use def chain to build the
// grouping of related instructions. The lambda captures the std::function
// to allow it to recurse.
std::function<void(ir::Instruction*)> traverser_functor;
std::function<void(opt::Instruction*)> traverser_functor;
traverser_functor = [this, def_use, &inst_set, &traverser_functor,
ignore_phi_users, report_loads](ir::Instruction* user) {
ignore_phi_users, report_loads](opt::Instruction* user) {
// If we've seen the instruction before or it is not inside the loop end the
// traversal.
if (!user || seen_instructions_.count(user) != 0 ||
@ -171,7 +171,7 @@ void LoopFissionImpl::TraverseUseDef(ir::Instruction* inst,
def_use->ForEachUser(user, traverser_functor);
// Wrapper functor for the use traversal.
auto traverse_use = [&traverser_functor](ir::Instruction* use, uint32_t) {
auto traverse_use = [&traverser_functor](opt::Instruction* use, uint32_t) {
traverser_functor(use);
};
def_use->ForEachUse(user, traverse_use);
@ -184,33 +184,33 @@ void LoopFissionImpl::TraverseUseDef(ir::Instruction* inst,
}
bool LoopFissionImpl::GroupInstructionsByUseDef() {
std::vector<std::set<ir::Instruction*>> sets{};
std::vector<std::set<opt::Instruction*>> sets{};
// We want to ignore all the instructions stemming from the loop condition
// instruction.
ir::BasicBlock* condition_block = loop_->FindConditionBlock();
opt::BasicBlock* condition_block = loop_->FindConditionBlock();
if (!condition_block) return false;
ir::Instruction* condition = &*condition_block->tail();
opt::Instruction* condition = &*condition_block->tail();
// We iterate over the blocks via iterating over all the blocks in the
// function, we do this so we are iterating in the same order which the blocks
// appear in the binary.
ir::Function& function = *loop_->GetHeaderBlock()->GetParent();
opt::Function& function = *loop_->GetHeaderBlock()->GetParent();
// Create a temporary set to ignore certain groups of instructions within the
// loop. We don't want any instructions related to control flow to be removed
// from either loop only instructions within the control flow bodies.
std::set<ir::Instruction*> instructions_to_ignore{};
std::set<opt::Instruction*> instructions_to_ignore{};
TraverseUseDef(condition, &instructions_to_ignore, true, true);
// Traverse control flow instructions to ensure they are added to the
// seen_instructions_ set and will be ignored when it it called with actual
// sets.
for (ir::BasicBlock& block : function) {
for (opt::BasicBlock& block : function) {
if (!loop_->IsInsideLoop(block.id())) continue;
for (ir::Instruction& inst : block) {
for (opt::Instruction& inst : block) {
// Ignore all instructions related to control flow.
if (inst.opcode() == SpvOp::SpvOpSelectionMerge || inst.IsBranch()) {
TraverseUseDef(&inst, &instructions_to_ignore, true, true);
@ -220,12 +220,12 @@ bool LoopFissionImpl::GroupInstructionsByUseDef() {
// Traverse the instructions and generate the sets, automatically ignoring any
// instructions in instructions_to_ignore.
for (ir::BasicBlock& block : function) {
for (opt::BasicBlock& block : function) {
if (!loop_->IsInsideLoop(block.id()) ||
loop_->GetHeaderBlock()->id() == block.id())
continue;
for (ir::Instruction& inst : block) {
for (opt::Instruction& inst : block) {
// Record the order that each load/store is seen.
if (inst.opcode() == SpvOp::SpvOpLoad ||
inst.opcode() == SpvOp::SpvOpStore) {
@ -238,7 +238,7 @@ bool LoopFissionImpl::GroupInstructionsByUseDef() {
}
// Build the set.
std::set<ir::Instruction*> inst_set{};
std::set<opt::Instruction*> inst_set{};
TraverseUseDef(&inst, &inst_set);
if (!inst_set.empty()) sets.push_back(std::move(inst_set));
}
@ -273,8 +273,8 @@ bool LoopFissionImpl::CanPerformSplit() {
// Build a list of all parent loops of this loop. Loop dependence analysis
// needs this structure.
std::vector<const ir::Loop*> loops;
ir::Loop* parent_loop = loop_;
std::vector<const opt::Loop*> loops;
opt::Loop* parent_loop = loop_;
while (parent_loop) {
loops.push_back(parent_loop);
parent_loop = parent_loop->GetParent();
@ -283,13 +283,13 @@ bool LoopFissionImpl::CanPerformSplit() {
LoopDependenceAnalysis analysis{context_, loops};
// A list of all the stores in the cloned loop.
std::vector<ir::Instruction*> set_one_stores{};
std::vector<opt::Instruction*> set_one_stores{};
// A list of all the loads in the cloned loop.
std::vector<ir::Instruction*> set_one_loads{};
std::vector<opt::Instruction*> set_one_loads{};
// Populate the above lists.
for (ir::Instruction* inst : cloned_loop_instructions_) {
for (opt::Instruction* inst : cloned_loop_instructions_) {
if (inst->opcode() == SpvOp::SpvOpStore) {
set_one_stores.push_back(inst);
} else if (inst->opcode() == SpvOp::SpvOpLoad) {
@ -307,7 +307,7 @@ bool LoopFissionImpl::CanPerformSplit() {
// Check the dependencies between loads in the cloned loop and stores in the
// original and vice versa.
for (ir::Instruction* inst : original_loop_instructions_) {
for (opt::Instruction* inst : original_loop_instructions_) {
// If we find any instruction which we can't move (such as a barrier),
// return false.
if (!MovableInstruction(*inst)) return false;
@ -315,7 +315,7 @@ bool LoopFissionImpl::CanPerformSplit() {
// Look at the dependency between the loads in the original and stores in
// the cloned loops.
if (inst->opcode() == SpvOp::SpvOpLoad) {
for (ir::Instruction* store : set_one_stores) {
for (opt::Instruction* store : set_one_stores) {
DistanceVector vec{loop_depth};
// If the store actually should appear after the load, return false.
@ -333,7 +333,7 @@ bool LoopFissionImpl::CanPerformSplit() {
}
}
} else if (inst->opcode() == SpvOp::SpvOpStore) {
for (ir::Instruction* load : set_one_loads) {
for (opt::Instruction* load : set_one_loads) {
DistanceVector vec{loop_depth};
// If the load actually should appear after the store, return false.
@ -355,30 +355,30 @@ bool LoopFissionImpl::CanPerformSplit() {
return true;
}
ir::Loop* LoopFissionImpl::SplitLoop() {
opt::Loop* LoopFissionImpl::SplitLoop() {
// Clone the loop.
LoopUtils util{context_, loop_};
LoopUtils::LoopCloningResult clone_results;
ir::Loop* cloned_loop = util.CloneAndAttachLoopToHeader(&clone_results);
opt::Loop* cloned_loop = util.CloneAndAttachLoopToHeader(&clone_results);
// Update the OpLoopMerge in the cloned loop.
cloned_loop->UpdateLoopMergeInst();
// Add the loop_ to the module.
ir::Function::iterator it =
opt::Function::iterator it =
util.GetFunction()->FindBlock(loop_->GetOrCreatePreHeaderBlock()->id());
util.GetFunction()->AddBasicBlocks(clone_results.cloned_bb_.begin(),
clone_results.cloned_bb_.end(), ++it);
loop_->SetPreHeaderBlock(cloned_loop->GetMergeBlock());
std::vector<ir::Instruction*> instructions_to_kill{};
std::vector<opt::Instruction*> instructions_to_kill{};
// Kill all the instructions which should appear in the cloned loop but not in
// the original loop.
for (uint32_t id : loop_->GetBlocks()) {
ir::BasicBlock* block = context_->cfg()->block(id);
opt::BasicBlock* block = context_->cfg()->block(id);
for (ir::Instruction& inst : *block) {
for (opt::Instruction& inst : *block) {
// If the instruction appears in the cloned loop instruction group, kill
// it.
if (cloned_loop_instructions_.count(&inst) == 1 &&
@ -395,9 +395,9 @@ ir::Loop* LoopFissionImpl::SplitLoop() {
// Kill all instructions which should appear in the original loop and not in
// the cloned loop.
for (uint32_t id : cloned_loop->GetBlocks()) {
ir::BasicBlock* block = context_->cfg()->block(id);
for (ir::Instruction& inst : *block) {
ir::Instruction* old_inst = clone_results.ptr_map_[&inst];
opt::BasicBlock* block = context_->cfg()->block(id);
for (opt::Instruction& inst : *block) {
opt::Instruction* old_inst = clone_results.ptr_map_[&inst];
// If the instruction belongs to the original loop instruction group, kill
// it.
if (cloned_loop_instructions_.count(old_inst) == 0 &&
@ -407,7 +407,7 @@ ir::Loop* LoopFissionImpl::SplitLoop() {
}
}
for (ir::Instruction* i : instructions_to_kill) {
for (opt::Instruction* i : instructions_to_kill) {
context_->KillInst(i);
}
@ -433,37 +433,38 @@ LoopFissionPass::LoopFissionPass() : split_multiple_times_(false) {
};
}
bool LoopFissionPass::ShouldSplitLoop(const ir::Loop& loop, ir::IRContext* c) {
bool LoopFissionPass::ShouldSplitLoop(const opt::Loop& loop,
opt::IRContext* c) {
LivenessAnalysis* analysis = c->GetLivenessAnalysis();
RegisterLiveness::RegionRegisterLiveness liveness{};
ir::Function* function = loop.GetHeaderBlock()->GetParent();
opt::Function* function = loop.GetHeaderBlock()->GetParent();
analysis->Get(function)->ComputeLoopRegisterPressure(loop, &liveness);
return split_criteria_(liveness);
}
Pass::Status LoopFissionPass::Process(ir::IRContext* c) {
Pass::Status LoopFissionPass::Process(opt::IRContext* c) {
bool changed = false;
for (ir::Function& f : *c->module()) {
for (opt::Function& f : *c->module()) {
// We collect all the inner most loops in the function and run the loop
// splitting util on each. The reason we do this is to allow us to iterate
// over each, as creating new loops will invalidate the the loop iterator.
std::vector<ir::Loop*> inner_most_loops{};
ir::LoopDescriptor& loop_descriptor = *c->GetLoopDescriptor(&f);
for (ir::Loop& loop : loop_descriptor) {
std::vector<opt::Loop*> inner_most_loops{};
opt::LoopDescriptor& loop_descriptor = *c->GetLoopDescriptor(&f);
for (opt::Loop& loop : loop_descriptor) {
if (!loop.HasChildren() && ShouldSplitLoop(loop, c)) {
inner_most_loops.push_back(&loop);
}
}
// List of new loops which meet the criteria to be split again.
std::vector<ir::Loop*> new_loops_to_split{};
std::vector<opt::Loop*> new_loops_to_split{};
while (!inner_most_loops.empty()) {
for (ir::Loop* loop : inner_most_loops) {
for (opt::Loop* loop : inner_most_loops) {
LoopFissionImpl impl{c, loop};
// Group the instructions in the loop into two different sets of related
@ -474,9 +475,9 @@ Pass::Status LoopFissionPass::Process(ir::IRContext* c) {
}
if (impl.CanPerformSplit()) {
ir::Loop* second_loop = impl.SplitLoop();
opt::Loop* second_loop = impl.SplitLoop();
changed = true;
c->InvalidateAnalysesExceptFor(ir::IRContext::kAnalysisLoopAnalysis);
c->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisLoopAnalysis);
// If the newly created loop meets the criteria to be split, split it
// again.

View File

@ -57,10 +57,10 @@ class LoopFissionPass : public Pass {
const char* name() const override { return "Loop Fission"; }
Pass::Status Process(ir::IRContext* context) override;
Pass::Status Process(opt::IRContext* context) override;
// Checks if |loop| meets the register pressure criteria to be split.
bool ShouldSplitLoop(const ir::Loop& loop, ir::IRContext* context);
bool ShouldSplitLoop(const opt::Loop& loop, opt::IRContext* context);
private:
// Functor to run in ShouldSplitLoop to determine if the register pressure

View File

@ -27,7 +27,7 @@ namespace opt {
namespace {
// Append all the loops nested in |loop| to |loops|.
void CollectChildren(ir::Loop* loop, std::vector<const ir::Loop*>* loops) {
void CollectChildren(opt::Loop* loop, std::vector<const opt::Loop*>* loops) {
for (auto child : *loop) {
loops->push_back(child);
if (child->NumImmediateChildren() != 0) {
@ -37,10 +37,10 @@ void CollectChildren(ir::Loop* loop, std::vector<const ir::Loop*>* loops) {
}
// Return the set of locations accessed by |stores| and |loads|.
std::set<ir::Instruction*> GetLocationsAccessed(
const std::map<ir::Instruction*, std::vector<ir::Instruction*>>& stores,
const std::map<ir::Instruction*, std::vector<ir::Instruction*>>& loads) {
std::set<ir::Instruction*> locations{};
std::set<opt::Instruction*> GetLocationsAccessed(
const std::map<opt::Instruction*, std::vector<opt::Instruction*>>& stores,
const std::map<opt::Instruction*, std::vector<opt::Instruction*>>& loads) {
std::set<opt::Instruction*> locations{};
for (const auto& kv : stores) {
locations.insert(std::get<0>(kv));
@ -56,8 +56,8 @@ std::set<ir::Instruction*> GetLocationsAccessed(
// Append all dependences from |sources| to |destinations| to |dependences|.
void GetDependences(std::vector<DistanceVector>* dependences,
LoopDependenceAnalysis* analysis,
const std::vector<ir::Instruction*>& sources,
const std::vector<ir::Instruction*>& destinations,
const std::vector<opt::Instruction*>& sources,
const std::vector<opt::Instruction*>& destinations,
size_t num_entries) {
for (auto source : sources) {
for (auto destination : destinations) {
@ -70,8 +70,8 @@ void GetDependences(std::vector<DistanceVector>* dependences,
}
// Apped all instructions in |block| to |instructions|.
void AddInstructionsInBlock(std::vector<ir::Instruction*>* instructions,
ir::BasicBlock* block) {
void AddInstructionsInBlock(std::vector<opt::Instruction*>* instructions,
opt::BasicBlock* block) {
for (auto& inst : *block) {
instructions->push_back(&inst);
}
@ -82,12 +82,12 @@ void AddInstructionsInBlock(std::vector<ir::Instruction*>* instructions,
} // namespace
bool LoopFusion::UsedInContinueOrConditionBlock(
ir::Instruction* phi_instruction, ir::Loop* loop) {
opt::Instruction* phi_instruction, opt::Loop* loop) {
auto condition_block = loop->FindConditionBlock()->id();
auto continue_block = loop->GetContinueBlock()->id();
auto not_used = context_->get_def_use_mgr()->WhileEachUser(
phi_instruction,
[this, condition_block, continue_block](ir::Instruction* instruction) {
[this, condition_block, continue_block](opt::Instruction* instruction) {
auto block_id = context_->get_instr_block(instruction)->id();
return block_id != condition_block && block_id != continue_block;
});
@ -96,10 +96,10 @@ bool LoopFusion::UsedInContinueOrConditionBlock(
}
void LoopFusion::RemoveIfNotUsedContinueOrConditionBlock(
std::vector<ir::Instruction*>* instructions, ir::Loop* loop) {
std::vector<opt::Instruction*>* instructions, opt::Loop* loop) {
instructions->erase(
std::remove_if(std::begin(*instructions), std::end(*instructions),
[this, loop](ir::Instruction* instruction) {
[this, loop](opt::Instruction* instruction) {
return !UsedInContinueOrConditionBlock(instruction,
loop);
}),
@ -132,7 +132,7 @@ bool LoopFusion::AreCompatible() {
// |GetInductionVariables| returns all OpPhi in the header. Check that both
// loops have exactly one that is used in the continue and condition blocks.
std::vector<ir::Instruction*> inductions_0{}, inductions_1{};
std::vector<opt::Instruction*> inductions_0{}, inductions_1{};
loop_0_->GetInductionVariables(inductions_0);
RemoveIfNotUsedContinueOrConditionBlock(&inductions_0, loop_0_);
@ -169,7 +169,7 @@ bool LoopFusion::AreCompatible() {
auto pre_header_1 = loop_1_->GetPreHeaderBlock();
std::vector<ir::BasicBlock*> block_to_check{};
std::vector<opt::BasicBlock*> block_to_check{};
block_to_check.push_back(pre_header_1);
if (loop_0_->GetMergeBlock() != loop_1_->GetPreHeaderBlock()) {
@ -208,7 +208,7 @@ bool LoopFusion::AreCompatible() {
auto is_used = false;
context_->get_def_use_mgr()->ForEachUse(
inst.GetSingleWordInOperand(0),
[&is_used](ir::Instruction* use_inst, uint32_t) {
[&is_used](opt::Instruction* use_inst, uint32_t) {
if (use_inst->opcode() == SpvOpLoad) {
is_used = true;
}
@ -230,7 +230,7 @@ bool LoopFusion::AreCompatible() {
return true;
} // namespace opt
bool LoopFusion::ContainsBarriersOrFunctionCalls(ir::Loop* loop) {
bool LoopFusion::ContainsBarriersOrFunctionCalls(opt::Loop* loop) {
for (const auto& block : loop->GetBlocks()) {
for (const auto& inst : *containing_function_->FindBlock(block)) {
auto opcode = inst.opcode();
@ -336,9 +336,9 @@ bool LoopFusion::CheckStep() {
return true;
}
std::map<ir::Instruction*, std::vector<ir::Instruction*>>
LoopFusion::LocationToMemOps(const std::vector<ir::Instruction*>& mem_ops) {
std::map<ir::Instruction*, std::vector<ir::Instruction*>> location_map{};
std::map<opt::Instruction*, std::vector<opt::Instruction*>>
LoopFusion::LocationToMemOps(const std::vector<opt::Instruction*>& mem_ops) {
std::map<opt::Instruction*, std::vector<opt::Instruction*>> location_map{};
for (auto instruction : mem_ops) {
auto access_location = context_->get_def_use_mgr()->GetDef(
@ -355,10 +355,10 @@ LoopFusion::LocationToMemOps(const std::vector<ir::Instruction*>& mem_ops) {
return location_map;
}
std::pair<std::vector<ir::Instruction*>, std::vector<ir::Instruction*>>
LoopFusion::GetLoadsAndStoresInLoop(ir::Loop* loop) {
std::vector<ir::Instruction*> loads{};
std::vector<ir::Instruction*> stores{};
std::pair<std::vector<opt::Instruction*>, std::vector<opt::Instruction*>>
LoopFusion::GetLoadsAndStoresInLoop(opt::Loop* loop) {
std::vector<opt::Instruction*> loads{};
std::vector<opt::Instruction*> stores{};
for (auto block_id : loop->GetBlocks()) {
if (block_id == loop->GetContinueBlock()->id()) {
@ -377,9 +377,9 @@ LoopFusion::GetLoadsAndStoresInLoop(ir::Loop* loop) {
return std::make_pair(loads, stores);
}
bool LoopFusion::IsUsedInLoop(ir::Instruction* instruction, ir::Loop* loop) {
bool LoopFusion::IsUsedInLoop(opt::Instruction* instruction, opt::Loop* loop) {
auto not_used = context_->get_def_use_mgr()->WhileEachUser(
instruction, [this, loop](ir::Instruction* user) {
instruction, [this, loop](opt::Instruction* user) {
auto block_id = context_->get_instr_block(user)->id();
return !loop->IsInsideLoop(block_id);
});
@ -397,7 +397,7 @@ bool LoopFusion::IsLegal() {
return false;
}
std::vector<ir::Instruction*> phi_instructions{};
std::vector<opt::Instruction*> phi_instructions{};
loop_0_->GetInductionVariables(phi_instructions);
// Check no OpPhi in |loop_0_| is used in |loop_1_|.
@ -410,7 +410,7 @@ bool LoopFusion::IsLegal() {
// Check no LCSSA OpPhi in merge block of |loop_0_| is used in |loop_1_|.
auto phi_used = false;
loop_0_->GetMergeBlock()->ForEachPhiInst(
[this, &phi_used](ir::Instruction* phi_instruction) {
[this, &phi_used](opt::Instruction* phi_instruction) {
phi_used |= IsUsedInLoop(phi_instruction, loop_1_);
});
@ -433,7 +433,7 @@ bool LoopFusion::IsLegal() {
auto locations_0 = GetLocationsAccessed(store_locs_0, load_locs_0);
auto locations_1 = GetLocationsAccessed(store_locs_1, load_locs_1);
std::vector<ir::Instruction*> potential_clashes{};
std::vector<opt::Instruction*> potential_clashes{};
std::set_intersection(std::begin(locations_0), std::end(locations_0),
std::begin(locations_1), std::end(locations_1),
@ -445,7 +445,7 @@ bool LoopFusion::IsLegal() {
}
// Find variables that have at least one store.
std::vector<ir::Instruction*> potential_clashes_with_stores{};
std::vector<opt::Instruction*> potential_clashes_with_stores{};
for (auto location : potential_clashes) {
if (store_locs_0.find(location) != std::end(store_locs_0) ||
store_locs_1.find(location) != std::end(store_locs_1)) {
@ -463,7 +463,7 @@ bool LoopFusion::IsLegal() {
// distance.
// Find all the loops in this loop nest for the dependency analysis.
std::vector<const ir::Loop*> loops{};
std::vector<const opt::Loop*> loops{};
// Find the parents.
for (auto current_loop = loop_0_; current_loop != nullptr;
@ -519,7 +519,7 @@ bool LoopFusion::IsLegal() {
return true;
}
void ReplacePhiParentWith(ir::Instruction* inst, uint32_t orig_block,
void ReplacePhiParentWith(opt::Instruction* inst, uint32_t orig_block,
uint32_t new_block) {
if (inst->GetSingleWordInOperand(1) == orig_block) {
inst->SetInOperand(1, {new_block});
@ -555,7 +555,7 @@ void LoopFusion::Fuse() {
// Update merge block id in the header of |loop_0_| to the merge block of
// |loop_1_|.
loop_0_->GetHeaderBlock()->ForEachInst([this](ir::Instruction* inst) {
loop_0_->GetHeaderBlock()->ForEachInst([this](opt::Instruction* inst) {
if (inst->opcode() == SpvOpLoopMerge) {
inst->SetInOperand(0, {loop_1_->GetMergeBlock()->id()});
}
@ -563,7 +563,7 @@ void LoopFusion::Fuse() {
// Update condition branch target in |loop_0_| to the merge block of
// |loop_1_|.
condition_block_of_0->ForEachInst([this](ir::Instruction* inst) {
condition_block_of_0->ForEachInst([this](opt::Instruction* inst) {
if (inst->opcode() == SpvOpBranchConditional) {
auto loop_0_merge_block_id = loop_0_->GetMergeBlock()->id();
@ -577,7 +577,7 @@ void LoopFusion::Fuse() {
// Move OpPhi instructions not corresponding to the induction variable from
// the header of |loop_1_| to the header of |loop_0_|.
std::vector<ir::Instruction*> instructions_to_move{};
std::vector<opt::Instruction*> instructions_to_move{};
for (auto& instruction : *loop_1_->GetHeaderBlock()) {
if (instruction.opcode() == SpvOpPhi && &instruction != induction_1_) {
instructions_to_move.push_back(&instruction);
@ -590,7 +590,7 @@ void LoopFusion::Fuse() {
}
// Update the OpPhi parents to the correct blocks in |loop_0_|.
loop_0_->GetHeaderBlock()->ForEachPhiInst([this](ir::Instruction* i) {
loop_0_->GetHeaderBlock()->ForEachPhiInst([this](opt::Instruction* i) {
ReplacePhiParentWith(i, loop_1_->GetPreHeaderBlock()->id(),
loop_0_->GetPreHeaderBlock()->id());
@ -611,14 +611,14 @@ void LoopFusion::Fuse() {
// Replace LCSSA OpPhi in merge block of |loop_0_|.
loop_0_->GetMergeBlock()->ForEachPhiInst(
[this](ir::Instruction* instruction) {
[this](opt::Instruction* instruction) {
context_->ReplaceAllUsesWith(instruction->result_id(),
instruction->GetSingleWordInOperand(0));
});
// Update LCSSA OpPhi in merge block of |loop_1_|.
loop_1_->GetMergeBlock()->ForEachPhiInst(
[condition_block_of_0](ir::Instruction* instruction) {
[condition_block_of_0](opt::Instruction* instruction) {
instruction->SetInOperand(1, {condition_block_of_0->id()});
});
@ -627,7 +627,7 @@ void LoopFusion::Fuse() {
// Gather all instructions to be killed from |loop_1_| (induction variable
// initialisation, header, condition and continue blocks).
std::vector<ir::Instruction*> instr_to_delete{};
std::vector<opt::Instruction*> instr_to_delete{};
AddInstructionsInBlock(&instr_to_delete, loop_1_->GetPreHeaderBlock());
AddInstructionsInBlock(&instr_to_delete, loop_1_->GetHeaderBlock());
AddInstructionsInBlock(&instr_to_delete, loop_1_->FindConditionBlock());
@ -673,7 +673,7 @@ void LoopFusion::Fuse() {
auto ld = context_->GetLoopDescriptor(containing_function_);
// Create a copy, so the iterator wouldn't be invalidated.
std::vector<ir::Loop*> loops_to_add_remove{};
std::vector<opt::Loop*> loops_to_add_remove{};
for (auto child_loop : *loop_1_) {
loops_to_add_remove.push_back(child_loop);
}
@ -722,10 +722,10 @@ void LoopFusion::Fuse() {
// Invalidate analyses.
context_->InvalidateAnalysesExceptFor(
ir::IRContext::Analysis::kAnalysisInstrToBlockMapping |
ir::IRContext::Analysis::kAnalysisLoopAnalysis |
ir::IRContext::Analysis::kAnalysisDefUse |
ir::IRContext::Analysis::kAnalysisCFG);
opt::IRContext::Analysis::kAnalysisInstrToBlockMapping |
opt::IRContext::Analysis::kAnalysisLoopAnalysis |
opt::IRContext::Analysis::kAnalysisDefUse |
opt::IRContext::Analysis::kAnalysisCFG);
}
} // namespace opt

View File

@ -29,7 +29,7 @@ namespace opt {
class LoopFusion {
public:
LoopFusion(ir::IRContext* context, ir::Loop* loop_0, ir::Loop* loop_1)
LoopFusion(opt::IRContext* context, opt::Loop* loop_0, opt::Loop* loop_1)
: context_(context),
loop_0_(loop_0),
loop_1_(loop_1),
@ -70,42 +70,42 @@ class LoopFusion {
// Returns |true| if |instruction| is used in the continue or condition block
// of |loop|.
bool UsedInContinueOrConditionBlock(ir::Instruction* instruction,
ir::Loop* loop);
bool UsedInContinueOrConditionBlock(opt::Instruction* instruction,
opt::Loop* loop);
// Remove entries in |instructions| that are not used in the continue or
// condition block of |loop|.
void RemoveIfNotUsedContinueOrConditionBlock(
std::vector<ir::Instruction*>* instructions, ir::Loop* loop);
std::vector<opt::Instruction*>* instructions, opt::Loop* loop);
// Returns |true| if |instruction| is used in |loop|.
bool IsUsedInLoop(ir::Instruction* instruction, ir::Loop* loop);
bool IsUsedInLoop(opt::Instruction* instruction, opt::Loop* loop);
// Returns |true| if |loop| has at least one barrier or function call.
bool ContainsBarriersOrFunctionCalls(ir::Loop* loop);
bool ContainsBarriersOrFunctionCalls(opt::Loop* loop);
// Get all instructions in the |loop| (except in the latch block) that have
// the opcode |opcode|.
std::pair<std::vector<ir::Instruction*>, std::vector<ir::Instruction*>>
GetLoadsAndStoresInLoop(ir::Loop* loop);
std::pair<std::vector<opt::Instruction*>, std::vector<opt::Instruction*>>
GetLoadsAndStoresInLoop(opt::Loop* loop);
// Given a vector of memory operations (OpLoad/OpStore), constructs a map from
// variables to the loads/stores that those variables.
std::map<ir::Instruction*, std::vector<ir::Instruction*>> LocationToMemOps(
const std::vector<ir::Instruction*>& mem_ops);
std::map<opt::Instruction*, std::vector<opt::Instruction*>> LocationToMemOps(
const std::vector<opt::Instruction*>& mem_ops);
ir::IRContext* context_;
opt::IRContext* context_;
// The original loops to be fused.
ir::Loop* loop_0_;
ir::Loop* loop_1_;
opt::Loop* loop_0_;
opt::Loop* loop_1_;
// The function that contains |loop_0_| and |loop_1_|.
ir::Function* containing_function_ = nullptr;
opt::Function* containing_function_ = nullptr;
// The induction variables for |loop_0_| and |loop_1_|.
ir::Instruction* induction_0_ = nullptr;
ir::Instruction* induction_1_ = nullptr;
opt::Instruction* induction_0_ = nullptr;
opt::Instruction* induction_1_ = nullptr;
};
} // namespace opt

View File

@ -22,21 +22,21 @@
namespace spvtools {
namespace opt {
Pass::Status LoopFusionPass::Process(ir::IRContext* c) {
Pass::Status LoopFusionPass::Process(opt::IRContext* c) {
bool modified = false;
ir::Module* module = c->module();
opt::Module* module = c->module();
// Process each function in the module
for (ir::Function& f : *module) {
for (opt::Function& f : *module) {
modified |= ProcessFunction(&f);
}
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
bool LoopFusionPass::ProcessFunction(ir::Function* function) {
bool LoopFusionPass::ProcessFunction(opt::Function* function) {
auto c = function->context();
ir::LoopDescriptor& ld = *c->GetLoopDescriptor(function);
opt::LoopDescriptor& ld = *c->GetLoopDescriptor(function);
// If a loop doesn't have a preheader needs then it needs to be created. Make
// sure to return Status::SuccessWithChange in that case.

View File

@ -34,12 +34,12 @@ class LoopFusionPass : public Pass {
// Processes the given |module|. Returns Status::Failure if errors occur when
// processing. Returns the corresponding Status::Success if processing is
// succesful to indicate whether changes have been made to the modue.
Status Process(ir::IRContext* c) override;
Status Process(opt::IRContext* c) override;
private:
// Fuse loops in |function| if compatible, legal and the fused loop won't use
// too many registers.
bool ProcessFunction(ir::Function* function);
bool ProcessFunction(opt::Function* function);
// The maximum number of registers a fused loop is allowed to use.
size_t max_registers_per_loop_;

Some files were not shown because too many files have changed in this diff Show More