ExtractInsert: Handle rudimentary CompositeConstruct and ConstantComposite This optimizes a single index extract whose composite value terminates with a CompositeConstruct (or ConstantComposite) by evaluating to the correct component. This was needed for opaque legalization. This highlights the need/opportunity to improve this optimization to deal with more complex composite expressions including currently handled ops plus Null ops and special vector composition. A TODO has been added.
diff --git a/source/opt/insert_extract_elim.cpp b/source/opt/insert_extract_elim.cpp index c543644..4ccaac7 100644 --- a/source/opt/insert_extract_elim.cpp +++ b/source/opt/insert_extract_elim.cpp
@@ -55,6 +55,11 @@ return true; } +bool InsertExtractElimPass::IsVectorType(uint32_t typeId) { + ir::Instruction* typeInst = def_use_mgr_->GetDef(typeId); + return typeInst->opcode() == SpvOpTypeVector; +} + bool InsertExtractElimPass::EliminateInsertExtract(ir::Function* func) { bool modified = false; for (auto bi = func->begin(); bi != func->end(); ++bi) { @@ -74,6 +79,33 @@ cid = cinst->GetSingleWordInOperand(kInsertCompositeIdInIdx); cinst = def_use_mgr_->GetDef(cid); } + // If search ended with CompositeConstruct or ConstantComposite + // and the extract has one index, return the appropriate component. + // If a vector CompositeConstruct we make sure all preceding + // components are of component type (not vector composition). + // TODO(greg-lunarg): Handle multiple-indices, ConstantNull, special + // vector composition, and additional CompositeInsert. + if ((cinst->opcode() == SpvOpCompositeConstruct || + cinst->opcode() == SpvOpConstantComposite) && + (*ii).NumInOperands() == 2) { + uint32_t compIdx = (*ii).GetSingleWordInOperand(1); + if (IsVectorType(cinst->type_id())) { + if (compIdx < cinst->NumInOperands()) { + uint32_t i = 0; + for (; i <= compIdx; i++) { + uint32_t compId = cinst->GetSingleWordInOperand(i); + ir::Instruction* compInst = def_use_mgr_->GetDef(compId); + if (compInst->type_id() != (*ii).type_id()) + break; + } + if (i > compIdx) + replId = cinst->GetSingleWordInOperand(compIdx); + } + } + else { + replId = cinst->GetSingleWordInOperand(compIdx); + } + } if (replId != 0) { const uint32_t extId = ii->result_id(); (void)def_use_mgr_->ReplaceAllUsesWith(extId, replId);
diff --git a/source/opt/insert_extract_elim.h b/source/opt/insert_extract_elim.h index 52213db..cf3be23 100644 --- a/source/opt/insert_extract_elim.h +++ b/source/opt/insert_extract_elim.h
@@ -52,6 +52,9 @@ bool ExtInsConflict( const ir::Instruction* extInst, const ir::Instruction* insInst) const; + // Return true if |typeId| is a vector type + bool IsVectorType(uint32_t typeId); + // Look for OpExtract on sequence of OpInserts in |func|. If there is an // insert with identical indices, replace the extract with the value // that is inserted if possible. Specifically, replace if there is no