• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "inst_builder.h"
17 #include "phi_resolver.h"
18 #include "optimizer/code_generator/encode.h"
19 #include "compiler_logger.h"
20 #ifndef PANDA_TARGET_WINDOWS
21 #include "callconv.h"
22 #endif
23 
24 namespace ark::compiler {
25 
InstBuilder(Graph * graph,RuntimeInterface::MethodPtr method,CallInst * callerInst,uint32_t inliningDepth)26 InstBuilder::InstBuilder(Graph *graph, RuntimeInterface::MethodPtr method, CallInst *callerInst, uint32_t inliningDepth)
27     : graph_(graph),
28       runtime_(graph->GetRuntime()),
29       defs_(graph->GetLocalAllocator()->Adapter()),
30       method_(method),
31       vregsAndArgsCount_(graph->GetRuntime()->GetMethodRegistersCount(method) +
32                          graph->GetRuntime()->GetMethodTotalArgumentsCount(method)),
33       instructionsBuf_(GetGraph()->GetRuntime()->GetMethodCode(GetGraph()->GetMethod())),
34       callerInst_(callerInst),
35       inliningDepth_(inliningDepth),
36       classId_ {runtime_->GetClassIdForMethod(method_)}
37 {
38     noTypeMarker_ = GetGraph()->NewMarker();
39     visitedBlockMarker_ = GetGraph()->NewMarker();
40 
41     defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph->GetLocalAllocator()->Adapter()));
42     for (auto &v : defs_) {
43         v.resize(GetVRegsCount());
44     }
45 
46     for (auto bb : graph->GetBlocksRPO()) {
47         if (bb->IsCatchBegin()) {
48             for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
49                 auto catchPhi = GetGraph()->CreateInstCatchPhi(DataType::NO_TYPE, bb->GetGuestPc());
50                 catchPhi->SetMarker(GetNoTypeMarker());
51                 bb->AppendInst(catchPhi);
52                 COMPILER_LOG(DEBUG, IR_BUILDER)
53                     << "Creat catchphi " << catchPhi->GetId() << " for bb(" << bb->GetId() << ")";
54                 if (vreg == vregsAndArgsCount_) {
55                     catchPhi->SetIsAcc();
56                 } else if (vreg > vregsAndArgsCount_) {
57                     catchPhi->SetType(DataType::ANY);
58                 }
59             }
60         }
61     }
62 }
63 
InitEnv(BasicBlock * bb)64 void InstBuilder::InitEnv(BasicBlock *bb)
65 {
66     auto thisFunc = GetGraph()->FindParameter(0);
67     auto cp = GetGraph()->CreateInstLoadConstantPool(DataType::ANY, INVALID_PC, thisFunc);
68     bb->AppendInst(cp);
69 
70     auto lexEnv = GetGraph()->CreateInstLoadLexicalEnv(DataType::ANY, INVALID_PC, thisFunc);
71     bb->AppendInst(lexEnv);
72 
73     defs_[bb->GetId()][vregsAndArgsCount_ + 1 + THIS_FUNC_IDX] = thisFunc;
74     defs_[bb->GetId()][vregsAndArgsCount_ + 1 + CONST_POOL_IDX] = cp;
75     defs_[bb->GetId()][vregsAndArgsCount_ + 1 + LEX_ENV_IDX] = lexEnv;
76     COMPILER_LOG(DEBUG, IR_BUILDER) << "Init environment this_func = " << thisFunc->GetId()
77                                     << ", const_pool = " << cp->GetId() << ", lex_env = " << lexEnv->GetId();
78 }
79 
SetCurrentBlock(BasicBlock * bb)80 void InstBuilder::SetCurrentBlock(BasicBlock *bb)
81 {
82     if (GetGraph()->IsDynamicMethod() && !GetGraph()->IsBytecodeOptimizer() &&
83         currentBb_ != GetGraph()->GetStartBlock() && currentDefs_ != nullptr) {
84         ASSERT((*currentDefs_)[vregsAndArgsCount_ + 1 + THIS_FUNC_IDX] != nullptr);
85         ASSERT((*currentDefs_)[vregsAndArgsCount_ + 1 + CONST_POOL_IDX] != nullptr);
86         ASSERT((*currentDefs_)[vregsAndArgsCount_ + 1 + LEX_ENV_IDX] != nullptr);
87     }
88     currentBb_ = bb;
89     currentDefs_ = &defs_[bb->GetId()];
90 }
91 
92 /* static */
ConvertPbcType(panda_file::Type type)93 DataType::Type InstBuilder::ConvertPbcType(panda_file::Type type)
94 {
95     switch (type.GetId()) {
96         case panda_file::Type::TypeId::VOID:
97             return DataType::VOID;
98         case panda_file::Type::TypeId::U1:
99             return DataType::BOOL;
100         case panda_file::Type::TypeId::I8:
101             return DataType::INT8;
102         case panda_file::Type::TypeId::U8:
103             return DataType::UINT8;
104         case panda_file::Type::TypeId::I16:
105             return DataType::INT16;
106         case panda_file::Type::TypeId::U16:
107             return DataType::UINT16;
108         case panda_file::Type::TypeId::I32:
109             return DataType::INT32;
110         case panda_file::Type::TypeId::U32:
111             return DataType::UINT32;
112         case panda_file::Type::TypeId::I64:
113             return DataType::INT64;
114         case panda_file::Type::TypeId::U64:
115             return DataType::UINT64;
116         case panda_file::Type::TypeId::F32:
117             return DataType::FLOAT32;
118         case panda_file::Type::TypeId::F64:
119             return DataType::FLOAT64;
120         case panda_file::Type::TypeId::REFERENCE:
121             return DataType::REFERENCE;
122         case panda_file::Type::TypeId::TAGGED:
123         case panda_file::Type::TypeId::INVALID:
124         default:
125             UNREACHABLE();
126     }
127     UNREACHABLE();
128 }
129 
Prepare(bool isInlinedGraph)130 void InstBuilder::Prepare(bool isInlinedGraph)
131 {
132     SetCurrentBlock(GetGraph()->GetStartBlock());
133 #ifndef PANDA_TARGET_WINDOWS
134     GetGraph()->ResetParameterInfo();
135 #endif
136     // Create parameter for actual num args
137     if (!GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod() && !GetGraph()->GetMode().IsDynamicStub()) {
138         auto paramInst = GetGraph()->AddNewParameter(ParameterInst::DYNAMIC_NUM_ARGS);
139         paramInst->SetType(DataType::UINT32);
140         paramInst->SetLocationData(GetGraph()->GetDataForNativeParam(DataType::UINT32));
141     }
142     size_t argRefNum = 0;
143     if (GetRuntime()->GetMethodReturnType(GetMethod()) == DataType::REFERENCE) {
144         argRefNum = 1;
145     }
146     auto numArgs = GetRuntime()->GetMethodTotalArgumentsCount(GetMethod());
147     bool isStatic = GetRuntime()->IsMethodStatic(GetMethod());
148     // Create Parameter instructions for all arguments
149     for (size_t i = 0; i < numArgs; i++) {
150         auto paramInst = GetGraph()->AddNewParameter(i);
151         auto type = GetCurrentMethodArgumentType(i);
152         auto regNum = GetRuntime()->GetMethodRegistersCount(GetMethod()) + i;
153         ASSERT(!GetGraph()->IsBytecodeOptimizer() || regNum != INVALID_REG);
154 
155         paramInst->SetType(type);
156         // This parameter in virtual method is implicit, so skipped
157         if (type == DataType::REFERENCE && (isStatic || i > 0)) {
158             paramInst->SetArgRefNumber(argRefNum++);
159         }
160         SetParamSpillFill(GetGraph(), paramInst, numArgs, i, type);
161 
162         UpdateDefinition(regNum, paramInst);
163     }
164 
165     // We don't need to create SafePoint at the beginning of the callee graph
166     if (g_options.IsCompilerUseSafepoint() && !isInlinedGraph) {
167         GetGraph()->GetStartBlock()->AppendInst(CreateSafePoint(GetGraph()->GetStartBlock()));
168     }
169     methodProfile_ = GetRuntime()->GetMethodProfile(GetMethod(), !GetGraph()->IsAotMode());
170 }
171 
UpdateDefsForCatch()172 void InstBuilder::UpdateDefsForCatch()
173 {
174     Inst *catchPhi = currentBb_->GetFirstInst();
175     ASSERT(catchPhi != nullptr);
176     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
177         ASSERT(catchPhi->IsCatchPhi());
178         defs_[currentBb_->GetId()][vreg] = catchPhi;
179         catchPhi = catchPhi->GetNext();
180     }
181 }
182 
UpdateDefsForLoopHead()183 void InstBuilder::UpdateDefsForLoopHead()
184 {
185     // If current block is a loop header, then propagate all definitions from preheader's predecessors to
186     // current block.
187     ASSERT(currentBb_->GetLoop()->GetPreHeader());
188     auto predDefs = defs_[currentBb_->GetLoop()->GetPreHeader()->GetId()];
189     COMPILER_LOG(DEBUG, IR_BUILDER) << "basic block is loop header";
190     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
191         auto defInst = predDefs[vreg];
192         if (defInst != nullptr) {
193             auto phi = GetGraph()->CreateInstPhi();
194             if (vreg > vregsAndArgsCount_) {
195                 phi->SetType(DataType::ANY);
196             }
197             phi->SetMarker(GetNoTypeMarker());
198             phi->SetLinearNumber(vreg);
199             currentBb_->AppendPhi(phi);
200             (*currentDefs_)[vreg] = phi;
201             COMPILER_LOG(DEBUG, IR_BUILDER) << "create Phi(id=" << phi->GetId() << ") for r" << vreg
202                                             << "(def id=" << predDefs[vreg]->GetId() << ")";
203         }
204     }
205 }
206 
UpdateDefinition(size_t vreg,Inst * inst)207 void InstBuilder::UpdateDefinition(size_t vreg, Inst *inst)
208 {
209     ASSERT(vreg < currentDefs_->size());
210     COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from "
211                                     << ((*currentDefs_)[vreg] != nullptr
212                                             ? std::to_string((*currentDefs_)[vreg]->GetId())
213                                             : "null")
214                                     << " to " << inst->GetId();
215     (*currentDefs_)[vreg] = inst;
216 }
217 
UpdateDefinitionAcc(Inst * inst)218 void InstBuilder::UpdateDefinitionAcc(Inst *inst)
219 {
220     if (inst == nullptr) {
221         COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition";
222     } else {
223         COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from "
224                                         << ((*currentDefs_)[vregsAndArgsCount_] != nullptr
225                                                 ? std::to_string((*currentDefs_)[vregsAndArgsCount_]->GetId())
226                                                 : "null")
227                                         << " to " << inst->GetId();
228     }
229     (*currentDefs_)[vregsAndArgsCount_] = inst;
230 }
231 
UpdateDefinitionLexEnv(Inst * inst)232 void InstBuilder::UpdateDefinitionLexEnv(Inst *inst)
233 {
234     ASSERT(inst != nullptr);
235     ASSERT((*currentDefs_)[vregsAndArgsCount_ + 1 + LEX_ENV_IDX] != nullptr);
236     COMPILER_LOG(DEBUG, IR_BUILDER) << "update lexical environment from "
237                                     << std::to_string((*currentDefs_)[vregsAndArgsCount_ + 1 + LEX_ENV_IDX]->GetId())
238                                     << " to " << inst->GetId();
239     (*currentDefs_)[vregsAndArgsCount_ + 1 + LEX_ENV_IDX] = inst;
240 }
241 
GetDefinition(size_t vreg)242 Inst *InstBuilder::GetDefinition(size_t vreg)
243 {
244     ASSERT(vreg < currentDefs_->size());
245     ASSERT((*currentDefs_)[vreg] != nullptr);
246 
247     if (vreg >= currentDefs_->size() || (*currentDefs_)[vreg] == nullptr) {
248         failed_ = true;
249         COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg;
250         return nullptr;
251     }
252     return (*currentDefs_)[vreg];
253 }
254 
GetDefinitionAcc()255 Inst *InstBuilder::GetDefinitionAcc()
256 {
257     auto *accInst = (*currentDefs_)[vregsAndArgsCount_];
258     ASSERT(accInst != nullptr);
259 
260     if (accInst == nullptr) {
261         failed_ = true;
262         COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed";
263     }
264     return accInst;
265 }
266 
GetEnvDefinition(uint8_t envIdx)267 Inst *InstBuilder::GetEnvDefinition(uint8_t envIdx)
268 {
269     auto *inst = (*currentDefs_)[vregsAndArgsCount_ + 1 + envIdx];
270     ASSERT(inst != nullptr);
271 
272     if (inst == nullptr) {
273         failed_ = true;
274     }
275     return inst;
276 }
277 
FindOrCreate32BitConstant(uint32_t value)278 ConstantInst *InstBuilder::FindOrCreate32BitConstant(uint32_t value)
279 {
280     auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value);
281     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
282         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
283     }
284     return inst;
285 }
286 
FindOrCreateConstant(uint64_t value)287 ConstantInst *InstBuilder::FindOrCreateConstant(uint64_t value)
288 {
289     auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value);
290     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
291         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
292     }
293     return inst;
294 }
295 
FindOrCreateAnyConstant(DataType::Any value)296 ConstantInst *InstBuilder::FindOrCreateAnyConstant(DataType::Any value)
297 {
298     auto inst = GetGraph()->FindOrCreateConstant(value);
299     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
300         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value.Raw() << ", inst=" << inst->GetId();
301     }
302     return inst;
303 }
304 
FindOrCreateDoubleConstant(double value)305 ConstantInst *InstBuilder::FindOrCreateDoubleConstant(double value)
306 {
307     auto inst = GetGraph()->FindOrCreateConstant<double>(value);
308     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
309         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
310     }
311     return inst;
312 }
313 
FindOrCreateFloatConstant(float value)314 ConstantInst *InstBuilder::FindOrCreateFloatConstant(float value)
315 {
316     auto inst = GetGraph()->FindOrCreateConstant<float>(value);
317     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
318         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
319     }
320     return inst;
321 }
322 
UpdateDefsForPreds(size_t vreg,std::optional<Inst * > & value)323 bool InstBuilder::UpdateDefsForPreds(size_t vreg, std::optional<Inst *> &value)
324 {
325     for (auto predBb : currentBb_->GetPredsBlocks()) {
326         // When irreducible loop header is visited before it's back-edge, phi should be created,
327         // since we do not know if definitions are different at this point
328         if (!predBb->IsMarked(visitedBlockMarker_)) {
329             ASSERT(currentBb_->GetLoop()->IsIrreducible());
330             return true;
331         }
332         if (!value.has_value()) {
333             value = defs_[predBb->GetId()][vreg];
334         } else if (value.value() != defs_[predBb->GetId()][vreg]) {
335             return true;
336         }
337     }
338     return false;
339 }
340 
UpdateDefs()341 void InstBuilder::UpdateDefs()
342 {
343     currentBb_->SetMarker(visitedBlockMarker_);
344     if (currentBb_->IsCatchBegin()) {
345         UpdateDefsForCatch();
346     } else if (currentBb_->IsLoopHeader() && !currentBb_->GetLoop()->IsIrreducible()) {
347         UpdateDefsForLoopHead();
348     } else if (currentBb_->GetPredsBlocks().size() == 1) {
349         // Only one predecessor - simply copy all its definitions
350         auto &predDefs = defs_[currentBb_->GetPredsBlocks()[0]->GetId()];
351         std::copy(predDefs.begin(), predDefs.end(), currentDefs_->begin());
352     } else if (currentBb_->GetPredsBlocks().size() > 1) {
353         // If there are multiple predecessors, then add phi for each register that has different definitions
354         for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
355             std::optional<Inst *> value;
356             bool different = UpdateDefsForPreds(vreg, value);
357             if (different) {
358                 auto phi = GetGraph()->CreateInstPhi();
359                 phi->SetMarker(GetNoTypeMarker());
360                 phi->SetLinearNumber(vreg);
361                 currentBb_->AppendPhi(phi);
362                 (*currentDefs_)[vreg] = phi;
363                 COMPILER_LOG(DEBUG, IR_BUILDER) << "create Phi(id=" << phi->GetId() << ") for r" << vreg;
364             } else {
365                 (*currentDefs_)[vreg] = value.value();
366             }
367         }
368     }
369 }
370 
AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock * > & catchHandlers,const InstVector & defs,Inst * throwableInst)371 void InstBuilder::AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catchHandlers, const InstVector &defs,
372                                     Inst *throwableInst)
373 {
374     ASSERT(!catchHandlers.empty());
375     for (auto catchBb : catchHandlers) {
376         auto inst = catchBb->GetFirstInst();
377         while (!inst->IsCatchPhi()) {
378             inst = inst->GetNext();
379         }
380         ASSERT(inst != nullptr);
381         GetGraph()->AppendThrowableInst(throwableInst, catchBb);
382         for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++, inst = inst->GetNext()) {
383             ASSERT(inst->GetOpcode() == Opcode::CatchPhi);
384             auto catchPhi = inst->CastToCatchPhi();
385             if (catchPhi->IsAcc()) {
386                 ASSERT(vreg == vregsAndArgsCount_);
387                 continue;
388             }
389             auto inputInst = defs[vreg];
390             if (inputInst != nullptr && inputInst != catchPhi) {
391                 catchPhi->AppendInput(inputInst);
392                 catchPhi->AppendThrowableInst(throwableInst);
393             }
394         }
395     }
396 }
397 
SetParamSpillFill(Graph * graph,ParameterInst * paramInst,size_t numArgs,size_t i,DataType::Type type)398 void InstBuilder::SetParamSpillFill(Graph *graph, ParameterInst *paramInst, size_t numArgs, size_t i,
399                                     DataType::Type type)
400 {
401     if (graph->IsBytecodeOptimizer()) {
402         auto regSrc = static_cast<Register>(VIRTUAL_FRAME_SIZE - numArgs + i);
403         DataType::Type regType;
404         if (DataType::IsReference(type)) {
405             regType = DataType::REFERENCE;
406         } else if (DataType::Is64Bits(type, graph->GetArch())) {
407             regType = DataType::UINT64;
408         } else {
409             regType = DataType::UINT32;
410         }
411 
412         paramInst->SetLocationData({LocationType::REGISTER, LocationType::REGISTER, regSrc, regSrc, regType});
413     } else {
414 #ifndef PANDA_TARGET_WINDOWS
415         if (graph->IsDynamicMethod() && !graph->GetMode().IsDynamicStub()) {
416             ASSERT(type == DataType::ANY);
417             uint16_t slot = i + CallConvDynInfo::FIXED_SLOT_COUNT;
418             ASSERT(slot <= UINT8_MAX);
419             paramInst->SetLocationData(
420                 {LocationType::STACK_PARAMETER, LocationType::INVALID, slot, INVALID_REG, DataType::UINT64});
421         } else {
422             paramInst->SetLocationData(graph->GetDataForNativeParam(type));
423         }
424 #endif
425     }
426 }
427 
428 /// Set type of instruction, then recursively set type to its inputs.
SetTypeRec(Inst * inst,DataType::Type type)429 void InstBuilder::SetTypeRec(Inst *inst, DataType::Type type)
430 {
431     inst->SetType(type);
432     inst->ResetMarker(GetNoTypeMarker());
433     for (auto input : inst->GetInputs()) {
434         if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
435             SetTypeRec(input.GetInst(), type);
436         }
437     }
438 }
439 
440 /**
441  * Remove vreg from SaveState for the case
442  * BB 1
443  *   ....
444  * succs: [bb 2, bb 3]
445  *
446  * BB 2: preds: [bb 1]
447  *   89.i64  Sub                        v85, v88 -> (v119, v90)
448  *   90.f64  Cast                       v89 -> (v96, v92)
449  * succs: [bb 3]
450  *
451  * BB 3: preds: [bb 1, bb 2]
452  *   .....
453  *   119.     SaveState                  v105(vr0), v106(vr1), v94(vr4), v89(vr8), v0(vr10), v1(vr11) -> (v120)
454  *
455  * v89(vr8) used only in BB 2, so we need to remove its from "119.     SaveState"
456  */
457 /* static */
RemoveNotDominateInputs(SaveStateInst * saveState)458 void InstBuilder::RemoveNotDominateInputs(SaveStateInst *saveState)
459 {
460     size_t idx = 0;
461     size_t inputsCount = saveState->GetInputsCount();
462     while (idx < inputsCount) {
463         auto inputInst = saveState->GetInput(idx).GetInst();
464         // We can don't call IsDominate, if save_state and input_inst in one basic block.
465         // It's reduce number of IsDominate calls.
466         if (!inputInst->InSameBlockOrDominate(saveState)) {
467             saveState->RemoveInput(idx);
468             inputsCount--;
469         } else {
470             ASSERT(inputInst->GetBasicBlock() != saveState->GetBasicBlock() || inputInst->IsDominate(saveState));
471             idx++;
472         }
473     }
474 }
475 
476 // Remove dead Phi and set types to phi which have not type.
477 // Phi may not have type if all it users are pseudo instructions, like SaveState
FixType(PhiInst * inst,BasicBlock * bb)478 void InstBuilder::FixType(PhiInst *inst, BasicBlock *bb)
479 {
480     inst->ReserveInputs(bb->GetPredsBlocks().size());
481     for (auto &predBb : bb->GetPredsBlocks()) {
482         if (inst->GetLinearNumber() == INVALID_LINEAR_NUM) {
483             continue;
484         }
485         auto pred = defs_[predBb->GetId()][inst->GetLinearNumber()];
486         if (pred == nullptr) {
487             // If any input of phi instruction is not defined then we assume that phi is dead. DCE should
488             // remove it.
489             continue;
490         }
491         inst->AppendInput(pred);
492     }
493 }
494 
495 // Check all instructions that have no type and fix it. Type is got from instructions with known input types.
FixType(Inst * inst)496 void InstBuilder::FixType(Inst *inst)
497 {
498     if (inst->IsSaveState()) {
499         RemoveNotDominateInputs(static_cast<SaveStateInst *>(inst));
500         return;
501     }
502     auto inputIdx = 0;
503     for (auto input : inst->GetInputs()) {
504         if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
505             auto inputType = inst->GetInputType(inputIdx);
506             if (inputType != DataType::NO_TYPE) {
507                 SetTypeRec(input.GetInst(), inputType);
508             }
509         }
510         inputIdx++;
511     }
512 }
513 
514 /// Fix instructions that can't be fully completed in building process.
FixInstructions()515 void InstBuilder::FixInstructions()
516 {
517     for (auto bb : GetGraph()->GetBlocksRPO()) {
518         for (auto inst : bb->PhiInstsSafe()) {
519             FixType(inst->CastToPhi(), bb);
520         }
521     }
522 
523     for (auto bb : GetGraph()->GetBlocksRPO()) {
524         for (auto inst : bb->AllInsts()) {
525             FixType(inst);
526         }
527     }
528     // Resolve dead and inconsistent phi instructions
529     PhiResolver phiResolver(GetGraph());
530     phiResolver.Run();
531     ResolveConstants();
532 }
533 
CreateSaveState(Opcode opc,size_t pc)534 SaveStateInst *InstBuilder::CreateSaveState(Opcode opc, size_t pc)
535 {
536     ASSERT(opc == Opcode::SaveState || opc == Opcode::SafePoint || opc == Opcode::SaveStateOsr ||
537            opc == Opcode::SaveStateDeoptimize);
538     SaveStateInst *inst;
539     bool withoutNumericInputs = false;
540     auto liveVergsCount =
541         std::count_if(currentDefs_->begin(), currentDefs_->end(), [](Inst *p) { return p != nullptr; });
542     if (opc == Opcode::SaveState) {
543         inst = GetGraph()->CreateInstSaveState(pc, GetMethod(), callerInst_, inliningDepth_);
544     } else if (opc == Opcode::SaveStateOsr) {
545         inst = GetGraph()->CreateInstSaveStateOsr(pc, GetMethod(), callerInst_, inliningDepth_);
546     } else if (opc == Opcode::SafePoint) {
547         inst = GetGraph()->CreateInstSafePoint(pc, GetMethod(), callerInst_, inliningDepth_);
548         withoutNumericInputs = true;
549     } else {
550         inst = GetGraph()->CreateInstSaveStateDeoptimize(pc, GetMethod(), callerInst_, inliningDepth_);
551     }
552     if (GetGraph()->IsBytecodeOptimizer()) {
553         inst->ReserveInputs(0);
554         return inst;
555     }
556     inst->ReserveInputs(liveVergsCount);
557 
558     for (VirtualRegister::ValueType regIdx = 0; regIdx < vregsAndArgsCount_; ++regIdx) {
559         auto defInst = (*currentDefs_)[regIdx];
560         if (defInst != nullptr && (!withoutNumericInputs || !DataType::IsTypeNumeric(defInst->GetType()))) {
561             auto inputIdx = inst->AppendInput(defInst);
562             inst->SetVirtualRegister(inputIdx, VirtualRegister(regIdx, VRegType::VREG));
563         }
564     }
565     VirtualRegister::ValueType regIdx = vregsAndArgsCount_;
566     auto defInst = (*currentDefs_)[regIdx];
567     if (defInst != nullptr && (!withoutNumericInputs || !DataType::IsTypeNumeric(defInst->GetType()))) {
568         auto inputIdx = inst->AppendInput(defInst);
569         inst->SetVirtualRegister(inputIdx, VirtualRegister(regIdx, VRegType::ACC));
570     }
571     regIdx++;
572     if (GetGraph()->IsDynamicMethod() && !GetGraph()->IsBytecodeOptimizer() && (*currentDefs_)[regIdx] != nullptr) {
573         for (uint8_t envIdx = 0; envIdx < VRegInfo::ENV_COUNT; ++envIdx) {
574             auto inputIdx = inst->AppendInput(GetEnvDefinition(envIdx));
575             inst->SetVirtualRegister(inputIdx, VirtualRegister(regIdx++, VRegType(VRegType::ENV_BEGIN + envIdx)));
576         }
577         if (additionalDef_ != nullptr) {
578             inst->AppendBridge(additionalDef_);
579         }
580     }
581     return inst;
582 }
583 
CreateLoadAndInitClassGeneric(uint32_t classId,size_t pc)584 ClassInst *InstBuilder::CreateLoadAndInitClassGeneric(uint32_t classId, size_t pc)
585 {
586     auto classPtr = GetRuntime()->ResolveType(GetGraph()->GetMethod(), classId);
587     ClassInst *inst = nullptr;
588     if (classPtr == nullptr) {
589         ASSERT(!graph_->IsBytecodeOptimizer());
590         inst = graph_->CreateInstUnresolvedLoadAndInitClass(DataType::REFERENCE, pc, nullptr,
591                                                             TypeIdMixin {classId, GetGraph()->GetMethod()}, classPtr);
592         if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
593             GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), classId,
594                                                              UnresolvedTypesInterface::SlotKind::CLASS);
595         }
596     } else {
597         inst = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, nullptr,
598                                                   TypeIdMixin {classId, GetGraph()->GetMethod()}, classPtr);
599     }
600     return inst;
601 }
602 
GetCurrentMethodReturnType() const603 DataType::Type InstBuilder::GetCurrentMethodReturnType() const
604 {
605     return GetRuntime()->GetMethodReturnType(GetMethod());
606 }
607 
GetCurrentMethodArgumentType(size_t index) const608 DataType::Type InstBuilder::GetCurrentMethodArgumentType(size_t index) const
609 {
610     return GetRuntime()->GetMethodTotalArgumentType(GetMethod(), index);
611 }
612 
GetCurrentMethodArgumentsCount() const613 size_t InstBuilder::GetCurrentMethodArgumentsCount() const
614 {
615     return GetRuntime()->GetMethodTotalArgumentsCount(GetMethod());
616 }
617 
GetMethodReturnType(uintptr_t id) const618 DataType::Type InstBuilder::GetMethodReturnType(uintptr_t id) const
619 {
620     return GetRuntime()->GetMethodReturnType(GetMethod(), id);
621 }
622 
GetMethodArgumentType(uintptr_t id,size_t index) const623 DataType::Type InstBuilder::GetMethodArgumentType(uintptr_t id, size_t index) const
624 {
625     return GetRuntime()->GetMethodArgumentType(GetMethod(), id, index);
626 }
627 
GetMethodArgumentsCount(uintptr_t id) const628 size_t InstBuilder::GetMethodArgumentsCount(uintptr_t id) const
629 {
630     return GetRuntime()->GetMethodArgumentsCount(GetMethod(), id);
631 }
632 
GetPc(const uint8_t * instPtr) const633 size_t InstBuilder::GetPc(const uint8_t *instPtr) const
634 {
635     return instPtr - instructionsBuf_;
636 }
637 
ResolveConstants()638 void InstBuilder::ResolveConstants()
639 {
640     ConstantInst *currConst = GetGraph()->GetFirstConstInst();
641     while (currConst != nullptr) {
642         SplitConstant(currConst);
643         currConst = currConst->GetNextConst();
644     }
645 }
646 
SplitConstant(ConstantInst * constInst)647 void InstBuilder::SplitConstant(ConstantInst *constInst)
648 {
649     if (constInst->GetType() != DataType::INT64 || !constInst->HasUsers()) {
650         return;
651     }
652     auto users = constInst->GetUsers();
653     auto currIt = users.begin();
654     while (currIt != users.end()) {
655         auto user = (*currIt).GetInst();
656         DataType::Type type = user->GetInputType(currIt->GetIndex());
657         ++currIt;
658         if (type != DataType::FLOAT32 && type != DataType::FLOAT64) {
659             continue;
660         }
661         ConstantInst *newConst = nullptr;
662         if (type == DataType::FLOAT32) {
663             auto val = bit_cast<float>(static_cast<uint32_t>(constInst->GetIntValue()));
664             newConst = GetGraph()->FindOrCreateConstant(val);
665         } else {
666             auto val = bit_cast<double, uint64_t>(constInst->GetIntValue());
667             newConst = GetGraph()->FindOrCreateConstant(val);
668         }
669         user->ReplaceInput(constInst, newConst);
670     }
671 }
672 
SyncWithGraph()673 void InstBuilder::SyncWithGraph()
674 {
675     size_t idx = currentDefs_ - &defs_[0];
676     size_t size = defs_.size();
677     defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph_->GetLocalAllocator()->Adapter()));
678     for (size_t i = size; i < defs_.size(); i++) {
679         defs_[i].resize(vregsAndArgsCount_ + 1 + graph_->GetEnvCount());
680         std::copy(defs_[idx].cbegin(), defs_[idx].cend(), defs_[i].begin());
681     }
682     currentDefs_ = &defs_[currentBb_->GetId()];
683 }
684 
685 template <bool IS_STATIC>
IsInConstructor() const686 bool InstBuilder::IsInConstructor() const
687 {
688     for (auto graph = GetGraph(); graph != nullptr; graph = graph->GetParentGraph()) {
689         auto method = graph->GetMethod();
690         if (IS_STATIC ? GetRuntime()->IsMethodStaticConstructor(method) : GetRuntime()->IsInstanceConstructor(method)) {
691             return true;
692         }
693     }
694     return false;
695 }
696 template bool InstBuilder::IsInConstructor<true>() const;
697 template bool InstBuilder::IsInConstructor<false>() const;
698 
699 }  // namespace ark::compiler
700