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