forked from KhronosGroup/SPIRV-Tools
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
We are no able to inline OpKill instructions into a continue construct. See KhronosGroup#2433. However, we have to be able to inline to correctly do legalization. This commit creates a pass that will wrap OpKill instructions into a function of its own. That way we are able to inline the rest of the code. The follow up to this will be to not inline any function that contains an OpKill. Fixes KhronosGroup#2726
- Loading branch information
Showing
14 changed files
with
443 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// Copyright (c) 2019 Google LLC | ||
// | ||
// 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 "source/opt/wrap_opkill.h" | ||
|
||
#include "ir_builder.h" | ||
|
||
namespace spvtools { | ||
namespace opt { | ||
|
||
Pass::Status WrapOpKill::Process() { | ||
bool modified = false; | ||
|
||
for (auto& func : *get_module()) { | ||
func.ForEachInst([this, &modified](Instruction* inst) { | ||
if (inst->opcode() == SpvOpKill) { | ||
modified = true; | ||
ReplaceWithFunctionCall(inst); | ||
} | ||
}); | ||
} | ||
|
||
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); | ||
} | ||
|
||
void WrapOpKill::ReplaceWithFunctionCall(Instruction* inst) { | ||
assert(inst->opcode() == SpvOpKill && | ||
"|inst| must be an OpKill instruction."); | ||
InstructionBuilder ir_builder( | ||
context(), inst, | ||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); | ||
ir_builder.AddFunctionCall(GetVoidTypeId(), GetOpKillFuncId(), {}); | ||
ir_builder.AddUnreachable(); | ||
context()->KillInst(inst); | ||
} | ||
|
||
uint32_t WrapOpKill::GetVoidTypeId() { | ||
if (void_type_id_ != 0) { | ||
return void_type_id_; | ||
} | ||
|
||
analysis::TypeManager* type_mgr = context()->get_type_mgr(); | ||
analysis::Void void_type; | ||
void_type_id_ = type_mgr->GetTypeInstruction(&void_type); | ||
return void_type_id_; | ||
} | ||
|
||
uint32_t WrapOpKill::GetVoidFunctionTypeId() { | ||
analysis::TypeManager* type_mgr = context()->get_type_mgr(); | ||
analysis::Void void_type; | ||
const analysis::Type* registered_void_type = | ||
type_mgr->GetRegisteredType(&void_type); | ||
|
||
analysis::Function func_type(registered_void_type, {}); | ||
return type_mgr->GetTypeInstruction(&func_type); | ||
} | ||
|
||
uint32_t WrapOpKill::GetOpKillFuncId() { | ||
if (opkill_func_id_ != 0) { | ||
return opkill_func_id_; | ||
} | ||
|
||
opkill_func_id_ = TakeNextId(); | ||
|
||
// Generate the function start instruction | ||
std::unique_ptr<Instruction> func_start(new Instruction( | ||
context(), SpvOpFunction, GetVoidTypeId(), opkill_func_id_, {})); | ||
func_start->AddOperand({SPV_OPERAND_TYPE_FUNCTION_CONTROL, {0}}); | ||
func_start->AddOperand({SPV_OPERAND_TYPE_ID, {GetVoidFunctionTypeId()}}); | ||
std::unique_ptr<Function> opkill_function( | ||
new Function(std::move(func_start))); | ||
|
||
// Generate the function end instruction | ||
std::unique_ptr<Instruction> func_end( | ||
new Instruction(context(), SpvOpFunctionEnd, 0, 0, {})); | ||
opkill_function->SetFunctionEnd(std::move(func_end)); | ||
|
||
// Create the one basic block for the function. | ||
std::unique_ptr<Instruction> label_inst( | ||
new Instruction(context(), SpvOpLabel, 0, TakeNextId(), {})); | ||
std::unique_ptr<BasicBlock> bb(new BasicBlock(std::move(label_inst))); | ||
|
||
// Add the OpKill to the basic block | ||
std::unique_ptr<Instruction> kill_inst( | ||
new Instruction(context(), SpvOpKill, 0, 0, {})); | ||
bb->AddInstruction(std::move(kill_inst)); | ||
|
||
// Add the bb to the function | ||
opkill_function->AddBasicBlock(std::move(bb)); | ||
|
||
// Add the function to the module. | ||
auto func = opkill_function.get(); | ||
context()->AddFunction(std::move(opkill_function)); | ||
|
||
if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) { | ||
func->ForEachInst( | ||
[this](Instruction* inst) { context()->AnalyzeDefUse(inst); }); | ||
} | ||
|
||
if (context()->AreAnalysesValid(IRContext::kAnalysisInstrToBlockMapping)) { | ||
for (BasicBlock& basic_block : *func) { | ||
context()->set_instr_block(basic_block.GetLabelInst(), &basic_block); | ||
for (Instruction& inst : basic_block) { | ||
context()->set_instr_block(&inst, &basic_block); | ||
} | ||
} | ||
} | ||
|
||
return opkill_func_id_; | ||
} | ||
|
||
} // namespace opt | ||
} // namespace spvtools |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (c) 2019 Google LLC | ||
// | ||
// 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. | ||
|
||
#ifndef SOURCE_OPT_WRAP_OPKILL_H_ | ||
#define SOURCE_OPT_WRAP_OPKILL_H_ | ||
|
||
#include "source/opt/pass.h" | ||
|
||
namespace spvtools { | ||
namespace opt { | ||
|
||
// Documented in optimizer.hpp | ||
class WrapOpKill : public Pass { | ||
public: | ||
WrapOpKill() : opkill_func_id_(0), void_type_id_(0) {} | ||
|
||
const char* name() const override { return "wrap-opkill"; } | ||
|
||
Status Process() override; | ||
|
||
IRContext::Analysis GetPreservedAnalyses() override { | ||
return IRContext::kAnalysisDefUse | | ||
IRContext::kAnalysisInstrToBlockMapping | | ||
IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | | ||
IRContext::kAnalysisNameMap | IRContext::kAnalysisBuiltinVarId | | ||
IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisConstants | | ||
IRContext::kAnalysisTypes; | ||
} | ||
|
||
private: | ||
// Replaces the OpKill instruction |inst| with a function call to a function | ||
// that contains a single instruction, which is OpKill. An OpUnreachable | ||
// instruction will be placed after the function call. | ||
void ReplaceWithFunctionCall(Instruction* inst); | ||
|
||
// Returns the id of the void type. | ||
uint32_t GetVoidTypeId(); | ||
|
||
// Returns the id of the function type for a void function with no parameters. | ||
uint32_t GetVoidFunctionTypeId(); | ||
|
||
// Return the id of a function that has return type void, no no parameters, | ||
// and contains a single instruction, which is an OpKill. | ||
uint32_t GetOpKillFuncId(); | ||
|
||
// The id of the function whose body is a single OpKill instruction. If the | ||
// id is 0, then the function has not been generated yet. | ||
uint32_t opkill_func_id_; | ||
|
||
// The id of the void type. If its value is 0, then the void type has not | ||
// been found or created yet. | ||
uint32_t void_type_id_; | ||
}; | ||
|
||
} // namespace opt | ||
} // namespace spvtools | ||
|
||
#endif // SOURCE_OPT_WRAP_OPKILL_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.