mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-11 11:20:05 +00:00
d35a78db57
Fixes #4960 * Switches to using enum classes with an underlying type to avoid undefined behaviour
92 lines
3.5 KiB
C++
92 lines
3.5 KiB
C++
// Copyright (c) 2022 Advanced Micro Devices, 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 "fix_func_call_arguments.h"
|
|
|
|
#include "ir_builder.h"
|
|
|
|
using namespace spvtools;
|
|
using namespace opt;
|
|
|
|
bool FixFuncCallArgumentsPass::ModuleHasASingleFunction() {
|
|
auto funcsNum = get_module()->end() - get_module()->begin();
|
|
return funcsNum == 1;
|
|
}
|
|
|
|
Pass::Status FixFuncCallArgumentsPass::Process() {
|
|
bool modified = false;
|
|
if (ModuleHasASingleFunction()) return Status::SuccessWithoutChange;
|
|
for (auto& func : *get_module()) {
|
|
func.ForEachInst([this, &modified](Instruction* inst) {
|
|
if (inst->opcode() == spv::Op::OpFunctionCall) {
|
|
modified |= FixFuncCallArguments(inst);
|
|
}
|
|
});
|
|
}
|
|
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
|
|
}
|
|
|
|
bool FixFuncCallArgumentsPass::FixFuncCallArguments(
|
|
Instruction* func_call_inst) {
|
|
bool modified = false;
|
|
for (uint32_t i = 0; i < func_call_inst->NumInOperands(); ++i) {
|
|
Operand& op = func_call_inst->GetInOperand(i);
|
|
if (op.type != SPV_OPERAND_TYPE_ID) continue;
|
|
Instruction* operand_inst = get_def_use_mgr()->GetDef(op.AsId());
|
|
if (operand_inst->opcode() == spv::Op::OpAccessChain) {
|
|
uint32_t var_id =
|
|
ReplaceAccessChainFuncCallArguments(func_call_inst, operand_inst);
|
|
func_call_inst->SetInOperand(i, {var_id});
|
|
modified = true;
|
|
}
|
|
}
|
|
if (modified) {
|
|
context()->UpdateDefUse(func_call_inst);
|
|
}
|
|
return modified;
|
|
}
|
|
|
|
uint32_t FixFuncCallArgumentsPass::ReplaceAccessChainFuncCallArguments(
|
|
Instruction* func_call_inst, Instruction* operand_inst) {
|
|
InstructionBuilder builder(
|
|
context(), func_call_inst,
|
|
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
|
|
|
Instruction* next_insert_point = func_call_inst->NextNode();
|
|
// Get Variable insertion point
|
|
Function* func = context()->get_instr_block(func_call_inst)->GetParent();
|
|
Instruction* variable_insertion_point = &*(func->begin()->begin());
|
|
Instruction* op_ptr_type = get_def_use_mgr()->GetDef(operand_inst->type_id());
|
|
Instruction* op_type =
|
|
get_def_use_mgr()->GetDef(op_ptr_type->GetSingleWordInOperand(1));
|
|
uint32_t varType = context()->get_type_mgr()->FindPointerToType(
|
|
op_type->result_id(), spv::StorageClass::Function);
|
|
// Create new variable
|
|
builder.SetInsertPoint(variable_insertion_point);
|
|
Instruction* var =
|
|
builder.AddVariable(varType, uint32_t(spv::StorageClass::Function));
|
|
// Load access chain to the new variable before function call
|
|
builder.SetInsertPoint(func_call_inst);
|
|
|
|
uint32_t operand_id = operand_inst->result_id();
|
|
Instruction* load = builder.AddLoad(op_type->result_id(), operand_id);
|
|
builder.AddStore(var->result_id(), load->result_id());
|
|
// Load return value to the acesschain after function call
|
|
builder.SetInsertPoint(next_insert_point);
|
|
load = builder.AddLoad(op_type->result_id(), var->result_id());
|
|
builder.AddStore(operand_id, load->result_id());
|
|
|
|
return var->result_id();
|
|
}
|