2017-06-02 19:23:20 +00:00
|
|
|
// Copyright (c) 2017 The Khronos Group Inc.
|
|
|
|
// Copyright (c) 2017 Valve Corporation
|
|
|
|
// Copyright (c) 2017 LunarG Inc.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#include "dead_branch_elim_pass.h"
|
|
|
|
|
|
|
|
#include "cfa.h"
|
|
|
|
#include "iterator.h"
|
|
|
|
|
|
|
|
namespace spvtools {
|
|
|
|
namespace opt {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2017-10-16 23:30:52 +00:00
|
|
|
const uint32_t kBranchTargetLabIdInIdx = 0;
|
2017-06-02 19:23:20 +00:00
|
|
|
const uint32_t kBranchCondTrueLabIdInIdx = 1;
|
|
|
|
const uint32_t kBranchCondFalseLabIdInIdx = 2;
|
|
|
|
const uint32_t kSelectionMergeMergeBlockIdInIdx = 0;
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2017-10-06 02:37:00 +00:00
|
|
|
bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) {
|
|
|
|
bool condIsConst;
|
2017-10-25 17:26:25 +00:00
|
|
|
ir::Instruction* cInst = get_def_use_mgr()->GetDef(condId);
|
2017-06-02 19:23:20 +00:00
|
|
|
switch (cInst->opcode()) {
|
|
|
|
case SpvOpConstantFalse: {
|
|
|
|
*condVal = false;
|
2017-10-06 02:37:00 +00:00
|
|
|
condIsConst = true;
|
2017-06-02 19:23:20 +00:00
|
|
|
} break;
|
|
|
|
case SpvOpConstantTrue: {
|
|
|
|
*condVal = true;
|
2017-10-06 02:37:00 +00:00
|
|
|
condIsConst = true;
|
2017-06-02 19:23:20 +00:00
|
|
|
} break;
|
|
|
|
case SpvOpLogicalNot: {
|
|
|
|
bool negVal;
|
2017-10-06 02:37:00 +00:00
|
|
|
condIsConst = GetConstCondition(cInst->GetSingleWordInOperand(0),
|
|
|
|
&negVal);
|
|
|
|
if (condIsConst)
|
2017-06-02 19:23:20 +00:00
|
|
|
*condVal = !negVal;
|
|
|
|
} break;
|
|
|
|
default: {
|
2017-10-06 02:37:00 +00:00
|
|
|
condIsConst = false;
|
2017-06-02 19:23:20 +00:00
|
|
|
} break;
|
|
|
|
}
|
2017-10-06 02:37:00 +00:00
|
|
|
return condIsConst;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DeadBranchElimPass::GetConstInteger(uint32_t selId, uint32_t* selVal) {
|
2017-10-25 17:26:25 +00:00
|
|
|
ir::Instruction* sInst = get_def_use_mgr()->GetDef(selId);
|
2017-10-06 02:37:00 +00:00
|
|
|
uint32_t typeId = sInst->type_id();
|
2017-10-25 17:26:25 +00:00
|
|
|
ir::Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
|
2017-10-12 16:21:26 +00:00
|
|
|
if (!typeInst || (typeInst->opcode() != SpvOpTypeInt)) return false;
|
2017-10-06 02:37:00 +00:00
|
|
|
// TODO(greg-lunarg): Support non-32 bit ints
|
|
|
|
if (typeInst->GetSingleWordInOperand(0) != 32)
|
|
|
|
return false;
|
|
|
|
if (sInst->opcode() == SpvOpConstant) {
|
|
|
|
*selVal = sInst->GetSingleWordInOperand(0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (sInst->opcode() == SpvOpConstantNull) {
|
|
|
|
*selVal = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2017-06-02 19:23:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeadBranchElimPass::AddBranch(uint32_t labelId, ir::BasicBlock* bp) {
|
|
|
|
std::unique_ptr<ir::Instruction> newBranch(
|
|
|
|
new ir::Instruction(SpvOpBranch, 0, 0,
|
|
|
|
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
|
2017-10-25 17:26:25 +00:00
|
|
|
get_def_use_mgr()->AnalyzeInstDefUse(&*newBranch);
|
2017-06-02 19:23:20 +00:00
|
|
|
bp->AddInstruction(std::move(newBranch));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeadBranchElimPass::AddSelectionMerge(uint32_t labelId,
|
|
|
|
ir::BasicBlock* bp) {
|
|
|
|
std::unique_ptr<ir::Instruction> newMerge(
|
|
|
|
new ir::Instruction(SpvOpSelectionMerge, 0, 0,
|
|
|
|
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}},
|
|
|
|
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {0}}}));
|
2017-10-25 17:26:25 +00:00
|
|
|
get_def_use_mgr()->AnalyzeInstDefUse(&*newMerge);
|
2017-06-02 19:23:20 +00:00
|
|
|
bp->AddInstruction(std::move(newMerge));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeadBranchElimPass::AddBranchConditional(uint32_t condId,
|
|
|
|
uint32_t trueLabId, uint32_t falseLabId, ir::BasicBlock* bp) {
|
|
|
|
std::unique_ptr<ir::Instruction> newBranchCond(
|
|
|
|
new ir::Instruction(SpvOpBranchConditional, 0, 0,
|
|
|
|
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {condId}},
|
|
|
|
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {trueLabId}},
|
|
|
|
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {falseLabId}}}));
|
2017-10-25 17:26:25 +00:00
|
|
|
get_def_use_mgr()->AnalyzeInstDefUse(&*newBranchCond);
|
2017-06-02 19:23:20 +00:00
|
|
|
bp->AddInstruction(std::move(newBranchCond));
|
|
|
|
}
|
|
|
|
|
2017-10-06 02:37:00 +00:00
|
|
|
bool DeadBranchElimPass::GetSelectionBranch(ir::BasicBlock* bp,
|
2017-06-02 19:23:20 +00:00
|
|
|
ir::Instruction** branchInst, ir::Instruction** mergeInst,
|
2017-10-06 02:37:00 +00:00
|
|
|
uint32_t *condId) {
|
2017-06-02 19:23:20 +00:00
|
|
|
auto ii = bp->end();
|
|
|
|
--ii;
|
|
|
|
*branchInst = &*ii;
|
|
|
|
if (ii == bp->begin())
|
|
|
|
return false;
|
|
|
|
--ii;
|
|
|
|
*mergeInst = &*ii;
|
|
|
|
if ((*mergeInst)->opcode() != SpvOpSelectionMerge)
|
|
|
|
return false;
|
2017-10-12 16:21:26 +00:00
|
|
|
// SPIR-V says the terminator for an OpSelectionMerge must be
|
|
|
|
// either a conditional branch or a switch.
|
|
|
|
assert((*branchInst)->opcode() == SpvOpBranchConditional ||
|
|
|
|
(*branchInst)->opcode() == SpvOpSwitch);
|
2017-10-06 02:37:00 +00:00
|
|
|
// Both BranchConidtional and Switch have their conditional value at 0.
|
|
|
|
*condId = (*branchInst)->GetSingleWordInOperand(0);
|
|
|
|
return true;
|
2017-06-02 19:23:20 +00:00
|
|
|
}
|
|
|
|
|
2017-10-16 23:30:52 +00:00
|
|
|
bool DeadBranchElimPass::HasNonPhiNonBackedgeRef(uint32_t labelId) {
|
2017-10-25 17:26:25 +00:00
|
|
|
analysis::UseList* uses = get_def_use_mgr()->GetUses(labelId);
|
2017-06-02 19:23:20 +00:00
|
|
|
if (uses == nullptr)
|
|
|
|
return false;
|
2017-10-16 23:30:52 +00:00
|
|
|
for (auto u : *uses) {
|
|
|
|
if (u.inst->opcode() != SpvOpPhi &&
|
|
|
|
backedges_.find(u.inst) == backedges_.end())
|
2017-06-02 19:23:20 +00:00
|
|
|
return true;
|
2017-10-16 23:30:52 +00:00
|
|
|
}
|
2017-06-02 19:23:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-16 23:30:52 +00:00
|
|
|
void DeadBranchElimPass::ComputeBackEdges(
|
|
|
|
std::list<ir::BasicBlock*>& structuredOrder) {
|
|
|
|
backedges_.clear();
|
|
|
|
std::unordered_set<uint32_t> visited;
|
|
|
|
// In structured order, edges to visited blocks are back edges
|
|
|
|
for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) {
|
|
|
|
visited.insert((*bi)->id());
|
|
|
|
auto ii = (*bi)->end();
|
|
|
|
--ii;
|
|
|
|
switch(ii->opcode()) {
|
|
|
|
case SpvOpBranch: {
|
|
|
|
const uint32_t labId = ii->GetSingleWordInOperand(
|
|
|
|
kBranchTargetLabIdInIdx);
|
|
|
|
if (visited.find(labId) != visited.end())
|
|
|
|
backedges_.insert(&*ii);
|
|
|
|
} break;
|
|
|
|
case SpvOpBranchConditional: {
|
|
|
|
const uint32_t tLabId = ii->GetSingleWordInOperand(
|
|
|
|
kBranchCondTrueLabIdInIdx);
|
|
|
|
if (visited.find(tLabId) != visited.end()) {
|
|
|
|
backedges_.insert(&*ii);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const uint32_t fLabId = ii->GetSingleWordInOperand(
|
|
|
|
kBranchCondFalseLabIdInIdx);
|
|
|
|
if (visited.find(fLabId) != visited.end())
|
|
|
|
backedges_.insert(&*ii);
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-02 19:23:20 +00:00
|
|
|
bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
|
|
|
|
// Traverse blocks in structured order
|
|
|
|
std::list<ir::BasicBlock*> structuredOrder;
|
2017-10-17 22:33:43 +00:00
|
|
|
ComputeStructuredOrder(func, &*func->begin(), &structuredOrder);
|
2017-10-16 23:30:52 +00:00
|
|
|
ComputeBackEdges(structuredOrder);
|
2017-06-02 19:23:20 +00:00
|
|
|
std::unordered_set<ir::BasicBlock*> elimBlocks;
|
|
|
|
bool modified = false;
|
|
|
|
for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) {
|
|
|
|
// Skip blocks that are already in the elimination set
|
|
|
|
if (elimBlocks.find(*bi) != elimBlocks.end())
|
|
|
|
continue;
|
2017-10-06 02:37:00 +00:00
|
|
|
// Skip blocks that don't have conditional branch preceded
|
2017-06-02 19:23:20 +00:00
|
|
|
// by OpSelectionMerge
|
|
|
|
ir::Instruction* br;
|
|
|
|
ir::Instruction* mergeInst;
|
|
|
|
uint32_t condId;
|
2017-10-06 02:37:00 +00:00
|
|
|
if (!GetSelectionBranch(*bi, &br, &mergeInst, &condId))
|
2017-06-02 19:23:20 +00:00
|
|
|
continue;
|
|
|
|
|
2017-10-06 02:37:00 +00:00
|
|
|
// If constant condition/selector, replace conditional branch/switch
|
|
|
|
// with unconditional branch and delete merge
|
|
|
|
uint32_t liveLabId;
|
|
|
|
if (br->opcode() == SpvOpBranchConditional) {
|
|
|
|
bool condVal;
|
|
|
|
if (!GetConstCondition(condId, &condVal))
|
|
|
|
continue;
|
|
|
|
liveLabId = (condVal == true) ?
|
|
|
|
br->GetSingleWordInOperand(kBranchCondTrueLabIdInIdx) :
|
|
|
|
br->GetSingleWordInOperand(kBranchCondFalseLabIdInIdx);
|
|
|
|
}
|
|
|
|
else {
|
2017-10-12 16:21:26 +00:00
|
|
|
assert(br->opcode() == SpvOpSwitch);
|
2017-10-06 02:37:00 +00:00
|
|
|
// Search switch operands for selector value, set liveLabId to
|
|
|
|
// corresponding label, use default if not found
|
|
|
|
uint32_t selVal;
|
|
|
|
if (!GetConstInteger(condId, &selVal))
|
|
|
|
continue;
|
|
|
|
uint32_t icnt = 0;
|
|
|
|
uint32_t caseVal;
|
|
|
|
br->ForEachInOperand(
|
|
|
|
[&icnt,&caseVal,&selVal,&liveLabId](const uint32_t* idp) {
|
|
|
|
if (icnt == 1) {
|
|
|
|
// Start with default label
|
|
|
|
liveLabId = *idp;
|
|
|
|
}
|
|
|
|
else if (icnt > 1) {
|
|
|
|
if (icnt % 2 == 0) {
|
|
|
|
caseVal = *idp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (caseVal == selVal)
|
|
|
|
liveLabId = *idp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++icnt;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-06-02 19:23:20 +00:00
|
|
|
const uint32_t mergeLabId =
|
|
|
|
mergeInst->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
|
|
|
|
AddBranch(liveLabId, *bi);
|
2017-10-25 17:26:25 +00:00
|
|
|
get_def_use_mgr()->KillInst(br);
|
|
|
|
get_def_use_mgr()->KillInst(mergeInst);
|
2017-06-02 19:23:20 +00:00
|
|
|
|
2017-10-06 02:37:00 +00:00
|
|
|
modified = true;
|
|
|
|
|
2017-06-02 19:23:20 +00:00
|
|
|
// Iterate to merge block adding dead blocks to elimination set
|
|
|
|
auto dbi = bi;
|
|
|
|
++dbi;
|
|
|
|
uint32_t dLabId = (*dbi)->id();
|
|
|
|
while (dLabId != mergeLabId) {
|
2017-10-16 23:30:52 +00:00
|
|
|
if (!HasNonPhiNonBackedgeRef(dLabId)) {
|
2017-06-02 19:23:20 +00:00
|
|
|
// Kill use/def for all instructions and mark block for elimination
|
|
|
|
KillAllInsts(*dbi);
|
|
|
|
elimBlocks.insert(*dbi);
|
|
|
|
}
|
|
|
|
++dbi;
|
|
|
|
dLabId = (*dbi)->id();
|
|
|
|
}
|
|
|
|
|
2017-10-06 02:37:00 +00:00
|
|
|
// If merge block is unreachable, continue eliminating blocks until
|
|
|
|
// a live block or last block is reached.
|
2017-10-16 23:30:52 +00:00
|
|
|
while (!HasNonPhiNonBackedgeRef(dLabId)) {
|
2017-10-06 02:37:00 +00:00
|
|
|
KillAllInsts(*dbi);
|
|
|
|
elimBlocks.insert(*dbi);
|
|
|
|
++dbi;
|
|
|
|
if (dbi == structuredOrder.end())
|
|
|
|
break;
|
|
|
|
dLabId = (*dbi)->id();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If last block reached, look for next dead branch
|
|
|
|
if (dbi == structuredOrder.end())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Create set of dead predecessors in preparation for phi update.
|
|
|
|
// Add the header block if the live branch is not the merge block.
|
|
|
|
std::unordered_set<ir::BasicBlock*> deadPreds(elimBlocks);
|
|
|
|
if (liveLabId != dLabId)
|
|
|
|
deadPreds.insert(*bi);
|
|
|
|
|
|
|
|
// Update phi instructions in terminating block.
|
|
|
|
for (auto pii = (*dbi)->begin(); ; ++pii) {
|
|
|
|
// Skip NoOps, break at end of phis
|
|
|
|
SpvOp op = pii->opcode();
|
|
|
|
if (op == SpvOpNop)
|
|
|
|
continue;
|
|
|
|
if (op != SpvOpPhi)
|
|
|
|
break;
|
|
|
|
// Count phi's live predecessors with lcnt and remember last one
|
|
|
|
// with lidx.
|
|
|
|
uint32_t lcnt = 0;
|
|
|
|
uint32_t lidx = 0;
|
|
|
|
uint32_t icnt = 0;
|
|
|
|
pii->ForEachInId(
|
|
|
|
[&deadPreds,&icnt,&lcnt,&lidx,this](uint32_t* idp) {
|
|
|
|
if (icnt % 2 == 1) {
|
|
|
|
if (deadPreds.find(id2block_[*idp]) == deadPreds.end()) {
|
|
|
|
++lcnt;
|
|
|
|
lidx = icnt - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++icnt;
|
|
|
|
});
|
|
|
|
// If just one live predecessor, replace resultid with live value id.
|
|
|
|
uint32_t replId;
|
|
|
|
if (lcnt == 1) {
|
|
|
|
replId = pii->GetSingleWordInOperand(lidx);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Otherwise create new phi eliminating dead predecessor entries
|
|
|
|
assert(lcnt > 1);
|
|
|
|
replId = TakeNextId();
|
|
|
|
std::vector<ir::Operand> phi_in_opnds;
|
|
|
|
icnt = 0;
|
|
|
|
uint32_t lastId;
|
|
|
|
pii->ForEachInId(
|
|
|
|
[&deadPreds,&icnt,&phi_in_opnds,&lastId,this](uint32_t* idp) {
|
|
|
|
if (icnt % 2 == 1) {
|
|
|
|
if (deadPreds.find(id2block_[*idp]) == deadPreds.end()) {
|
|
|
|
phi_in_opnds.push_back(
|
|
|
|
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {lastId}});
|
|
|
|
phi_in_opnds.push_back(
|
|
|
|
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*idp}});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lastId = *idp;
|
|
|
|
}
|
|
|
|
++icnt;
|
|
|
|
});
|
|
|
|
std::unique_ptr<ir::Instruction> newPhi(new ir::Instruction(
|
|
|
|
SpvOpPhi, pii->type_id(), replId, phi_in_opnds));
|
2017-10-25 17:26:25 +00:00
|
|
|
get_def_use_mgr()->AnalyzeInstDefUse(&*newPhi);
|
2017-10-06 02:37:00 +00:00
|
|
|
pii = pii.InsertBefore(std::move(newPhi));
|
|
|
|
++pii;
|
|
|
|
}
|
|
|
|
const uint32_t phiId = pii->result_id();
|
2017-07-26 22:34:41 +00:00
|
|
|
KillNamesAndDecorates(phiId);
|
2017-10-25 17:26:25 +00:00
|
|
|
(void)get_def_use_mgr()->ReplaceAllUsesWith(phiId, replId);
|
|
|
|
get_def_use_mgr()->KillInst(&*pii);
|
2017-06-02 19:23:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Erase dead blocks
|
|
|
|
for (auto ebi = func->begin(); ebi != func->end(); )
|
|
|
|
if (elimBlocks.find(&*ebi) != elimBlocks.end())
|
|
|
|
ebi = ebi.Erase();
|
|
|
|
else
|
|
|
|
++ebi;
|
|
|
|
return modified;
|
|
|
|
}
|
|
|
|
|
2017-10-30 15:13:24 +00:00
|
|
|
void DeadBranchElimPass::Initialize(ir::IRContext* c) {
|
|
|
|
InitializeProcessing(c);
|
2017-06-02 19:23:20 +00:00
|
|
|
|
|
|
|
// Initialize function and block maps
|
|
|
|
id2block_.clear();
|
|
|
|
block2structured_succs_.clear();
|
2017-08-10 22:42:16 +00:00
|
|
|
|
|
|
|
// Initialize block map
|
2017-10-25 17:26:25 +00:00
|
|
|
for (auto& fn : *get_module())
|
2017-08-10 22:42:16 +00:00
|
|
|
for (auto& blk : fn)
|
2017-06-02 19:23:20 +00:00
|
|
|
id2block_[blk.id()] = &blk;
|
|
|
|
|
2017-07-19 00:57:26 +00:00
|
|
|
// Initialize extension whitelist
|
|
|
|
InitExtensions();
|
2017-06-02 19:23:20 +00:00
|
|
|
};
|
|
|
|
|
2017-07-19 00:57:26 +00:00
|
|
|
bool DeadBranchElimPass::AllExtensionsSupported() const {
|
|
|
|
// If any extension not in whitelist, return false
|
2017-10-25 17:26:25 +00:00
|
|
|
for (auto& ei : get_module()->extensions()) {
|
2017-07-19 00:57:26 +00:00
|
|
|
const char* extName = reinterpret_cast<const char*>(
|
|
|
|
&ei.GetInOperand(0).words[0]);
|
|
|
|
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-02 19:23:20 +00:00
|
|
|
Pass::Status DeadBranchElimPass::ProcessImpl() {
|
|
|
|
// Current functionality assumes structured control flow.
|
|
|
|
// TODO(greg-lunarg): Handle non-structured control-flow.
|
2017-10-25 17:26:25 +00:00
|
|
|
if (!get_module()->HasCapability(SpvCapabilityShader))
|
2017-06-02 19:23:20 +00:00
|
|
|
return Status::SuccessWithoutChange;
|
2017-07-26 22:34:41 +00:00
|
|
|
// Do not process if module contains OpGroupDecorate. Additional
|
|
|
|
// support required in KillNamesAndDecorates().
|
|
|
|
// TODO(greg-lunarg): Add support for OpGroupDecorate
|
2017-10-25 17:26:25 +00:00
|
|
|
for (auto& ai : get_module()->annotations())
|
2017-07-26 22:34:41 +00:00
|
|
|
if (ai.opcode() == SpvOpGroupDecorate)
|
|
|
|
return Status::SuccessWithoutChange;
|
2017-07-19 00:57:26 +00:00
|
|
|
// Do not process if any disallowed extensions are enabled
|
|
|
|
if (!AllExtensionsSupported())
|
|
|
|
return Status::SuccessWithoutChange;
|
|
|
|
// Process all entry point functions
|
2017-08-10 22:42:16 +00:00
|
|
|
ProcessFunction pfn = [this](ir::Function* fp) {
|
|
|
|
return EliminateDeadBranches(fp);
|
|
|
|
};
|
2017-10-25 17:26:25 +00:00
|
|
|
bool modified = ProcessEntryPointCallTree(pfn, get_module());
|
2017-06-02 19:23:20 +00:00
|
|
|
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
|
|
|
|
}
|
|
|
|
|
2017-07-27 19:30:12 +00:00
|
|
|
DeadBranchElimPass::DeadBranchElimPass() {}
|
2017-06-02 19:23:20 +00:00
|
|
|
|
2017-10-30 15:13:24 +00:00
|
|
|
Pass::Status DeadBranchElimPass::Process(ir::IRContext* module) {
|
2017-06-02 19:23:20 +00:00
|
|
|
Initialize(module);
|
|
|
|
return ProcessImpl();
|
|
|
|
}
|
|
|
|
|
2017-07-19 00:57:26 +00:00
|
|
|
void DeadBranchElimPass::InitExtensions() {
|
|
|
|
extensions_whitelist_.clear();
|
|
|
|
extensions_whitelist_.insert({
|
|
|
|
"SPV_AMD_shader_explicit_vertex_parameter",
|
|
|
|
"SPV_AMD_shader_trinary_minmax",
|
|
|
|
"SPV_AMD_gcn_shader",
|
|
|
|
"SPV_KHR_shader_ballot",
|
|
|
|
"SPV_AMD_shader_ballot",
|
|
|
|
"SPV_AMD_gpu_shader_half_float",
|
|
|
|
"SPV_KHR_shader_draw_parameters",
|
|
|
|
"SPV_KHR_subgroup_vote",
|
|
|
|
"SPV_KHR_16bit_storage",
|
|
|
|
"SPV_KHR_device_group",
|
|
|
|
"SPV_KHR_multiview",
|
|
|
|
"SPV_NVX_multiview_per_view_attributes",
|
|
|
|
"SPV_NV_viewport_array2",
|
|
|
|
"SPV_NV_stereo_view_rendering",
|
|
|
|
"SPV_NV_sample_mask_override_coverage",
|
|
|
|
"SPV_NV_geometry_shader_passthrough",
|
|
|
|
"SPV_AMD_texture_gather_bias_lod",
|
|
|
|
"SPV_KHR_storage_buffer_storage_class",
|
|
|
|
"SPV_KHR_variable_pointers",
|
|
|
|
"SPV_AMD_gpu_shader_int16",
|
|
|
|
"SPV_KHR_post_depth_coverage",
|
|
|
|
"SPV_KHR_shader_atomic_counter_ops",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-06-02 19:23:20 +00:00
|
|
|
} // namespace opt
|
|
|
|
} // namespace spvtools
|
|
|
|
|