• 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         if (GetGraph()->IsAbcKit()) {
152             paramInst->SetFlag(inst_flags::NO_DCE);
153         }
154         auto type = GetCurrentMethodArgumentType(i);
155         auto regNum = GetRuntime()->GetMethodRegistersCount(GetMethod()) + i;
156         ASSERT(!GetGraph()->IsBytecodeOptimizer() || regNum != GetInvalidReg());
157 
158         paramInst->SetType(type);
159         // This parameter in virtual method is implicit, so skipped
160         if (type == DataType::REFERENCE && (isStatic || i > 0)) {
161             paramInst->SetArgRefNumber(argRefNum++);
162         }
163         SetParamSpillFill(GetGraph(), paramInst, numArgs, i, type);
164 
165         UpdateDefinition(regNum, paramInst);
166     }
167 
168     // We don't need to create SafePoint at the beginning of the callee graph
169     if (g_options.IsCompilerUseSafepoint() && !isInlinedGraph) {
170         GetGraph()->GetStartBlock()->AppendInst(CreateSafePoint(GetGraph()->GetStartBlock()));
171     }
172     methodProfile_ = GetRuntime()->GetMethodProfile(GetMethod(), !GetGraph()->IsAotMode());
173 }
174 
UpdateDefsForCatch()175 void InstBuilder::UpdateDefsForCatch()
176 {
177     Inst *catchPhi = currentBb_->GetFirstInst();
178     ASSERT(catchPhi != nullptr);
179     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
180         ASSERT(catchPhi->IsCatchPhi());
181         defs_[currentBb_->GetId()][vreg] = catchPhi;
182         catchPhi = catchPhi->GetNext();
183     }
184 }
185 
UpdateDefsForLoopHead()186 void InstBuilder::UpdateDefsForLoopHead()
187 {
188     // If current block is a loop header, then propagate all definitions from preheader's predecessors to
189     // current block.
190     ASSERT(currentBb_->GetLoop()->GetPreHeader());
191     auto predDefs = defs_[currentBb_->GetLoop()->GetPreHeader()->GetId()];
192     COMPILER_LOG(DEBUG, IR_BUILDER) << "basic block is loop header";
193     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
194         auto defInst = predDefs[vreg];
195         if (defInst != nullptr) {
196             auto phi = GetGraph()->CreateInstPhi();
197             if (vreg > vregsAndArgsCount_) {
198                 phi->SetType(DataType::ANY);
199             }
200             phi->SetMarker(GetNoTypeMarker());
201             phi->SetLinearNumber(vreg);
202             currentBb_->AppendPhi(phi);
203             (*currentDefs_)[vreg] = phi;
204             COMPILER_LOG(DEBUG, IR_BUILDER) << "create Phi(id=" << phi->GetId() << ") for r" << vreg
205                                             << "(def id=" << predDefs[vreg]->GetId() << ")";
206         }
207     }
208 }
209 
UpdateDefinition(size_t vreg,Inst * inst)210 void InstBuilder::UpdateDefinition(size_t vreg, Inst *inst)
211 {
212     ASSERT(vreg < currentDefs_->size());
213     COMPILER_LOG(DEBUG, IR_BUILDER) << "update def for r" << vreg << " from "
214                                     << ((*currentDefs_)[vreg] != nullptr
215                                             ? std::to_string((*currentDefs_)[vreg]->GetId())
216                                             : "null")
217                                     << " to " << inst->GetId();
218     (*currentDefs_)[vreg] = inst;
219 }
220 
UpdateDefinitionAcc(Inst * inst)221 void InstBuilder::UpdateDefinitionAcc(Inst *inst)
222 {
223     if (inst == nullptr) {
224         COMPILER_LOG(DEBUG, IR_BUILDER) << "reset accumulator definition";
225     } else {
226         COMPILER_LOG(DEBUG, IR_BUILDER) << "update accumulator from "
227                                         << ((*currentDefs_)[vregsAndArgsCount_] != nullptr
228                                                 ? std::to_string((*currentDefs_)[vregsAndArgsCount_]->GetId())
229                                                 : "null")
230                                         << " to " << inst->GetId();
231     }
232     (*currentDefs_)[vregsAndArgsCount_] = inst;
233 }
234 
UpdateDefinitionLexEnv(Inst * inst)235 void InstBuilder::UpdateDefinitionLexEnv(Inst *inst)
236 {
237     ASSERT(inst != nullptr);
238     ASSERT((*currentDefs_)[vregsAndArgsCount_ + 1 + LEX_ENV_IDX] != nullptr);
239     COMPILER_LOG(DEBUG, IR_BUILDER) << "update lexical environment from "
240                                     << std::to_string((*currentDefs_)[vregsAndArgsCount_ + 1 + LEX_ENV_IDX]->GetId())
241                                     << " to " << inst->GetId();
242     (*currentDefs_)[vregsAndArgsCount_ + 1 + LEX_ENV_IDX] = inst;
243 }
244 
GetDefinition(size_t vreg)245 Inst *InstBuilder::GetDefinition(size_t vreg)
246 {
247     ASSERT(vreg < currentDefs_->size());
248     ASSERT((*currentDefs_)[vreg] != nullptr);
249 
250     if (vreg >= currentDefs_->size() || (*currentDefs_)[vreg] == nullptr) {
251         failed_ = true;
252         COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinition failed for verg " << vreg;
253         return nullptr;
254     }
255     return (*currentDefs_)[vreg];
256 }
257 
GetDefinitionAcc()258 Inst *InstBuilder::GetDefinitionAcc()
259 {
260     auto *accInst = (*currentDefs_)[vregsAndArgsCount_];
261     ASSERT(accInst != nullptr);
262 
263     if (accInst == nullptr) {
264         failed_ = true;
265         COMPILER_LOG(ERROR, IR_BUILDER) << "GetDefinitionAcc failed";
266     }
267     return accInst;
268 }
269 
GetEnvDefinition(uint8_t envIdx)270 Inst *InstBuilder::GetEnvDefinition(uint8_t envIdx)
271 {
272     auto *inst = (*currentDefs_)[vregsAndArgsCount_ + 1 + envIdx];
273     ASSERT(inst != nullptr);
274 
275     if (inst == nullptr) {
276         failed_ = true;
277     }
278     return inst;
279 }
280 
FindOrCreate32BitConstant(uint32_t value)281 ConstantInst *InstBuilder::FindOrCreate32BitConstant(uint32_t value)
282 {
283     auto inst = GetGraph()->FindOrCreateConstant<uint32_t>(value);
284     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
285         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
286     }
287     return inst;
288 }
289 
FindOrCreateConstant(uint64_t value)290 ConstantInst *InstBuilder::FindOrCreateConstant(uint64_t value)
291 {
292     auto inst = GetGraph()->FindOrCreateConstant<uint64_t>(value);
293     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
294         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
295     }
296     return inst;
297 }
298 
FindOrCreateAnyConstant(DataType::Any value)299 ConstantInst *InstBuilder::FindOrCreateAnyConstant(DataType::Any value)
300 {
301     auto inst = GetGraph()->FindOrCreateConstant(value);
302     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
303         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value.Raw() << ", inst=" << inst->GetId();
304     }
305     return inst;
306 }
307 
FindOrCreateDoubleConstant(double value)308 ConstantInst *InstBuilder::FindOrCreateDoubleConstant(double value)
309 {
310     auto inst = GetGraph()->FindOrCreateConstant<double>(value);
311     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
312         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
313     }
314     return inst;
315 }
316 
FindOrCreateFloatConstant(float value)317 ConstantInst *InstBuilder::FindOrCreateFloatConstant(float value)
318 {
319     auto inst = GetGraph()->FindOrCreateConstant<float>(value);
320     if (inst->GetId() == GetGraph()->GetCurrentInstructionId() - 1) {
321         COMPILER_LOG(DEBUG, IR_BUILDER) << "create new constant: value=" << value << ", inst=" << inst->GetId();
322     }
323     return inst;
324 }
325 
UpdateDefsForPreds(size_t vreg,std::optional<Inst * > & value)326 bool InstBuilder::UpdateDefsForPreds(size_t vreg, std::optional<Inst *> &value)
327 {
328     for (auto predBb : currentBb_->GetPredsBlocks()) {
329         // When irreducible loop header is visited before it's back-edge, phi should be created,
330         // since we do not know if definitions are different at this point
331         if (!predBb->IsMarked(visitedBlockMarker_)) {
332             ASSERT(currentBb_->GetLoop()->IsIrreducible());
333             return true;
334         }
335         if (!value.has_value()) {
336             value = defs_[predBb->GetId()][vreg];
337         } else if (value.value() != defs_[predBb->GetId()][vreg]) {
338             return true;
339         }
340     }
341     return false;
342 }
343 
UpdateDefs()344 void InstBuilder::UpdateDefs()
345 {
346     currentBb_->SetMarker(visitedBlockMarker_);
347     if (currentBb_->IsCatchBegin()) {
348         UpdateDefsForCatch();
349     } else if (currentBb_->IsLoopHeader() && !currentBb_->GetLoop()->IsIrreducible()) {
350         UpdateDefsForLoopHead();
351     } else if (currentBb_->GetPredsBlocks().size() == 1) {
352         // Only one predecessor - simply copy all its definitions
353         auto &predDefs = defs_[currentBb_->GetPredsBlocks()[0]->GetId()];
354         std::copy(predDefs.begin(), predDefs.end(), currentDefs_->begin());
355     } else if (currentBb_->GetPredsBlocks().size() > 1) {
356         // If there are multiple predecessors, then add phi for each register that has different definitions
357         for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
358             std::optional<Inst *> value;
359             bool different = UpdateDefsForPreds(vreg, value);
360             if (different) {
361                 auto phi = GetGraph()->CreateInstPhi();
362                 phi->SetMarker(GetNoTypeMarker());
363                 phi->SetLinearNumber(vreg);
364                 currentBb_->AppendPhi(phi);
365                 (*currentDefs_)[vreg] = phi;
366                 COMPILER_LOG(DEBUG, IR_BUILDER) << "create Phi(id=" << phi->GetId() << ") for r" << vreg;
367             } else {
368                 (*currentDefs_)[vreg] = value.value();
369             }
370         }
371     }
372 }
373 
AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock * > & catchHandlers,const InstVector & defs,Inst * throwableInst)374 void InstBuilder::AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catchHandlers, const InstVector &defs,
375                                     Inst *throwableInst)
376 {
377     ASSERT(!catchHandlers.empty());
378     for (auto catchBb : catchHandlers) {
379         auto inst = catchBb->GetFirstInst();
380         while (!inst->IsCatchPhi()) {
381             inst = inst->GetNext();
382         }
383         ASSERT(inst != nullptr);
384         GetGraph()->AppendThrowableInst(throwableInst, catchBb);
385         for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++, inst = inst->GetNext()) {
386             ASSERT(inst->GetOpcode() == Opcode::CatchPhi);
387             auto catchPhi = inst->CastToCatchPhi();
388             if (catchPhi->IsAcc()) {
389                 ASSERT(vreg == vregsAndArgsCount_);
390                 continue;
391             }
392             auto inputInst = defs[vreg];
393             if (inputInst != nullptr && inputInst != catchPhi) {
394                 catchPhi->AppendInput(inputInst);
395                 catchPhi->AppendThrowableInst(throwableInst);
396             }
397         }
398     }
399 }
400 
SetParamSpillFill(Graph * graph,ParameterInst * paramInst,size_t numArgs,size_t i,DataType::Type type)401 void InstBuilder::SetParamSpillFill(Graph *graph, ParameterInst *paramInst, size_t numArgs, size_t i,
402                                     DataType::Type type)
403 {
404     if (graph->IsBytecodeOptimizer()) {
405         auto regSrc = static_cast<Register>(GetFrameSize() - numArgs + i);
406         DataType::Type regType;
407         if (DataType::IsReference(type)) {
408             regType = DataType::REFERENCE;
409         } else if (DataType::Is64Bits(type, graph->GetArch())) {
410             regType = DataType::UINT64;
411         } else {
412             regType = DataType::UINT32;
413         }
414 
415         paramInst->SetLocationData({LocationType::REGISTER, LocationType::REGISTER, regSrc, regSrc, regType});
416     } else {
417 #ifndef PANDA_TARGET_WINDOWS
418         if (graph->IsDynamicMethod() && !graph->GetMode().IsDynamicStub()) {
419             ASSERT(type == DataType::ANY);
420             uint16_t slot = i + CallConvDynInfo::FIXED_SLOT_COUNT;
421             ASSERT(slot <= UINT8_MAX);
422             paramInst->SetLocationData(
423                 {LocationType::STACK_PARAMETER, LocationType::INVALID, slot, GetInvalidReg(), DataType::UINT64});
424         } else {
425             paramInst->SetLocationData(graph->GetDataForNativeParam(type));
426         }
427 #endif
428     }
429 }
430 
431 /// Set type of instruction, then recursively set type to its inputs.
SetTypeRec(Inst * inst,DataType::Type type)432 void InstBuilder::SetTypeRec(Inst *inst, DataType::Type type)
433 {
434     inst->SetType(type);
435     inst->ResetMarker(GetNoTypeMarker());
436     for (auto input : inst->GetInputs()) {
437         if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
438             SetTypeRec(input.GetInst(), type);
439         }
440     }
441 }
442 
443 /**
444  * Remove vreg from SaveState for the case
445  * BB 1
446  *   ....
447  * succs: [bb 2, bb 3]
448  *
449  * BB 2: preds: [bb 1]
450  *   89.i64  Sub                        v85, v88 -> (v119, v90)
451  *   90.f64  Cast                       v89 -> (v96, v92)
452  * succs: [bb 3]
453  *
454  * BB 3: preds: [bb 1, bb 2]
455  *   .....
456  *   119.     SaveState                  v105(vr0), v106(vr1), v94(vr4), v89(vr8), v0(vr10), v1(vr11) -> (v120)
457  *
458  * v89(vr8) used only in BB 2, so we need to remove its from "119.     SaveState"
459  */
460 /* static */
RemoveNotDominateInputs(SaveStateInst * saveState)461 void InstBuilder::RemoveNotDominateInputs(SaveStateInst *saveState)
462 {
463     size_t idx = 0;
464     size_t inputsCount = saveState->GetInputsCount();
465     while (idx < inputsCount) {
466         auto inputInst = saveState->GetInput(idx).GetInst();
467         // We can don't call IsDominate, if save_state and input_inst in one basic block.
468         // It's reduce number of IsDominate calls.
469         if (!inputInst->InSameBlockOrDominate(saveState)) {
470             saveState->RemoveInput(idx);
471             inputsCount--;
472         } else {
473             ASSERT(inputInst->GetBasicBlock() != saveState->GetBasicBlock() || inputInst->IsDominate(saveState));
474             idx++;
475         }
476     }
477 }
478 
479 // Remove dead Phi and set types to phi which have not type.
480 // Phi may not have type if all it users are pseudo instructions, like SaveState
FixType(PhiInst * inst,BasicBlock * bb)481 void InstBuilder::FixType(PhiInst *inst, BasicBlock *bb)
482 {
483     inst->ReserveInputs(bb->GetPredsBlocks().size());
484     for (auto &predBb : bb->GetPredsBlocks()) {
485         if (inst->GetLinearNumber() == INVALID_LINEAR_NUM) {
486             continue;
487         }
488         auto pred = defs_[predBb->GetId()][inst->GetLinearNumber()];
489         if (pred == nullptr) {
490             // If any input of phi instruction is not defined then we assume that phi is dead. DCE should
491             // remove it.
492             continue;
493         }
494         inst->AppendInput(pred);
495     }
496 }
497 
498 // Check all instructions that have no type and fix it. Type is got from instructions with known input types.
FixType(Inst * inst)499 void InstBuilder::FixType(Inst *inst)
500 {
501     if (inst->IsSaveState()) {
502         RemoveNotDominateInputs(static_cast<SaveStateInst *>(inst));
503         return;
504     }
505     auto inputIdx = 0;
506     for (auto input : inst->GetInputs()) {
507         if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
508             auto inputType = inst->GetInputType(inputIdx);
509             if (inputType != DataType::NO_TYPE) {
510                 SetTypeRec(input.GetInst(), inputType);
511             }
512         }
513         inputIdx++;
514     }
515 }
516 
517 /// Fix instructions that can't be fully completed in building process.
FixInstructions()518 void InstBuilder::FixInstructions()
519 {
520     for (auto bb : GetGraph()->GetBlocksRPO()) {
521         for (auto inst : bb->PhiInstsSafe()) {
522             FixType(inst->CastToPhi(), bb);
523         }
524     }
525 
526     for (auto bb : GetGraph()->GetBlocksRPO()) {
527         for (auto inst : bb->AllInsts()) {
528             FixType(inst);
529         }
530     }
531     // Resolve dead and inconsistent phi instructions
532     PhiResolver phiResolver(GetGraph());
533     phiResolver.Run();
534     ResolveConstants();
535 }
536 
CreateSaveState(Opcode opc,size_t pc)537 SaveStateInst *InstBuilder::CreateSaveState(Opcode opc, size_t pc)
538 {
539     ASSERT(opc == Opcode::SaveState || opc == Opcode::SafePoint || opc == Opcode::SaveStateOsr ||
540            opc == Opcode::SaveStateDeoptimize);
541     SaveStateInst *inst;
542     bool withoutNumericInputs = false;
543     auto liveVergsCount =
544         std::count_if(currentDefs_->begin(), currentDefs_->end(), [](Inst *p) { return p != nullptr; });
545     if (opc == Opcode::SaveState) {
546         inst = GetGraph()->CreateInstSaveState(pc, GetMethod(), callerInst_, inliningDepth_);
547     } else if (opc == Opcode::SaveStateOsr) {
548         inst = GetGraph()->CreateInstSaveStateOsr(pc, GetMethod(), callerInst_, inliningDepth_);
549     } else if (opc == Opcode::SafePoint) {
550         inst = GetGraph()->CreateInstSafePoint(pc, GetMethod(), callerInst_, inliningDepth_);
551         withoutNumericInputs = true;
552     } else {
553         inst = GetGraph()->CreateInstSaveStateDeoptimize(pc, GetMethod(), callerInst_, inliningDepth_);
554     }
555     if (GetGraph()->IsBytecodeOptimizer()) {
556         inst->ReserveInputs(0);
557         return inst;
558     }
559     inst->ReserveInputs(liveVergsCount);
560 
561     for (VirtualRegister::ValueType regIdx = 0; regIdx < vregsAndArgsCount_; ++regIdx) {
562         auto defInst = (*currentDefs_)[regIdx];
563         if (defInst != nullptr && (!withoutNumericInputs || !DataType::IsTypeNumeric(defInst->GetType()))) {
564             auto inputIdx = inst->AppendInput(defInst);
565             inst->SetVirtualRegister(inputIdx, VirtualRegister(regIdx, VRegType::VREG));
566         }
567     }
568     VirtualRegister::ValueType regIdx = vregsAndArgsCount_;
569     auto defInst = (*currentDefs_)[regIdx];
570     if (defInst != nullptr && (!withoutNumericInputs || !DataType::IsTypeNumeric(defInst->GetType()))) {
571         auto inputIdx = inst->AppendInput(defInst);
572         inst->SetVirtualRegister(inputIdx, VirtualRegister(regIdx, VRegType::ACC));
573     }
574     regIdx++;
575     if (GetGraph()->IsDynamicMethod() && !GetGraph()->IsBytecodeOptimizer() && (*currentDefs_)[regIdx] != nullptr) {
576         for (uint8_t envIdx = 0; envIdx < VRegInfo::ENV_COUNT; ++envIdx) {
577             auto inputIdx = inst->AppendInput(GetEnvDefinition(envIdx));
578             inst->SetVirtualRegister(inputIdx, VirtualRegister(regIdx++, VRegType(VRegType::ENV_BEGIN + envIdx)));
579         }
580         if (additionalDef_ != nullptr) {
581             inst->AppendBridge(additionalDef_);
582         }
583     }
584     return inst;
585 }
586 
CreateLoadAndInitClassGeneric(uint32_t classId,size_t pc)587 ClassInst *InstBuilder::CreateLoadAndInitClassGeneric(uint32_t classId, size_t pc)
588 {
589     auto classPtr = GetRuntime()->ResolveType(GetGraph()->GetMethod(), classId);
590     ClassInst *inst = nullptr;
591     if (classPtr == nullptr) {
592         ASSERT(!graph_->IsBytecodeOptimizer());
593         inst = graph_->CreateInstUnresolvedLoadAndInitClass(DataType::REFERENCE, pc, nullptr,
594                                                             TypeIdMixin {classId, GetGraph()->GetMethod()}, classPtr);
595         if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
596             GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), classId,
597                                                              UnresolvedTypesInterface::SlotKind::CLASS);
598         }
599     } else {
600         inst = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, nullptr,
601                                                   TypeIdMixin {classId, GetGraph()->GetMethod()}, classPtr);
602     }
603     return inst;
604 }
605 
GetCurrentMethodReturnType() const606 DataType::Type InstBuilder::GetCurrentMethodReturnType() const
607 {
608     return GetRuntime()->GetMethodReturnType(GetMethod());
609 }
610 
GetCurrentMethodArgumentType(size_t index) const611 DataType::Type InstBuilder::GetCurrentMethodArgumentType(size_t index) const
612 {
613     return GetRuntime()->GetMethodTotalArgumentType(GetMethod(), index);
614 }
615 
GetCurrentMethodArgumentsCount() const616 size_t InstBuilder::GetCurrentMethodArgumentsCount() const
617 {
618     return GetRuntime()->GetMethodTotalArgumentsCount(GetMethod());
619 }
620 
GetMethodReturnType(uintptr_t id) const621 DataType::Type InstBuilder::GetMethodReturnType(uintptr_t id) const
622 {
623     return GetRuntime()->GetMethodReturnType(GetMethod(), id);
624 }
625 
GetMethodArgumentType(uintptr_t id,size_t index) const626 DataType::Type InstBuilder::GetMethodArgumentType(uintptr_t id, size_t index) const
627 {
628     return GetRuntime()->GetMethodArgumentType(GetMethod(), id, index);
629 }
630 
GetMethodArgumentsCount(uintptr_t id) const631 size_t InstBuilder::GetMethodArgumentsCount(uintptr_t id) const
632 {
633     return GetRuntime()->GetMethodArgumentsCount(GetMethod(), id);
634 }
635 
GetPc(const uint8_t * instPtr) const636 size_t InstBuilder::GetPc(const uint8_t *instPtr) const
637 {
638     return instPtr - instructionsBuf_;
639 }
640 
ResolveConstants()641 void InstBuilder::ResolveConstants()
642 {
643     ConstantInst *currConst = GetGraph()->GetFirstConstInst();
644     while (currConst != nullptr) {
645         SplitConstant(currConst);
646         currConst = currConst->GetNextConst();
647     }
648 }
649 
SplitConstant(ConstantInst * constInst)650 void InstBuilder::SplitConstant(ConstantInst *constInst)
651 {
652     if (constInst->GetType() != DataType::INT64 || !constInst->HasUsers()) {
653         return;
654     }
655     auto users = constInst->GetUsers();
656     auto currIt = users.begin();
657     while (currIt != users.end()) {
658         auto user = (*currIt).GetInst();
659         DataType::Type type = user->GetInputType(currIt->GetIndex());
660         ++currIt;
661         if (type != DataType::FLOAT32 && type != DataType::FLOAT64) {
662             continue;
663         }
664         ConstantInst *newConst = nullptr;
665         if (type == DataType::FLOAT32) {
666             auto val = bit_cast<float>(static_cast<uint32_t>(constInst->GetIntValue()));
667             newConst = GetGraph()->FindOrCreateConstant(val);
668         } else {
669             auto val = bit_cast<double, uint64_t>(constInst->GetIntValue());
670             newConst = GetGraph()->FindOrCreateConstant(val);
671         }
672         user->ReplaceInput(constInst, newConst);
673     }
674 }
675 
SyncWithGraph()676 void InstBuilder::SyncWithGraph()
677 {
678     size_t idx = currentDefs_ - &defs_[0];
679     size_t size = defs_.size();
680     defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph_->GetLocalAllocator()->Adapter()));
681     for (size_t i = size; i < defs_.size(); i++) {
682         defs_[i].resize(vregsAndArgsCount_ + 1 + graph_->GetEnvCount());
683         std::copy(defs_[idx].cbegin(), defs_[idx].cend(), defs_[i].begin());
684     }
685     currentDefs_ = &defs_[currentBb_->GetId()];
686 }
687 
688 template <bool IS_STATIC>
IsInConstructor() const689 bool InstBuilder::IsInConstructor() const
690 {
691     for (auto graph = GetGraph(); graph != nullptr; graph = graph->GetParentGraph()) {
692         auto method = graph->GetMethod();
693         if (IS_STATIC ? GetRuntime()->IsMethodStaticConstructor(method) : GetRuntime()->IsInstanceConstructor(method)) {
694             return true;
695         }
696     }
697     return false;
698 }
699 template bool InstBuilder::IsInConstructor<true>() const;
700 template bool InstBuilder::IsInConstructor<false>() const;
701 
702 }  // namespace ark::compiler
703