#include "aggressive_dead_code_elim_pass.h"
#include "iterator.h"
-
#include "spirv/1.0/GLSL.std.450.h"
namespace spvtools {
bp->AddInstruction(std::move(newBranchCond));
}
+void DeadBranchElimPass::KillNamesAndDecorates(uint32_t id) {
+ // TODO(greg-lunarg): Remove id from any OpGroupDecorate and
+ // kill if no other operands.
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return;
+ analysis::UseList* uses = def_use_mgr_->GetUses(id);
+ if (uses == nullptr)
+ return;
+ std::list<ir::Instruction*> killList;
+ for (auto u : *uses) {
+ const SpvOp op = u.inst->opcode();
+ if (op == SpvOpName || IsDecorate(op))
+ killList.push_back(u.inst);
+ }
+ for (auto kip : killList)
+ def_use_mgr_->KillInst(kip);
+}
+
+void DeadBranchElimPass::KillNamesAndDecorates(ir::Instruction* inst) {
+ const uint32_t rId = inst->result_id();
+ if (rId == 0)
+ return;
+ KillNamesAndDecorates(rId);
+}
+
void DeadBranchElimPass::KillAllInsts(ir::BasicBlock* bp) {
bp->ForEachInst([this](ir::Instruction* ip) {
+ KillNamesAndDecorates(ip);
def_use_mgr_->KillInst(ip);
});
}
useFirst ? kPhiVal0IdInIdx : kPhiVal1IdInIdx;
const uint32_t replId = phiInst->GetSingleWordInOperand(phiValIdx);
const uint32_t phiId = phiInst->result_id();
+ KillNamesAndDecorates(phiId);
(void)def_use_mgr_->ReplaceAllUsesWith(phiId, replId);
def_use_mgr_->KillInst(phiInst);
});
InitExtensions();
};
+void DeadBranchElimPass::FindNamedOrDecoratedIds() {
+ for (auto& di : module_->debugs())
+ if (di.opcode() == SpvOpName)
+ named_or_decorated_ids_.insert(di.GetSingleWordInOperand(0));
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpDecorate || ai.opcode() == SpvOpDecorateId)
+ named_or_decorated_ids_.insert(ai.GetSingleWordInOperand(0));
+}
+
bool DeadBranchElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : module_->extensions()) {
// TODO(greg-lunarg): Handle non-structured control-flow.
if (!module_->HasCapability(SpvCapabilityShader))
return Status::SuccessWithoutChange;
+ // Do not process if module contains OpGroupDecorate. Additional
+ // support required in KillNamesAndDecorates().
+ // TODO(greg-lunarg): Add support for OpGroupDecorate
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpGroupDecorate)
+ return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
+ // Collect all named and decorated ids
+ FindNamedOrDecoratedIds();
// Process all entry point functions
bool modified = false;
for (const auto& e : module_->entry_points()) {
// Return true if |labelId| has any non-phi references
bool HasNonPhiRef(uint32_t labelId);
+ // Return true if |op| is supported decorate.
+ inline bool IsDecorate(uint32_t op) const {
+ return (op == SpvOpDecorate || op == SpvOpDecorateId);
+ }
+
+ // Kill all name and decorate ops using |inst|
+ void KillNamesAndDecorates(ir::Instruction* inst);
+
+ // Kill all name and decorate ops using |id|
+ void KillNamesAndDecorates(uint32_t id);
+
+ // Collect all named or decorated ids in module
+ void FindNamedOrDecoratedIds();
+
// For function |func|, look for BranchConditionals with constant condition
// and convert to a Branch to the indicated label. Delete resulting dead
// blocks. Assumes only structured control flow in shader. Note some such
// ComputeStructuredSuccessors() for definition.
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
block2structured_succs_;
+
+ // named or decorated ids
+ std::unordered_set<uint32_t> named_or_decorated_ids_;
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
return true;
}
+bool LocalAccessChainConvertPass::HasOnlyNamesAndDecorates(uint32_t id) const {
+ analysis::UseList* uses = def_use_mgr_->GetUses(id);
+ if (uses == nullptr)
+ return true;
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return false;
+ for (auto u : *uses) {
+ const SpvOp op = u.inst->opcode();
+ if (op != SpvOpName && !IsDecorate(op))
+ return false;
+ }
+ return true;
+}
+
void LocalAccessChainConvertPass::DeleteIfUseless(ir::Instruction* inst) {
const uint32_t resId = inst->result_id();
assert(resId != 0);
- analysis::UseList* uses = def_use_mgr_->GetUses(resId);
- if (uses == nullptr)
+ if (HasOnlyNamesAndDecorates(resId)) {
+ KillNamesAndDecorates(resId);
def_use_mgr_->KillInst(inst);
+ }
}
void LocalAccessChainConvertPass::ReplaceAndDeleteLoad(
uint32_t replId,
ir::Instruction* ptrInst) {
const uint32_t loadId = loadInst->result_id();
+ KillNamesAndDecorates(loadId);
(void) def_use_mgr_->ReplaceAllUsesWith(loadId, replId);
// remove load instruction
def_use_mgr_->KillInst(loadInst);
}
}
+void LocalAccessChainConvertPass::KillNamesAndDecorates(uint32_t id) {
+ // TODO(greg-lunarg): Remove id from any OpGroupDecorate and
+ // kill if no other operands.
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return;
+ analysis::UseList* uses = def_use_mgr_->GetUses(id);
+ if (uses == nullptr)
+ return;
+ std::list<ir::Instruction*> killList;
+ for (auto u : *uses) {
+ const SpvOp op = u.inst->opcode();
+ if (op == SpvOpName || IsDecorate(op))
+ killList.push_back(u.inst);
+ }
+ for (auto kip : killList)
+ def_use_mgr_->KillInst(kip);
+}
+
+void LocalAccessChainConvertPass::KillNamesAndDecorates(ir::Instruction* inst) {
+ const uint32_t rId = inst->result_id();
+ if (rId == 0)
+ return;
+ KillNamesAndDecorates(rId);
+}
+
uint32_t LocalAccessChainConvertPass::GetPointeeTypeId(
const ir::Instruction* ptrInst) const {
const uint32_t ptrTypeId = ptrInst->type_id();
InitExtensions();
};
+void LocalAccessChainConvertPass::FindNamedOrDecoratedIds() {
+ for (auto& di : module_->debugs())
+ if (di.opcode() == SpvOpName)
+ named_or_decorated_ids_.insert(di.GetSingleWordInOperand(0));
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpDecorate || ai.opcode() == SpvOpDecorateId)
+ named_or_decorated_ids_.insert(ai.GetSingleWordInOperand(0));
+}
+
bool LocalAccessChainConvertPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : module_->extensions()) {
if (inst.opcode() == SpvOpTypeInt &&
inst.GetSingleWordInOperand(kTypeIntWidthInIdx) != 32)
return Status::SuccessWithoutChange;
+
+ // Do not process if module contains OpGroupDecorate. Additional
+ // support required in KillNamesAndDecorates().
+ // TODO(greg-lunarg): Add support for OpGroupDecorate
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpGroupDecorate)
+ return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
+ // Collect all named and decorated ids
+ FindNamedOrDecoratedIds();
// Process all entry point functions.
bool modified = false;
for (auto& e : module_->entry_points()) {
// variables.
bool IsTargetVar(uint32_t varId);
+ // Return true if |op| is supported decorate.
+ inline bool IsDecorate(uint32_t op) const {
+ return (op == SpvOpDecorate || op == SpvOpDecorateId);
+ }
+
+ // Return true if all uses of |id| are only name or decorate ops.
+ bool HasOnlyNamesAndDecorates(uint32_t id) const;
+
+ // Kill all name and decorate ops using |inst|
+ void KillNamesAndDecorates(ir::Instruction* inst);
+
+ // Kill all name and decorate ops using |id|
+ void KillNamesAndDecorates(uint32_t id);
+
+ // Collect all named or decorated ids in module
+ void FindNamedOrDecoratedIds();
+
// Delete |inst| if it has no uses. Assumes |inst| has a non-zero resultId.
void DeleteIfUseless(ir::Instruction* inst);
// Cache of verified non-target vars
std::unordered_set<uint32_t> seen_non_target_vars_;
+ // named or decorated ids
+ std::unordered_set<uint32_t> named_or_decorated_ids_;
+
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
void LocalSingleBlockLoadStoreElimPass::ReplaceAndDeleteLoad(
ir::Instruction* loadInst, uint32_t replId) {
const uint32_t loadId = loadInst->result_id();
+ KillNamesAndDecorates(loadId);
(void) def_use_mgr_->ReplaceAllUsesWith(loadId, replId);
// TODO(greg-lunarg): Consider moving DCE into separate pass
DCEInst(loadInst);
}
}
+bool LocalSingleBlockLoadStoreElimPass::HasOnlyNamesAndDecorates(
+ uint32_t id) const {
+ analysis::UseList* uses = def_use_mgr_->GetUses(id);
+ if (uses == nullptr)
+ return true;
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return false;
+ for (auto u : *uses) {
+ const SpvOp op = u.inst->opcode();
+ if (op != SpvOpName && !IsDecorate(op))
+ return false;
+ }
+ return true;
+}
+
+void LocalSingleBlockLoadStoreElimPass::KillNamesAndDecorates(uint32_t id) {
+ // TODO(greg-lunarg): Remove id from any OpGroupDecorate and
+ // kill if no other operands.
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return;
+ analysis::UseList* uses = def_use_mgr_->GetUses(id);
+ if (uses == nullptr)
+ return;
+ std::list<ir::Instruction*> killList;
+ for (auto u : *uses) {
+ const SpvOp op = u.inst->opcode();
+ if (op == SpvOpName || IsDecorate(op))
+ killList.push_back(u.inst);
+ }
+ for (auto kip : killList)
+ def_use_mgr_->KillInst(kip);
+}
+
+void LocalSingleBlockLoadStoreElimPass::KillNamesAndDecorates(
+ ir::Instruction* inst) {
+ const uint32_t rId = inst->result_id();
+ if (rId == 0)
+ return;
+ KillNamesAndDecorates(rId);
+}
+
void LocalSingleBlockLoadStoreElimPass::DCEInst(ir::Instruction* inst) {
std::queue<ir::Instruction*> deadInsts;
deadInsts.push(inst);
// Remember variable if dead load
if (di->opcode() == SpvOpLoad)
(void) GetPtr(di, &varId);
+ KillNamesAndDecorates(di);
def_use_mgr_->KillInst(di);
// For all operands with no remaining uses, add their instruction
// to the dead instruction queue.
for (auto id : ids) {
- analysis::UseList* uses = def_use_mgr_->GetUses(id);
- if (uses == nullptr)
+ if (HasOnlyNamesAndDecorates(id))
deadInsts.push(def_use_mgr_->GetDef(id));
}
// if a load was deleted and it was the variable's
InitExtensions();
};
+void LocalSingleBlockLoadStoreElimPass::FindNamedOrDecoratedIds() {
+ for (auto& di : module_->debugs())
+ if (di.opcode() == SpvOpName)
+ named_or_decorated_ids_.insert(di.GetSingleWordInOperand(0));
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpDecorate || ai.opcode() == SpvOpDecorateId)
+ named_or_decorated_ids_.insert(ai.GetSingleWordInOperand(0));
+}
+
bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : module_->extensions()) {
// Assumes logical addressing only
if (module_->HasCapability(SpvCapabilityAddresses))
return Status::SuccessWithoutChange;
+ // Do not process if module contains OpGroupDecorate. Additional
+ // support required in KillNamesAndDecorates().
+ // TODO(greg-lunarg): Add support for OpGroupDecorate
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpGroupDecorate)
+ return Status::SuccessWithoutChange;
// If any extensions in the module are not explicitly supported,
// return unmodified.
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
+ // Collect all named and decorated ids
+ FindNamedOrDecoratedIds();
// Process all entry point functions
bool modified = false;
for (auto& e : module_->entry_points()) {
// Add stores using |ptr_id| to |insts|
void AddStores(uint32_t ptr_id, std::queue<ir::Instruction*>* insts);
+ // Return true if |op| is supported decorate.
+ inline bool IsDecorate(uint32_t op) const {
+ return (op == SpvOpDecorate || op == SpvOpDecorateId);
+ }
+
+ // Return true if all uses of |id| are only name or decorate ops.
+ bool HasOnlyNamesAndDecorates(uint32_t id) const;
+
+ // Kill all name and decorate ops using |inst|
+ void KillNamesAndDecorates(ir::Instruction* inst);
+
+ // Kill all name and decorate ops using |id|
+ void KillNamesAndDecorates(uint32_t id);
+
+ // Collect all named or decorated ids in module
+ void FindNamedOrDecoratedIds();
+
// Delete |inst| and iterate DCE on all its operands. Won't delete
// labels.
void DCEInst(ir::Instruction* inst);
// from this set each time a new store of that variable is encountered.
std::unordered_set<uint32_t> pinned_vars_;
+ // named or decorated ids
+ std::unordered_set<uint32_t> named_or_decorated_ids_;
+
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
void LocalSingleStoreElimPass::ReplaceAndDeleteLoad(
ir::Instruction* loadInst, uint32_t replId) {
- (void) def_use_mgr_->ReplaceAllUsesWith(loadInst->result_id(), replId);
+ const uint32_t loadId = loadInst->result_id();
+ KillNamesAndDecorates(loadId);
+ (void) def_use_mgr_->ReplaceAllUsesWith(loadId, replId);
DCEInst(loadInst);
}
}
}
+bool LocalSingleStoreElimPass::HasOnlyNamesAndDecorates(
+ uint32_t id) const {
+ analysis::UseList* uses = def_use_mgr_->GetUses(id);
+ if (uses == nullptr)
+ return true;
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return false;
+ for (auto u : *uses) {
+ const SpvOp op = u.inst->opcode();
+ if (op != SpvOpName && !IsDecorate(op))
+ return false;
+ }
+ return true;
+}
+
+void LocalSingleStoreElimPass::KillNamesAndDecorates(uint32_t id) {
+ // TODO(greg-lunarg): Remove id from any OpGroupDecorate and
+ // kill if no other operands.
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return;
+ analysis::UseList* uses = def_use_mgr_->GetUses(id);
+ if (uses == nullptr)
+ return;
+ std::list<ir::Instruction*> killList;
+ for (auto u : *uses) {
+ const SpvOp op = u.inst->opcode();
+ if (op == SpvOpName || IsDecorate(op))
+ killList.push_back(u.inst);
+ }
+ for (auto kip : killList)
+ def_use_mgr_->KillInst(kip);
+}
+
+void LocalSingleStoreElimPass::KillNamesAndDecorates(
+ ir::Instruction* inst) {
+ const uint32_t rId = inst->result_id();
+ if (rId == 0)
+ return;
+ KillNamesAndDecorates(rId);
+}
+
void LocalSingleStoreElimPass::DCEInst(ir::Instruction* inst) {
std::queue<ir::Instruction*> deadInsts;
deadInsts.push(inst);
continue;
}
// Remember operands
- std::queue<uint32_t> ids;
+ std::vector<uint32_t> ids;
di->ForEachInId([&ids](uint32_t* iid) {
- ids.push(*iid);
+ ids.push_back(*iid);
});
uint32_t varId = 0;
// Remember variable if dead load
if (di->opcode() == SpvOpLoad)
(void) GetPtr(di, &varId);
+ KillNamesAndDecorates(di);
def_use_mgr_->KillInst(di);
// For all operands with no remaining uses, add their instruction
// to the dead instruction queue.
- while (!ids.empty()) {
- uint32_t id = ids.front();
- analysis::UseList* uses = def_use_mgr_->GetUses(id);
- if (uses == nullptr)
+ for (auto id : ids) {
+ if (HasOnlyNamesAndDecorates(id))
deadInsts.push(def_use_mgr_->GetDef(id));
- ids.pop();
}
// if a load was deleted and it was the variable's
// last load, add all its stores to dead queue
- if (varId != 0 && !IsLiveVar(varId))
+ if (varId != 0 && !IsLiveVar(varId))
AddStores(varId, &deadInsts);
deadInsts.pop();
}
InitExtensions();
};
+void LocalSingleStoreElimPass::FindNamedOrDecoratedIds() {
+ for (auto& di : module_->debugs())
+ if (di.opcode() == SpvOpName)
+ named_or_decorated_ids_.insert(di.GetSingleWordInOperand(0));
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpDecorate || ai.opcode() == SpvOpDecorateId)
+ named_or_decorated_ids_.insert(ai.GetSingleWordInOperand(0));
+}
+
bool LocalSingleStoreElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : module_->extensions()) {
// Assumes logical addressing only
if (module_->HasCapability(SpvCapabilityAddresses))
return Status::SuccessWithoutChange;
+ // Do not process if module contains OpGroupDecorate. Additional
+ // support required in KillNamesAndDecorates().
+ // TODO(greg-lunarg): Add support for OpGroupDecorate
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpGroupDecorate)
+ return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
+ // Collect all named and decorated ids
+ FindNamedOrDecoratedIds();
// Process all entry point functions
bool modified = false;
for (auto& e : module_->entry_points()) {
// Add stores using |ptr_id| to |insts|
void AddStores(uint32_t ptr_id, std::queue<ir::Instruction*>* insts);
+ // Return true if |op| is supported decorate.
+ inline bool IsDecorate(uint32_t op) const {
+ return (op == SpvOpDecorate || op == SpvOpDecorateId);
+ }
+
+ // Return true if all uses of |id| are only name or decorate ops.
+ bool HasOnlyNamesAndDecorates(uint32_t id) const;
+
+ // Kill all name and decorate ops using |inst|
+ void KillNamesAndDecorates(ir::Instruction* inst);
+
+ // Kill all name and decorate ops using |id|
+ void KillNamesAndDecorates(uint32_t id);
+
+ // Collect all named or decorated ids in module
+ void FindNamedOrDecoratedIds();
+
// Delete |inst| and iterate DCE on all its operands if they are now
// useless. If a load is deleted and its variable has no other loads,
// delete all its variable's stores.
// If block has no idom it points to itself.
std::unordered_map<ir::BasicBlock*, ir::BasicBlock*> idom_;
+ // named or decorated ids
+ std::unordered_set<uint32_t> named_or_decorated_ids_;
+
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
// Next unused ID
uint32_t next_id_;
-
};
} // namespace opt
analysis::UseList* uses = def_use_mgr_->GetUses(id);
if (uses == nullptr)
return true;
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return false;
for (auto u : *uses) {
const SpvOp op = u.inst->opcode();
if (op != SpvOpName && !IsDecorate(op))
void LocalMultiStoreElimPass::KillNamesAndDecorates(uint32_t id) {
// TODO(greg-lunarg): Remove id from any OpGroupDecorate and
// kill if no other operands.
+ if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
+ return;
analysis::UseList* uses = def_use_mgr_->GetUses(id);
if (uses == nullptr)
return;
}
void LocalMultiStoreElimPass::KillNamesAndDecorates(ir::Instruction* inst) {
- // TODO(greg-lunarg): Remove inst from any OpGroupDecorate and
- // kill if not other operands.
const uint32_t rId = inst->result_id();
if (rId == 0)
return;
return true;
}
+void LocalMultiStoreElimPass::FindNamedOrDecoratedIds() {
+ for (auto& di : module_->debugs())
+ if (di.opcode() == SpvOpName)
+ named_or_decorated_ids_.insert(di.GetSingleWordInOperand(0));
+ for (auto& ai : module_->annotations())
+ if (ai.opcode() == SpvOpDecorate || ai.opcode() == SpvOpDecorateId)
+ named_or_decorated_ids_.insert(ai.GetSingleWordInOperand(0));
+}
+
Pass::Status LocalMultiStoreElimPass::ProcessImpl() {
// Assumes all control flow structured.
// TODO(greg-lunarg): Do SSA rewrite for non-structured control flow
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
+ // Collect all named and decorated ids
+ FindNamedOrDecoratedIds();
// Process functions
bool modified = false;
for (auto& e : module_->entry_points()) {
// Return true if all extensions in this module are allowed by this pass.
bool AllExtensionsSupported() const;
+ // Collect all named or decorated ids in module
+ void FindNamedOrDecoratedIds();
+
// Remove remaining loads and stores of function scope variables only
// referenced with non-access-chain loads and stores from function |func|.
// Insert Phi functions where necessary. Running LocalAccessChainRemoval,
// pass ie. loads and stores.
std::unordered_set<uint32_t> supported_ref_vars_;
+ // named or decorated ids
+ std::unordered_set<uint32_t> named_or_decorated_ids_;
+
// Map from block to its structured successor blocks. See
// ComputeStructuredSuccessors() for definition.
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
predefs + before, predefs + after, true, true);
}
+TEST_F(DeadBranchElimTest, DecorateDeleted) {
+ // Note: SPIR-V hand-edited to add decoration
+ // #version 140
+ //
+ // in vec4 BaseColor;
+ //
+ // void main()
+ // {
+ // vec4 v = BaseColor;
+ // if (false)
+ // v = v * vec4(0.5,0.5,0.5,0.5);
+ // gl_FragColor = v;
+ // }
+
+ const std::string predefs_before =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %v "v"
+OpName %BaseColor "BaseColor"
+OpName %gl_FragColor "gl_FragColor"
+OpDecorate %22 RelaxedPrecision
+%void = OpTypeVoid
+%7 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%bool = OpTypeBool
+%false = OpConstantFalse %bool
+%float_0_5 = OpConstant %float 0.5
+%15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %v "v"
+OpName %BaseColor "BaseColor"
+OpName %gl_FragColor "gl_FragColor"
+%void = OpTypeVoid
+%8 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%bool = OpTypeBool
+%false = OpConstantFalse %bool
+%float_0_5 = OpConstant %float 0.5
+%16 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
+ const std::string before =
+ R"(%main = OpFunction %void None %7
+%17 = OpLabel
+%v = OpVariable %_ptr_Function_v4float Function
+%18 = OpLoad %v4float %BaseColor
+OpStore %v %18
+OpSelectionMerge %19 None
+OpBranchConditional %false %20 %19
+%20 = OpLabel
+%21 = OpLoad %v4float %v
+%22 = OpFMul %v4float %21 %15
+OpStore %v %22
+OpBranch %19
+%19 = OpLabel
+%23 = OpLoad %v4float %v
+OpStore %gl_FragColor %23
+OpReturn
+OpFunctionEnd
+)";
+
+ const std::string after =
+ R"(%main = OpFunction %void None %8
+%18 = OpLabel
+%v = OpVariable %_ptr_Function_v4float Function
+%19 = OpLoad %v4float %BaseColor
+OpStore %v %19
+OpBranch %20
+%20 = OpLabel
+%23 = OpLoad %v4float %v
+OpStore %gl_FragColor %23
+OpReturn
+OpFunctionEnd
+)";
+
+ SinglePassRunAndCheck<opt::DeadBranchElimPass>(
+ predefs_before + before, predefs_after + after, true, true);
+}
+
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// More complex control flow
// gl_FragColor = v;
// }
- const std::string predefs =
+ const std::string predefs_before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %BaseColor "BaseColor"
+OpName %gl_FragColor "gl_FragColor"
+%void = OpTypeVoid
+%7 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
const std::string before =
R"(%main = OpFunction %void None %7
%13 = OpLabel
const std::string after =
R"(%main = OpFunction %void None %7
%13 = OpLabel
-%v = OpVariable %_ptr_Function_v4float Function
%14 = OpLoad %v4float %BaseColor
OpStore %gl_FragColor %14
OpReturn
)";
SinglePassRunAndCheck<opt::LocalSingleBlockLoadStoreElimPass>(
- predefs + before, predefs + after, true, true);
+ predefs_before + before, predefs_after + after, true, true);
}
TEST_F(LocalSingleBlockLoadStoreElimTest, SimpleLoadLoadElim) {
// gl_FragColor = v/f;
// }
- const std::string predefs =
+ const std::string predefs_before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %Idx %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %v "v"
+OpName %BaseColor "BaseColor"
+OpName %Idx "Idx"
+OpName %gl_FragColor "gl_FragColor"
+OpDecorate %Idx Flat
+%void = OpTypeVoid
+%9 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%_ptr_Function_float = OpTypePointer Function %float
+%int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%Idx = OpVariable %_ptr_Input_int Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
const std::string before =
R"(%main = OpFunction %void None %9
%18 = OpLabel
R"(%main = OpFunction %void None %9
%18 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
-%f = OpVariable %_ptr_Function_float Function
%19 = OpLoad %v4float %BaseColor
OpStore %v %19
%20 = OpLoad %int %Idx
)";
SinglePassRunAndCheck<opt::LocalSingleBlockLoadStoreElimPass>(
- predefs + before, predefs + after, true, true);
+ predefs_before + before, predefs_after + after, true, true);
}
TEST_F(LocalSingleBlockLoadStoreElimTest, NoElimIfInterveningAccessChainStore) {
// gl_FragData[1] = v2;
// }
- const std::string predefs =
+ const std::string predefs_before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
%int_1 = OpConstant %int 1
)";
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %gl_FragData
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %BaseColor "BaseColor"
+OpName %gl_FragData "gl_FragData"
+%void = OpTypeVoid
+%8 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%_arr_v4float_uint_32 = OpTypeArray %v4float %uint_32
+%_ptr_Output__arr_v4float_uint_32 = OpTypePointer Output %_arr_v4float_uint_32
+%gl_FragData = OpVariable %_ptr_Output__arr_v4float_uint_32 Output
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%float_0_5 = OpConstant %float 0.5
+%int_1 = OpConstant %int 1
+)";
+
const std::string before =
R"(%main = OpFunction %void None %8
%22 = OpLabel
const std::string after =
R"(%main = OpFunction %void None %8
%22 = OpLabel
-%v1 = OpVariable %_ptr_Function_v4float Function
-%v2 = OpVariable %_ptr_Function_v4float Function
%23 = OpLoad %v4float %BaseColor
%25 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
OpStore %25 %23
)";
SinglePassRunAndCheck<opt::LocalSingleBlockLoadStoreElimPass>(
- predefs + before, predefs + after, true, true);
+ predefs_before + before, predefs_after + after, true, true);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
// gl_FragColor = v + f;
// }
- const std::string predefs =
+ const std::string predefs_before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %BaseColor "BaseColor"
+OpName %f "f"
+OpName %fi "fi"
+OpName %gl_FragColor "gl_FragColor"
+%void = OpTypeVoid
+%9 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%_ptr_Function_float = OpTypePointer Function %float
+%_ptr_Input_float = OpTypePointer Input %float
+%fi = OpVariable %_ptr_Input_float Input
+%float_0 = OpConstant %float 0
+%bool = OpTypeBool
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
const std::string before =
R"(%main = OpFunction %void None %9
%19 = OpLabel
const std::string after =
R"(%main = OpFunction %void None %9
%19 = OpLabel
-%v = OpVariable %_ptr_Function_v4float Function
%f = OpVariable %_ptr_Function_float Function
%20 = OpLoad %v4float %BaseColor
%21 = OpLoad %float %fi
)";
SinglePassRunAndCheck<opt::LocalSingleStoreElimPass>(
- predefs + before, predefs + after, true, true);
+ predefs_before + before,
+ predefs_after + after, true, true);
}
TEST_F(LocalSingleStoreElimTest, MultipleLoads) {
// gl_FragColor = v + f;
// }
- const std::string predefs =
+ const std::string predefs_before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %BaseColor "BaseColor"
+OpName %fi "fi"
+OpName %r "r"
+OpName %gl_FragColor "gl_FragColor"
+%void = OpTypeVoid
+%9 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%_ptr_Input_float = OpTypePointer Input %float
+%fi = OpVariable %_ptr_Input_float Input
+%float_0 = OpConstant %float 0
+%bool = OpTypeBool
+%float_1 = OpConstant %float 1
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
const std::string before =
R"(%main = OpFunction %void None %9
%19 = OpLabel
const std::string after =
R"(%main = OpFunction %void None %9
%19 = OpLabel
-%v = OpVariable %_ptr_Function_v4float Function
%r = OpVariable %_ptr_Function_v4float Function
%20 = OpLoad %v4float %BaseColor
%21 = OpLoad %float %fi
)";
SinglePassRunAndCheck<opt::LocalSingleStoreElimPass>(
- predefs + before, predefs + after, true, true);
+ predefs_before + before,
+ predefs_after + after, true, true);
}
TEST_F(LocalSingleStoreElimTest, NoStoreElimWithInterveningAccessChainLoad) {
// gl_FragColor = v * f;
// }
- const std::string predefs =
+ const std::string predefs_before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %v "v"
+OpName %BaseColor "BaseColor"
+OpName %gl_FragColor "gl_FragColor"
+%void = OpTypeVoid
+%8 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%_ptr_Function_float = OpTypePointer Function %float
+%uint = OpTypeInt 32 0
+%uint_3 = OpConstant %uint 3
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
const std::string before =
R"(%main = OpFunction %void None %8
%17 = OpLabel
R"(%main = OpFunction %void None %8
%17 = OpLabel
%v = OpVariable %_ptr_Function_v4float Function
-%f = OpVariable %_ptr_Function_float Function
%18 = OpLoad %v4float %BaseColor
OpStore %v %18
%19 = OpAccessChain %_ptr_Function_float %v %uint_3
)";
SinglePassRunAndCheck<opt::LocalSingleStoreElimPass>(
- predefs + before, predefs + after, true, true);
+ predefs_before + before,
+ predefs_after + after, true, true);
}
TEST_F(LocalSingleStoreElimTest, NoReplaceOfDominatingPartialStore) {
// gl_FragColor = v + f;
// }
- const std::string predefs =
+ const std::string predefs_before =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
)";
+ const std::string predefs_after =
+ R"(OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor
+OpExecutionMode %main OriginUpperLeft
+OpSource GLSL 140
+OpName %main "main"
+OpName %BaseColor "BaseColor"
+OpName %f "f"
+OpName %fi "fi"
+OpName %gl_FragColor "gl_FragColor"
+%void = OpTypeVoid
+%9 = OpTypeFunction %void
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%BaseColor = OpVariable %_ptr_Input_v4float Input
+%_ptr_Function_float = OpTypePointer Function %float
+%_ptr_Input_float = OpTypePointer Input %float
+%fi = OpVariable %_ptr_Input_float Input
+%float_0 = OpConstant %float 0
+%bool = OpTypeBool
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%gl_FragColor = OpVariable %_ptr_Output_v4float Output
+)";
+
const std::string before =
R"(%main = OpFunction %void None %9
%19 = OpLabel
const std::string after =
R"(%main = OpFunction %void None %9
%19 = OpLabel
-%v = OpVariable %_ptr_Function_v4float Function
%f = OpVariable %_ptr_Function_float Function
%20 = OpLoad %v4float %BaseColor
%21 = OpLoad %float %fi
)";
SinglePassRunAndCheck<opt::LocalSingleStoreElimPass>(
- predefs + before, predefs + after, true, true);
+ predefs_before + before, predefs_after + after, true, true);
}
TEST_F(LocalSingleStoreElimTest, NoOptIfStoreNotDominating) {