1 /*
2 * Copyright (c) 2021-2025 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 auto unresolvedTypes = GetRuntime()->GetUnresolvedTypes();
597 ASSERT(unresolvedTypes != nullptr);
598 unresolvedTypes->AddTableSlot(GetMethod(), classId, UnresolvedTypesInterface::SlotKind::CLASS);
599 }
600 } else {
601 ASSERT(classId != 0);
602 inst = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, nullptr,
603 TypeIdMixin {classId, GetGraph()->GetMethod()}, classPtr);
604 }
605 return inst;
606 }
607
GetCurrentMethodReturnType() const608 DataType::Type InstBuilder::GetCurrentMethodReturnType() const
609 {
610 return GetRuntime()->GetMethodReturnType(GetMethod());
611 }
612
GetCurrentMethodArgumentType(size_t index) const613 DataType::Type InstBuilder::GetCurrentMethodArgumentType(size_t index) const
614 {
615 return GetRuntime()->GetMethodTotalArgumentType(GetMethod(), index);
616 }
617
GetCurrentMethodArgumentsCount() const618 size_t InstBuilder::GetCurrentMethodArgumentsCount() const
619 {
620 return GetRuntime()->GetMethodTotalArgumentsCount(GetMethod());
621 }
622
GetMethodReturnType(uintptr_t id) const623 DataType::Type InstBuilder::GetMethodReturnType(uintptr_t id) const
624 {
625 return GetRuntime()->GetMethodReturnType(GetMethod(), id);
626 }
627
GetMethodArgumentType(uintptr_t id,size_t index) const628 DataType::Type InstBuilder::GetMethodArgumentType(uintptr_t id, size_t index) const
629 {
630 return GetRuntime()->GetMethodArgumentType(GetMethod(), id, index);
631 }
632
GetMethodArgumentsCount(uintptr_t id) const633 size_t InstBuilder::GetMethodArgumentsCount(uintptr_t id) const
634 {
635 return GetRuntime()->GetMethodArgumentsCount(GetMethod(), id);
636 }
637
GetPc(const uint8_t * instPtr) const638 size_t InstBuilder::GetPc(const uint8_t *instPtr) const
639 {
640 return instPtr - instructionsBuf_;
641 }
642
ResolveConstants()643 void InstBuilder::ResolveConstants()
644 {
645 ConstantInst *currConst = GetGraph()->GetFirstConstInst();
646 while (currConst != nullptr) {
647 SplitConstant(currConst);
648 currConst = currConst->GetNextConst();
649 }
650 }
651
SplitConstant(ConstantInst * constInst)652 void InstBuilder::SplitConstant(ConstantInst *constInst)
653 {
654 if (constInst->GetType() != DataType::INT64 || !constInst->HasUsers()) {
655 return;
656 }
657 auto users = constInst->GetUsers();
658 auto currIt = users.begin();
659 while (currIt != users.end()) {
660 auto user = (*currIt).GetInst();
661 DataType::Type type = user->GetInputType(currIt->GetIndex());
662 ++currIt;
663 if (type != DataType::FLOAT32 && type != DataType::FLOAT64) {
664 continue;
665 }
666 ConstantInst *newConst = nullptr;
667 if (type == DataType::FLOAT32) {
668 auto val = bit_cast<float>(static_cast<uint32_t>(constInst->GetIntValue()));
669 newConst = GetGraph()->FindOrCreateConstant(val);
670 } else {
671 auto val = bit_cast<double, uint64_t>(constInst->GetIntValue());
672 newConst = GetGraph()->FindOrCreateConstant(val);
673 }
674 user->ReplaceInput(constInst, newConst);
675 }
676 }
677
SyncWithGraph()678 void InstBuilder::SyncWithGraph()
679 {
680 size_t idx = currentDefs_ - &defs_[0];
681 size_t size = defs_.size();
682 defs_.resize(graph_->GetVectorBlocks().size(), InstVector(graph_->GetLocalAllocator()->Adapter()));
683 for (size_t i = size; i < defs_.size(); i++) {
684 defs_[i].resize(vregsAndArgsCount_ + 1 + graph_->GetEnvCount());
685 std::copy(defs_[idx].cbegin(), defs_[idx].cend(), defs_[i].begin());
686 }
687 currentDefs_ = &defs_[currentBb_->GetId()];
688 }
689
690 template <bool IS_STATIC>
IsInConstructor() const691 bool InstBuilder::IsInConstructor() const
692 {
693 for (auto graph = GetGraph(); graph != nullptr; graph = graph->GetParentGraph()) {
694 auto method = graph->GetMethod();
695 if (IS_STATIC ? GetRuntime()->IsMethodStaticConstructor(method) : GetRuntime()->IsInstanceConstructor(method)) {
696 return true;
697 }
698 }
699 return false;
700 }
701 template bool InstBuilder::IsInConstructor<true>() const;
702 template bool InstBuilder::IsInConstructor<false>() const;
703
704 } // namespace ark::compiler
705