• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022 Advanced Micro Devices, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "fix_func_call_arguments.h"
16 
17 #include "ir_builder.h"
18 
19 using namespace spvtools;
20 using namespace opt;
21 
ModuleHasASingleFunction()22 bool FixFuncCallArgumentsPass::ModuleHasASingleFunction() {
23   auto funcsNum = get_module()->end() - get_module()->begin();
24   return funcsNum == 1;
25 }
26 
Process()27 Pass::Status FixFuncCallArgumentsPass::Process() {
28   bool modified = false;
29   if (ModuleHasASingleFunction()) return Status::SuccessWithoutChange;
30   for (auto& func : *get_module()) {
31     func.ForEachInst([this, &modified](Instruction* inst) {
32       if (inst->opcode() == SpvOpFunctionCall) {
33         modified |= FixFuncCallArguments(inst);
34       }
35     });
36   }
37   return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
38 }
39 
FixFuncCallArguments(Instruction * func_call_inst)40 bool FixFuncCallArgumentsPass::FixFuncCallArguments(
41     Instruction* func_call_inst) {
42   bool modified = false;
43   for (uint32_t i = 0; i < func_call_inst->NumInOperands(); ++i) {
44     Operand& op = func_call_inst->GetInOperand(i);
45     if (op.type != SPV_OPERAND_TYPE_ID) continue;
46     Instruction* operand_inst = get_def_use_mgr()->GetDef(op.AsId());
47     if (operand_inst->opcode() == SpvOpAccessChain) {
48       uint32_t var_id =
49           ReplaceAccessChainFuncCallArguments(func_call_inst, operand_inst);
50       func_call_inst->SetInOperand(i, {var_id});
51       modified = true;
52     }
53   }
54   if (modified) {
55     context()->UpdateDefUse(func_call_inst);
56   }
57   return modified;
58 }
59 
ReplaceAccessChainFuncCallArguments(Instruction * func_call_inst,Instruction * operand_inst)60 uint32_t FixFuncCallArgumentsPass::ReplaceAccessChainFuncCallArguments(
61     Instruction* func_call_inst, Instruction* operand_inst) {
62   InstructionBuilder builder(
63       context(), func_call_inst,
64       IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
65 
66   Instruction* next_insert_point = func_call_inst->NextNode();
67   // Get Variable insertion point
68   Function* func = context()->get_instr_block(func_call_inst)->GetParent();
69   Instruction* variable_insertion_point = &*(func->begin()->begin());
70   Instruction* op_ptr_type = get_def_use_mgr()->GetDef(operand_inst->type_id());
71   Instruction* op_type =
72       get_def_use_mgr()->GetDef(op_ptr_type->GetSingleWordInOperand(1));
73   uint32_t varType = context()->get_type_mgr()->FindPointerToType(
74       op_type->result_id(), SpvStorageClassFunction);
75   // Create new variable
76   builder.SetInsertPoint(variable_insertion_point);
77   Instruction* var = builder.AddVariable(varType, SpvStorageClassFunction);
78   // Load access chain to the new variable before function call
79   builder.SetInsertPoint(func_call_inst);
80 
81   uint32_t operand_id = operand_inst->result_id();
82   Instruction* load = builder.AddLoad(op_type->result_id(), operand_id);
83   builder.AddStore(var->result_id(), load->result_id());
84   // Load return value to the acesschain after function call
85   builder.SetInsertPoint(next_insert_point);
86   load = builder.AddLoad(op_type->result_id(), var->result_id());
87   builder.AddStore(operand_id, load->result_id());
88 
89   return var->result_id();
90 }
91