• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
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 
16 #include "libabckit/src/irbuilder_dynamic/inst_builder_dyn.h"
17 #include "libabckit/src/irbuilder_dynamic/phi_resolver_dyn.h"
18 
19 namespace libabckit {
20 
21 // NOLINTNEXTLINE(google-build-using-namespace)
22 using namespace ark;
23 
Prepare()24 void InstBuilder::Prepare()
25 {
26     SetCurrentBlock(GetGraph()->GetStartBlock());
27 #ifndef PANDA_TARGET_WINDOWS
28     GetGraph()->ResetParameterInfo();
29 #endif
30     auto numArgs = GetRuntime()->GetMethodTotalArgumentsCount(GetMethod());
31     // Create Parameter instructions for all arguments
32     for (size_t i = 0; i < numArgs; i++) {
33         auto paramInst = GetGraph()->AddNewParameter(i);
34         auto type = compiler::DataType::Type::ANY;
35         auto regNum = GetRuntime()->GetMethodRegistersCount(GetMethod()) + i;
36         ASSERT(!GetGraph()->IsBytecodeOptimizer() || regNum != ark::compiler::GetInvalidReg());
37 
38         paramInst->SetType(type);
39         SetParamSpillFill(GetGraph(), paramInst, numArgs, i, type);
40 
41         UpdateDefinition(regNum, paramInst);
42     }
43 }
44 
UpdateDefsForCatch()45 void InstBuilder::UpdateDefsForCatch()
46 {
47     compiler::Inst *catchPhi = currentBb_->GetFirstInst();
48     ASSERT(catchPhi != nullptr);
49     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
50         ASSERT(catchPhi->IsCatchPhi());
51         defs_[currentBb_->GetId()][vreg] = catchPhi;
52         catchPhi = catchPhi->GetNext();
53     }
54 }
55 
UpdateDefsForLoopHead()56 void InstBuilder::UpdateDefsForLoopHead()
57 {
58     // If current block is a loop header, then propagate all definitions from preheader's predecessors to
59     // current block.
60     ASSERT(currentBb_->GetLoop()->GetPreHeader());
61     auto predDefs = defs_[currentBb_->GetLoop()->GetPreHeader()->GetId()];
62     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
63         auto defInst = predDefs[vreg];
64         if (defInst != nullptr) {
65             auto phi = GetGraph()->CreateInstPhi();
66             phi->SetMarker(GetNoTypeMarker());
67             phi->SetLinearNumber(vreg);
68             currentBb_->AppendPhi(phi);
69             (*currentDefs_)[vreg] = phi;
70         }
71     }
72 }
73 
AddPhiToDifferent()74 void InstBuilder::AddPhiToDifferent()
75 {
76     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
77         compiler::Inst *value = nullptr;
78         bool different = false;
79         for (auto predBb : currentBb_->GetPredsBlocks()) {
80             // When irreducible loop header is visited before it's back-edge, phi should be created,
81             // since we do not know if definitions are different at this point
82             if (!predBb->IsMarked(visitedBlockMarker_)) {
83                 ASSERT(currentBb_->GetLoop()->IsIrreducible());
84                 different = true;
85                 break;
86             }
87             if (value == nullptr) {
88                 value = defs_[predBb->GetId()][vreg];
89             } else if (value != defs_[predBb->GetId()][vreg]) {
90                 different = true;
91                 break;
92             }
93         }
94         if (different) {
95             auto phi = GetGraph()->CreateInstPhi();
96             phi->SetMarker(GetNoTypeMarker());
97             phi->SetLinearNumber(vreg);
98             currentBb_->AppendPhi(phi);
99             (*currentDefs_)[vreg] = phi;
100         } else {
101             (*currentDefs_)[vreg] = value;
102         }
103     }
104 }
105 
UpdateDefs()106 void InstBuilder::UpdateDefs()
107 {
108     currentBb_->SetMarker(visitedBlockMarker_);
109     if (currentBb_->IsCatchBegin()) {
110         UpdateDefsForCatch();
111     } else if (currentBb_->IsLoopHeader() && !currentBb_->GetLoop()->IsIrreducible()) {
112         UpdateDefsForLoopHead();
113     } else if (currentBb_->GetPredsBlocks().size() == 1) {
114         // Only one predecessor - simply copy all its definitions
115         auto &predDefs = defs_[currentBb_->GetPredsBlocks()[0]->GetId()];
116         std::copy(predDefs.begin(), predDefs.end(), currentDefs_->begin());
117     } else if (currentBb_->GetPredsBlocks().size() > 1) {
118         AddPhiToDifferent();
119     }
120 }
121 
AddCatchPhiInputs(const ArenaUnorderedSet<compiler::BasicBlock * > & catchHandlers,const compiler::InstVector & defs,compiler::Inst * throwableInst)122 void InstBuilder::AddCatchPhiInputs(const ArenaUnorderedSet<compiler::BasicBlock *> &catchHandlers,
123                                     const compiler::InstVector &defs, compiler::Inst *throwableInst)
124 {
125     ASSERT(!catchHandlers.empty());
126     for (auto catchBb : catchHandlers) {
127         auto inst = catchBb->GetFirstInst();
128         while (!inst->IsCatchPhi()) {
129             inst = inst->GetNext();
130         }
131         ASSERT(inst != nullptr);
132         GetGraph()->AppendThrowableInst(throwableInst, catchBb);
133         for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++, inst = inst->GetNext()) {
134             ASSERT(inst->GetOpcode() == ark::compiler::Opcode::CatchPhi);
135             auto catchPhi = inst->CastToCatchPhi();
136             if (catchPhi->IsAcc()) {
137                 ASSERT(vreg == vregsAndArgsCount_);
138                 continue;
139             }
140             auto inputInst = defs[vreg];
141             if (inputInst != nullptr && inputInst != catchPhi) {
142                 catchPhi->AppendInput(inputInst);
143                 catchPhi->AppendThrowableInst(throwableInst);
144             }
145         }
146     }
147 }
148 
SetParamSpillFill(compiler::Graph * graph,compiler::ParameterInst * paramInst,size_t numArgs,size_t i,compiler::DataType::Type type)149 void InstBuilder::SetParamSpillFill(compiler::Graph *graph, compiler::ParameterInst *paramInst, size_t numArgs,
150                                     size_t i, compiler::DataType::Type type)
151 {
152     if (graph->IsBytecodeOptimizer()) {
153         auto regSrc = static_cast<compiler::Register>(compiler::GetFrameSize() - numArgs + i);
154         compiler::DataType::Type regType;
155         if (compiler::DataType::IsReference(type)) {
156             regType = compiler::DataType::REFERENCE;
157         } else if (compiler::DataType::Is64Bits(type, graph->GetArch())) {
158             regType = compiler::DataType::UINT64;
159         } else {
160             regType = compiler::DataType::UINT32;
161         }
162 
163         paramInst->SetLocationData(
164             {compiler::LocationType::REGISTER, compiler::LocationType::REGISTER, regSrc, regSrc, regType});
165     }
166 }
167 
168 /**
169  * Set type of instruction, then recursively set type to its inputs.
170  */
SetTypeRec(compiler::Inst * inst,compiler::DataType::Type type)171 void InstBuilder::SetTypeRec(compiler::Inst *inst, compiler::DataType::Type type)
172 {
173     inst->SetType(type);
174     inst->ResetMarker(GetNoTypeMarker());
175     for (auto input : inst->GetInputs()) {
176         if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
177             SetTypeRec(input.GetInst(), type);
178         }
179     }
180 }
181 
182 // CC-OFFNXT(WordsTool.190) sensitive word conflict
183 /**
184  * Remove vreg from SaveState for the case
185  * BB 1
186  *   ....
187  * succs: [bb 2, bb 3]
188  *
189  * BB 2: preds: [bb 1]
190  *   89.i64  Sub                        v85, v88 -> (v119, v90)
191  *   90.f64  Cast                       v89 -> (v96, v92)
192  * succs: [bb 3]
193  *
194  * BB 3: preds: [bb 1, bb 2]
195  *   .....
196  *   119.     SaveState                  v105(vr0), v106(vr1), v94(vr4), v89(vr8), v0(vr10), v1(vr11) -> (v120)
197  *
198  * v89(vr8) used only in BB 2, so we need to remove its from "119.     SaveState"
199  */
200 /* static */
RemoveNotDominateInputs(compiler::SaveStateInst * saveState)201 void InstBuilder::RemoveNotDominateInputs(compiler::SaveStateInst *saveState)
202 {
203     size_t idx = 0;
204     size_t inputsCount = saveState->GetInputsCount();
205     while (idx < inputsCount) {
206         auto inputInst = saveState->GetInput(idx).GetInst();
207         // We can don't call IsDominate, if save_state and input_inst in one basic block.
208         // It's reduce number of IsDominate calls.
209         if (!inputInst->InSameBlockOrDominate(saveState)) {
210             saveState->RemoveInput(idx);
211             inputsCount--;
212         } else {
213             ASSERT(inputInst->GetBasicBlock() != saveState->GetBasicBlock() || inputInst->IsDominate(saveState));
214             idx++;
215         }
216     }
217 }
218 
UpdatePreds(compiler::BasicBlock * bb,compiler::Inst * inst)219 void InstBuilder::UpdatePreds(compiler::BasicBlock *bb, compiler::Inst *inst)
220 {
221     inst->ReserveInputs(bb->GetPredsBlocks().size());
222     for (auto &predBb : bb->GetPredsBlocks()) {
223         if (inst->GetLinearNumber() == compiler::INVALID_LINEAR_NUM) {
224             continue;
225         }
226         auto pred = defs_[predBb->GetId()][inst->GetLinearNumber()];
227         if (pred == nullptr) {
228             // If any input of phi instruction is not defined then we assume that phi is dead. DCE should
229             // remove it.
230             continue;
231         }
232         inst->AppendInput(pred);
233     }
234 }
235 
SetType(compiler::Inst * inst)236 void InstBuilder::SetType(compiler::Inst *inst)
237 {
238     if (inst->IsSaveState()) {
239         RemoveNotDominateInputs(static_cast<compiler::SaveStateInst *>(inst));
240         return;
241     }
242     auto inputIdx = 0;
243     for (auto input : inst->GetInputs()) {
244         if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
245             auto inputType = inst->GetInputType(inputIdx);
246             if (inputType != compiler::DataType::NO_TYPE) {
247                 SetTypeRec(input.GetInst(), inputType);
248             }
249         }
250         inputIdx++;
251     }
252 }
253 
254 /**
255  * Fix instructions that can't be fully completed in building process.
256  */
FixInstructions()257 void InstBuilder::FixInstructions()
258 {
259     // Remove dead Phi and set types to phi which have not type.
260     // Phi may not have type if all it users are pseudo instructions, like SaveState
261     for (auto bb : GetGraph()->GetBlocksRPO()) {
262         for (auto inst : bb->PhiInstsSafe()) {
263             UpdatePreds(bb, inst);
264         }
265     }
266 
267     // Check all instructions that have no type and fix it. Type is got from instructions with known input types.
268     for (auto bb : GetGraph()->GetBlocksRPO()) {
269         for (auto inst : bb->AllInsts()) {
270             SetType(inst);
271         }
272     }
273     // Resolve dead and inconsistent phi instructions
274     PhiResolver phiResolver(GetGraph());
275     phiResolver.Run();
276     ResolveConstants();
277     CleanupCatchPhis();
278 }
279 
CreateSaveState(compiler::Opcode opc,size_t pc)280 compiler::SaveStateInst *InstBuilder::CreateSaveState([[maybe_unused]] compiler::Opcode opc, size_t pc)
281 {
282     ASSERT(opc == ark::compiler::Opcode::SaveState);
283     compiler::SaveStateInst *inst = GetGraph()->CreateInstSaveState();
284     inst->SetPc(pc);
285     inst->SetMethod(GetMethod());
286     inst->ReserveInputs(0);
287     return inst;
288 }
289 
GetMethodArgumentsCount(uintptr_t id) const290 size_t InstBuilder::GetMethodArgumentsCount(uintptr_t id) const
291 {
292     return GetRuntime()->GetMethodArgumentsCount(GetMethod(), id);
293 }
294 
GetPc(const uint8_t * instPtr) const295 size_t InstBuilder::GetPc(const uint8_t *instPtr) const
296 {
297     return instPtr - instructionsBuf_;
298 }
299 
ResolveConstants()300 void InstBuilder::ResolveConstants()
301 {
302     compiler::ConstantInst *currConst = GetGraph()->GetFirstConstInst();
303     while (currConst != nullptr) {
304         SplitConstant(currConst);
305         currConst = currConst->GetNextConst();
306     }
307 }
308 
SplitConstant(compiler::ConstantInst * constInst)309 void InstBuilder::SplitConstant(compiler::ConstantInst *constInst)
310 {
311     if (constInst->GetType() != compiler::DataType::INT64 || !constInst->HasUsers()) {
312         return;
313     }
314     auto users = constInst->GetUsers();
315     auto currIt = users.begin();
316     while (currIt != users.end()) {
317         auto user = (*currIt).GetInst();
318         compiler::DataType::Type type = user->GetInputType(currIt->GetIndex());
319         ++currIt;
320         if (type != compiler::DataType::FLOAT32 && type != compiler::DataType::FLOAT64) {
321             continue;
322         }
323         compiler::ConstantInst *newConst = nullptr;
324         if (type == compiler::DataType::FLOAT32) {
325             auto val = bit_cast<float>(static_cast<uint32_t>(constInst->GetIntValue()));
326             newConst = GetGraph()->FindOrCreateConstant(val);
327         } else {
328             auto val = bit_cast<double, uint64_t>(constInst->GetIntValue());
329             newConst = GetGraph()->FindOrCreateConstant(val);
330         }
331         user->ReplaceInput(constInst, newConst);
332     }
333 }
334 
CleanupInst(compiler::BasicBlock * block,compiler::Inst * inst)335 void InstBuilder::CleanupInst(compiler::BasicBlock *block, compiler::Inst *inst)
336 {
337     if (!inst->IsCatchPhi() || inst->GetInputs().Empty()) {
338         return;
339     }
340     // Remove catch-phis without real users
341     bool hasSsUsersOnly = true;
342     for (const auto &user : inst->GetUsers()) {
343         if (!user.GetInst()->IsSaveState()) {
344             hasSsUsersOnly = false;
345             break;
346         }
347     }
348     if (hasSsUsersOnly) {
349         auto users = inst->GetUsers();
350         while (!users.Empty()) {
351             auto &user = users.Front();
352             user.GetInst()->RemoveInput(user.GetIndex());
353         }
354         block->RemoveInst(inst);
355     }
356 }
357 
CleanupCatchPhis()358 void InstBuilder::CleanupCatchPhis()
359 {
360     for (auto block : GetGraph()->GetBlocksRPO()) {
361         for (auto inst : block->AllInstsSafe()) {
362             CleanupInst(block, inst);
363         }
364     }
365 }
366 
367 }  // namespace libabckit
368