mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-03 21:51:05 +00:00
bb7802b18c
This is the first step in replacing the std::vector of Instruction pointers to using and intrusive linked list. To this end, we created the InstructionList class. It inherites from the IntrusiveList class, but add the extra concept of ownership. An InstructionList owns the instruction that are in it. This is to be consistent with the current ownership rules where the vector owns the instruction that are in it. The other larger change is that the inst_ member of the BasicBlock class was changed to using the InstructionList class. Added test for the InsertBefore functions, and making sure that the InstructionList destructor will delete the elements that it contains. I've also add extra comments to explain ownership a little better.
123 lines
3.8 KiB
C++
123 lines
3.8 KiB
C++
// 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 "inline_opaque_pass.h"
|
|
|
|
namespace spvtools {
|
|
namespace opt {
|
|
|
|
namespace {
|
|
|
|
const uint32_t kTypePointerTypeIdInIdx = 1;
|
|
|
|
} // anonymous namespace
|
|
|
|
bool InlineOpaquePass::IsOpaqueType(uint32_t typeId) {
|
|
const ir::Instruction* typeInst = def_use_mgr_->GetDef(typeId);
|
|
switch (typeInst->opcode()) {
|
|
case SpvOpTypeSampler:
|
|
case SpvOpTypeImage:
|
|
case SpvOpTypeSampledImage:
|
|
return true;
|
|
case SpvOpTypePointer:
|
|
return IsOpaqueType(typeInst->GetSingleWordInOperand(
|
|
kTypePointerTypeIdInIdx));
|
|
default:
|
|
break;
|
|
}
|
|
// TODO(greg-lunarg): Handle arrays containing opaque type
|
|
if (typeInst->opcode() != SpvOpTypeStruct)
|
|
return false;
|
|
// Return true if any member is opaque
|
|
int ocnt = 0;
|
|
typeInst->ForEachInId([&ocnt,this](const uint32_t* tid) {
|
|
if (ocnt == 0 && IsOpaqueType(*tid)) ++ocnt;
|
|
});
|
|
return ocnt > 0;
|
|
}
|
|
|
|
bool InlineOpaquePass::HasOpaqueArgsOrReturn(const ir::Instruction* callInst) {
|
|
// Check return type
|
|
if (IsOpaqueType(callInst->type_id()))
|
|
return true;
|
|
// Check args
|
|
int icnt = 0;
|
|
int ocnt = 0;
|
|
callInst->ForEachInId([&icnt,&ocnt,this](const uint32_t *iid) {
|
|
if (icnt > 0) {
|
|
const ir::Instruction* argInst = def_use_mgr_->GetDef(*iid);
|
|
if (IsOpaqueType(argInst->type_id()))
|
|
++ocnt;
|
|
}
|
|
++icnt;
|
|
});
|
|
return ocnt > 0;
|
|
}
|
|
|
|
bool InlineOpaquePass::InlineOpaque(ir::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;
|
|
GenInlineCode(&newBlocks, &newVars, ii, bi);
|
|
// If call block is replaced with more than one block, point
|
|
// succeeding phis at new last block.
|
|
if (newBlocks.size() > 1)
|
|
UpdateSucceedingPhis(newBlocks);
|
|
// Replace old calling block with new block(s).
|
|
bi = bi.Erase();
|
|
bi = bi.InsertBefore(&newBlocks);
|
|
// Insert new function variables.
|
|
if (newVars.size() > 0) func->begin()->begin().InsertBefore(std::move(newVars));
|
|
// Restart inlining at beginning of calling block.
|
|
ii = bi->begin();
|
|
modified = true;
|
|
} else {
|
|
++ii;
|
|
}
|
|
}
|
|
}
|
|
return modified;
|
|
}
|
|
|
|
void InlineOpaquePass::Initialize(ir::Module* module) {
|
|
InitializeInline(module);
|
|
};
|
|
|
|
Pass::Status InlineOpaquePass::ProcessImpl() {
|
|
// Do opaque inlining on each function in entry point call tree
|
|
ProcessFunction pfn = [this](ir::Function* fp) {
|
|
return InlineOpaque(fp);
|
|
};
|
|
bool modified = ProcessEntryPointCallTree(pfn, module_);
|
|
FinalizeNextId(module_);
|
|
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
|
|
}
|
|
|
|
InlineOpaquePass::InlineOpaquePass() {}
|
|
|
|
Pass::Status InlineOpaquePass::Process(ir::Module* module) {
|
|
Initialize(module);
|
|
return ProcessImpl();
|
|
}
|
|
|
|
} // namespace opt
|
|
} // namespace spvtools
|