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_generator.h"
17
18 namespace ark::compiler {
19 // CC-OFFNXT(huge_method, huge_cyclomatic_complexity, G.FUN.01) big switch-case
GenerateGraph(Inst * inst)20 Graph *GraphCreator::GenerateGraph(Inst *inst)
21 {
22 Graph *graph;
23 SetNumVRegsArgs(0U, 0U);
24 switch (inst->GetOpcode()) {
25 case Opcode::LoadArray:
26 case Opcode::LoadArrayI:
27 case Opcode::StoreArray:
28 case Opcode::StoreArrayI:
29 case Opcode::StoreObject:
30 case Opcode::SelectImm:
31 case Opcode::Select:
32 case Opcode::ReturnInlined:
33 case Opcode::LoadArrayPair:
34 case Opcode::LoadArrayPairI:
35 case Opcode::StoreArrayPair:
36 case Opcode::StoreArrayPairI:
37 case Opcode::NewArray:
38 case Opcode::NewObject:
39 // -1 means special processing
40 graph = GenerateOperation(inst, -1L);
41 break;
42 case Opcode::ReturnVoid:
43 case Opcode::NullPtr:
44 case Opcode::Constant:
45 case Opcode::Parameter:
46 case Opcode::SpillFill:
47 case Opcode::ReturnI:
48 graph = GenerateOperation(inst, 0U);
49 break;
50 case Opcode::Neg:
51 case Opcode::Abs:
52 case Opcode::Not:
53 case Opcode::LoadString:
54 case Opcode::LoadType:
55 case Opcode::LenArray:
56 case Opcode::Return:
57 case Opcode::IfImm:
58 case Opcode::SaveState:
59 case Opcode::SafePoint:
60 case Opcode::Cast:
61 case Opcode::CallStatic:
62 case Opcode::CallVirtual:
63 case Opcode::AddI:
64 case Opcode::SubI:
65 case Opcode::ShlI:
66 case Opcode::ShrI:
67 case Opcode::AShrI:
68 case Opcode::AndI:
69 case Opcode::OrI:
70 case Opcode::XorI:
71 case Opcode::LoadObject:
72 case Opcode::LoadStatic:
73 case Opcode::Monitor:
74 case Opcode::NegSR:
75 graph = GenerateOperation(inst, 1U);
76 break;
77 case Opcode::Add:
78 case Opcode::Sub:
79 case Opcode::Mul:
80 case Opcode::Div:
81 case Opcode::Mod:
82 case Opcode::Min:
83 case Opcode::Max:
84 case Opcode::Shl:
85 case Opcode::Shr:
86 case Opcode::AShr:
87 case Opcode::And:
88 case Opcode::Or:
89 case Opcode::Xor:
90 case Opcode::Compare:
91 case Opcode::Cmp:
92 case Opcode::If:
93 case Opcode::StoreStatic:
94 case Opcode::AndNot:
95 case Opcode::OrNot:
96 case Opcode::XorNot:
97 case Opcode::MNeg:
98 case Opcode::AddSR:
99 case Opcode::SubSR:
100 case Opcode::AndSR:
101 case Opcode::OrSR:
102 case Opcode::XorSR:
103 case Opcode::AndNotSR:
104 case Opcode::OrNotSR:
105 case Opcode::XorNotSR:
106 case Opcode::IsInstance:
107 graph = GenerateOperation(inst, 2U);
108 break;
109 case Opcode::MAdd:
110 case Opcode::MSub:
111 graph = GenerateOperation(inst, 3U);
112 break;
113 case Opcode::BoundsCheck:
114 case Opcode::BoundsCheckI:
115 graph = GenerateBoundaryCheckOperation(inst);
116 break;
117 case Opcode::NullCheck:
118 case Opcode::CheckCast:
119 case Opcode::ZeroCheck:
120 case Opcode::NegativeCheck:
121 graph = GenerateCheckOperation(inst);
122 break;
123 case Opcode::Phi:
124 graph = GeneratePhiOperation(inst);
125 break;
126 case Opcode::Throw:
127 graph = GenerateThrowOperation(inst);
128 break;
129 case Opcode::MultiArray:
130 graph = GenerateMultiArrayOperation(inst);
131 break;
132 case Opcode::Intrinsic:
133 graph = GenerateIntrinsicOperation(inst);
134 break;
135 default:
136 ASSERT_DO(0U, inst->Dump(&std::cerr));
137 graph = nullptr;
138 break;
139 }
140 if (graph != nullptr) {
141 auto id = graph->GetCurrentInstructionId();
142 inst->SetId(id);
143 graph->SetCurrentInstructionId(++id);
144 graph->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
145 graph->ResetParameterInfo();
146 for (auto param : graph->GetStartBlock()->Insts()) {
147 if (param->GetOpcode() == Opcode::Parameter) {
148 param->CastToParameter()->SetLocationData(graph->GetDataForNativeParam(param->GetType()));
149 runtime_.argTypes_->push_back(param->GetType());
150 }
151 }
152 }
153 if (inst->GetOpcode() == Opcode::CheckCast) {
154 runtime_.returnType_ = DataType::REFERENCE;
155 } else if (inst->GetType() == DataType::NO_TYPE || inst->IsStore()) {
156 runtime_.returnType_ = DataType::VOID;
157 } else {
158 runtime_.returnType_ = inst->GetType();
159 }
160 #ifndef NDEBUG
161 if (graph != nullptr) {
162 // GraphChecker hack: LowLevel instructions may appear only after Lowering pass:
163 graph->SetLowLevelInstructionsEnabled();
164 }
165 #endif
166 return graph;
167 }
168
CreateGraph()169 Graph *GraphCreator::CreateGraph()
170 {
171 Graph *graph = allocator_.New<Graph>(&allocator_, &localAllocator_, arch_);
172 runtime_.argTypes_ = allocator_.New<ArenaVector<DataType::Type>>(allocator_.Adapter());
173 graph->SetRuntime(&runtime_);
174 graph->SetStackSlotsCount(3U);
175 return graph;
176 }
177
178 // NOLINTNEXTLINE(readability-function-size)
GenerateOperation(Inst * inst,int32_t n)179 Graph *GraphCreator::GenerateOperation(Inst *inst, int32_t n)
180 {
181 Graph *graph;
182 auto opc = inst->GetOpcode();
183 if (opc == Opcode::If || opc == Opcode::IfImm) {
184 graph = CreateGraphWithThreeBasicBlock();
185 } else {
186 graph = CreateGraphWithOneBasicBlock();
187 }
188 ASSERT(graph->GetVectorBlocks().size() > 2U);
189 PopulateGraph(graph, inst, n);
190 return graph;
191 }
192
DataTypeByOpcode(Inst * inst)193 auto DataTypeByOpcode(Inst *inst)
194 {
195 switch (inst->GetOpcode()) {
196 case Opcode::IsInstance:
197 case Opcode::LenArray:
198 case Opcode::SaveState:
199 case Opcode::SafePoint:
200 case Opcode::CallStatic:
201 case Opcode::CallVirtual:
202 case Opcode::NewArray:
203 case Opcode::LoadObject:
204 case Opcode::Monitor:
205 return DataType::REFERENCE;
206 case Opcode::IfImm:
207 return inst->CastToIfImm()->GetOperandsType();
208 case Opcode::If:
209 return inst->CastToIf()->GetOperandsType();
210 case Opcode::Compare:
211 return inst->CastToCompare()->GetOperandsType();
212 case Opcode::Cmp:
213 return inst->CastToCmp()->GetOperandsType();
214 default:
215 return inst->GetType();
216 }
217 }
218
PopulateLoadArrayPair(Graph * graph,BasicBlock * block,Inst * inst,Opcode opc)219 Inst *GraphCreator::PopulateLoadArrayPair(Graph *graph, BasicBlock *block, Inst *inst, Opcode opc)
220 {
221 auto array = CreateParamInst(graph, DataType::REFERENCE, 0U);
222 Inst *index = nullptr;
223 if (opc == Opcode::LoadArrayPair) {
224 index = CreateParamInst(graph, DataType::INT32, 1U);
225 }
226 inst->SetInput(0U, array);
227 if (opc == Opcode::LoadArrayPair) {
228 inst->SetInput(1U, index);
229 }
230 block->AppendInst(inst);
231 auto loadPairPart0 = graph->CreateInstLoadPairPart(inst->GetType(), INVALID_PC, inst, 0U);
232 auto loadPairPart1 = graph->CreateInstLoadPairPart(inst->GetType(), INVALID_PC, inst, 1U);
233 block->AppendInst(loadPairPart0);
234 return loadPairPart1;
235 }
236
PopulateStoreArrayPair(Graph * graph,Inst * inst,Opcode opc)237 void GraphCreator::PopulateStoreArrayPair(Graph *graph, Inst *inst, Opcode opc)
238 {
239 int stackSlot = 0;
240 auto array = CreateParamInst(graph, DataType::REFERENCE, stackSlot++);
241 Inst *index = nullptr;
242 if (opc == Opcode::StoreArrayPair) {
243 index = CreateParamInst(graph, DataType::INT32, stackSlot++);
244 }
245 auto val1 = CreateParamInst(graph, inst->GetType(), stackSlot++);
246 auto val2 = CreateParamInst(graph, inst->GetType(), stackSlot++);
247 int idx = 0;
248 inst->SetInput(idx++, array);
249 if (opc == Opcode::StoreArrayPair) {
250 inst->SetInput(idx++, index);
251 }
252 inst->SetInput(idx++, val1);
253 inst->SetInput(idx++, val2);
254 }
255
PopulateReturnInlined(Graph * graph,BasicBlock * block,Inst * inst,int32_t n)256 void GraphCreator::PopulateReturnInlined(Graph *graph, BasicBlock *block, Inst *inst, [[maybe_unused]] int32_t n)
257 {
258 ASSERT(n == -1L);
259 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
260 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
261 block->AppendInst(saveState);
262
263 auto callInst = static_cast<CallInst *>(graph->CreateInstCallStatic());
264 callInst->SetType(DataType::VOID);
265 callInst->SetInlined(true);
266 callInst->SetInputs(&allocator_, {{saveState, DataType::NO_TYPE}});
267 block->AppendInst(callInst);
268
269 inst->SetInput(0U, saveState);
270 SetNumVRegsArgs(0U, saveState->GetInputsCount());
271 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
272 }
273
PopulateCall(Graph * graph,BasicBlock * block,Inst * inst,DataType::Type type,int32_t n)274 void GraphCreator::PopulateCall(Graph *graph, BasicBlock *block, Inst *inst, DataType::Type type, int32_t n)
275 {
276 ASSERT(n >= 0);
277 auto callInst = static_cast<CallInst *>(inst);
278 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
279 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
280 callInst->SetCallMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
281 block->PrependInst(saveState);
282 callInst->AllocateInputTypes(&allocator_, n + 1);
283 for (int32_t i = 0; i < n; ++i) {
284 auto param = CreateParamInst(graph, type, i);
285 callInst->AppendInput(param, type);
286 saveState->AppendInput(param);
287 }
288 for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
289 saveState->SetVirtualRegister(i, VirtualRegister(i, VRegType::VREG));
290 }
291 callInst->AppendInput(saveState, DataType::NO_TYPE);
292 SetNumVRegsArgs(0, saveState->GetInputsCount());
293 graph->SetVRegsCount(saveState->GetInputsCount() + 1);
294 }
295
PopulateLoadStoreArray(Graph * graph,Inst * inst,DataType::Type type,int32_t n)296 void GraphCreator::PopulateLoadStoreArray(Graph *graph, Inst *inst, DataType::Type type, [[maybe_unused]] int32_t n)
297 {
298 ASSERT(n == -1L);
299 auto param1 = CreateParamInst(graph, DataType::REFERENCE, 0U); // array
300 auto param2 = CreateParamInst(graph, DataType::INT32, 1U); // index
301 inst->SetInput(0U, param1);
302 inst->SetInput(1U, param2);
303 if (inst->GetOpcode() == Opcode::StoreArray) {
304 auto param3 = CreateParamInst(graph, type, 2U);
305 inst->SetInput(2U, param3);
306 }
307 }
308
PopulateLoadStoreArrayI(Graph * graph,Inst * inst,DataType::Type type,int32_t n)309 void GraphCreator::PopulateLoadStoreArrayI(Graph *graph, Inst *inst, DataType::Type type, [[maybe_unused]] int32_t n)
310 {
311 ASSERT(n == -1L);
312 auto param1 = CreateParamInst(graph, DataType::REFERENCE, 0U); // array/object
313 inst->SetInput(0U, param1);
314 if (inst->GetOpcode() != Opcode::LoadArrayI) {
315 auto param2 = CreateParamInst(graph, type, 1U);
316 inst->SetInput(1U, param2);
317 }
318 }
319
PopulateSelect(Graph * graph,Inst * inst,DataType::Type type,int32_t n)320 void GraphCreator::PopulateSelect(Graph *graph, Inst *inst, DataType::Type type, [[maybe_unused]] int32_t n)
321 {
322 ASSERT(n == -1L);
323 auto cmpType = inst->CastToSelect()->GetOperandsType();
324 auto param0 = CreateParamInst(graph, type, 0U);
325 auto param1 = CreateParamInst(graph, type, 1U);
326 auto param2 = CreateParamInst(graph, cmpType, 2U);
327 auto param3 = CreateParamInst(graph, cmpType, 3U);
328 inst->SetInput(0U, param0);
329 inst->SetInput(1U, param1);
330 inst->SetInput(2U, param2);
331 inst->SetInput(3U, param3);
332 }
333
PopulateSelectI(Graph * graph,Inst * inst,DataType::Type type,int32_t n)334 void GraphCreator::PopulateSelectI(Graph *graph, Inst *inst, DataType::Type type, [[maybe_unused]] int32_t n)
335 {
336 ASSERT(n == -1L);
337 auto cmpType = inst->CastToSelectImm()->GetOperandsType();
338 auto param0 = CreateParamInst(graph, type, 0U);
339 auto param1 = CreateParamInst(graph, type, 1U);
340 auto param2 = CreateParamInst(graph, cmpType, 2U);
341 inst->SetInput(0U, param0);
342 inst->SetInput(1U, param1);
343 inst->SetInput(2U, param2);
344 }
345
PopulateStoreStatic(Graph * graph,BasicBlock * block,Inst * inst,DataType::Type type)346 void GraphCreator::PopulateStoreStatic(Graph *graph, BasicBlock *block, Inst *inst, DataType::Type type)
347 {
348 auto param0 = CreateParamInst(graph, type, 0U);
349 inst->SetInput(1U, param0);
350 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
351 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
352 saveState->AppendInput(param0);
353 saveState->SetVirtualRegister(0U, VirtualRegister(0U, VRegType::VREG));
354 auto initInst =
355 graph->CreateInstLoadAndInitClass(DataType::REFERENCE, INVALID_PC, saveState,
356 TypeIdMixin {inst->CastToStoreStatic()->GetTypeId(), nullptr}, nullptr);
357 inst->SetInput(0U, initInst);
358 block->PrependInst(initInst);
359 block->PrependInst(saveState);
360 SetNumVRegsArgs(0U, saveState->GetInputsCount());
361 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
362 }
363
PopulateLoadStatic(Graph * graph,BasicBlock * block,Inst * inst)364 void GraphCreator::PopulateLoadStatic(Graph *graph, BasicBlock *block, Inst *inst)
365 {
366 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
367 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
368 auto initInst =
369 graph->CreateInstLoadAndInitClass(DataType::REFERENCE, INVALID_PC, saveState,
370 TypeIdMixin {inst->CastToLoadStatic()->GetTypeId(), nullptr}, nullptr);
371 inst->SetInput(0U, initInst);
372 block->PrependInst(initInst);
373 block->PrependInst(saveState);
374 SetNumVRegsArgs(0U, saveState->GetInputsCount());
375 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
376 }
377
PopulateMonitor(Graph * graph,BasicBlock * block,Inst * inst)378 void GraphCreator::PopulateMonitor(Graph *graph, BasicBlock *block, Inst *inst)
379 {
380 auto param0 = CreateParamInst(graph, DataType::REFERENCE, 0U);
381 inst->SetInput(0U, param0);
382 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
383 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
384 saveState->AppendInput(param0);
385 saveState->SetVirtualRegister(0U, VirtualRegister(0U, VRegType::VREG));
386 inst->SetInput(1U, saveState);
387 block->PrependInst(saveState);
388 SetNumVRegsArgs(0U, saveState->GetInputsCount());
389 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
390 }
391
PopulateLoadType(Graph * graph,BasicBlock * block,Inst * inst)392 void GraphCreator::PopulateLoadType(Graph *graph, BasicBlock *block, Inst *inst)
393 {
394 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
395 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
396 inst->SetInput(0U, saveState);
397 block->PrependInst(saveState);
398 SetNumVRegsArgs(0U, saveState->GetInputsCount());
399 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
400 }
401
PopulateIsInstance(Graph * graph,BasicBlock * block,Inst * inst)402 void GraphCreator::PopulateIsInstance(Graph *graph, BasicBlock *block, Inst *inst)
403 {
404 auto param0 = CreateParamInst(graph, DataType::REFERENCE, 0U);
405 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
406 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
407 saveState->AppendInput(param0);
408 saveState->SetVirtualRegister(0U, VirtualRegister(0U, VRegType::VREG));
409 auto loadClass = graph->CreateInstLoadClass(DataType::REFERENCE, INVALID_PC, saveState, TypeIdMixin {0, nullptr},
410 reinterpret_cast<RuntimeInterface::ClassPtr>(1));
411 inst->SetInput(0U, param0);
412 inst->SetInput(1U, loadClass);
413 inst->SetSaveState(saveState);
414 block->PrependInst(loadClass);
415 block->PrependInst(saveState);
416 SetNumVRegsArgs(0U, saveState->GetInputsCount());
417 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
418 }
419
PopulateNewArray(Graph * graph,BasicBlock * block,Inst * inst,int32_t n)420 void GraphCreator::PopulateNewArray(Graph *graph, BasicBlock *block, Inst *inst, [[maybe_unused]] int32_t n)
421 {
422 ASSERT(n == -1L);
423 auto initInst = graph->CreateInstLoadAndInitClass(DataType::REFERENCE, INVALID_PC);
424 inst->SetInput(NewArrayInst::INDEX_CLASS, initInst);
425
426 auto param0 = CreateParamInst(graph, DataType::INT32, 0U);
427 inst->SetInput(NewArrayInst::INDEX_SIZE, param0);
428 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
429 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
430 saveState->AppendInput(param0);
431 saveState->SetVirtualRegister(0U, VirtualRegister(0U, VRegType::VREG));
432
433 initInst->SetTypeId(inst->CastToNewArray()->GetTypeId());
434 initInst->SetInput(0U, saveState);
435
436 inst->SetInput(NewArrayInst::INDEX_SAVE_STATE, saveState);
437 block->PrependInst(initInst);
438 block->PrependInst(saveState);
439 SetNumVRegsArgs(0U, saveState->GetInputsCount());
440 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
441 }
442
PopulateNewObject(Graph * graph,BasicBlock * block,Inst * inst,int32_t n)443 void GraphCreator::PopulateNewObject(Graph *graph, BasicBlock *block, Inst *inst, [[maybe_unused]] int32_t n)
444 {
445 ASSERT(n == -1L);
446 auto saveState = graph->CreateInstSaveState()->CastToSaveState();
447 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
448 auto initInst =
449 graph->CreateInstLoadAndInitClass(DataType::REFERENCE, INVALID_PC, saveState,
450 TypeIdMixin {inst->CastToNewObject()->GetTypeId(), nullptr}, nullptr);
451 inst->SetInput(0U, initInst);
452 inst->SetInput(0U, initInst);
453 inst->SetInput(1U, saveState);
454 block->PrependInst(initInst);
455 block->PrependInst(saveState);
456 SetNumVRegsArgs(0U, saveState->GetInputsCount());
457 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
458 }
459
PopulateDefault(Graph * graph,Inst * inst,DataType::Type type,int32_t n)460 void GraphCreator::PopulateDefault(Graph *graph, Inst *inst, DataType::Type type, int32_t n)
461 {
462 ASSERT(n >= 0);
463 for (int32_t i = 0; i < n; ++i) {
464 auto param = CreateParamInst(graph, type, i);
465 if (!inst->IsOperandsDynamic()) {
466 inst->SetInput(i, param);
467 } else {
468 inst->AppendInput(param);
469 }
470 }
471 }
472
473 // CC-OFFNXT(huge_cyclomatic_complexity, huge_cca_cyclomatic_complexity) solid logic
PopulateGraph(Graph * graph,Inst * inst,int32_t n)474 void GraphCreator::PopulateGraph(Graph *graph, Inst *inst, int32_t n)
475 {
476 auto type = DataTypeByOpcode(inst);
477 auto block = graph->GetVectorBlocks()[2U];
478 auto opc = inst->GetOpcode();
479 if (opc == Opcode::LoadArrayPair || opc == Opcode::LoadArrayPairI) {
480 inst = PopulateLoadArrayPair(graph, block, inst, opc);
481 } else if (opc == Opcode::StoreArrayPairI || opc == Opcode::StoreArrayPair) {
482 PopulateStoreArrayPair(graph, inst, opc);
483 } else if (opc == Opcode::ReturnInlined) {
484 PopulateReturnInlined(graph, block, inst, n);
485 } else if (opc == Opcode::CallStatic || opc == Opcode::CallVirtual) {
486 PopulateCall(graph, block, inst, type, n);
487 } else if (opc == Opcode::LoadArray || opc == Opcode::StoreArray) {
488 PopulateLoadStoreArray(graph, inst, type, n);
489 } else if (opc == Opcode::LoadArrayI || opc == Opcode::StoreArrayI || opc == Opcode::StoreObject) {
490 PopulateLoadStoreArrayI(graph, inst, type, n);
491 } else if (opc == Opcode::Select) {
492 PopulateSelect(graph, inst, type, n);
493 } else if (opc == Opcode::SelectImm) {
494 PopulateSelectI(graph, inst, type, n);
495 } else if (opc == Opcode::StoreStatic) {
496 PopulateStoreStatic(graph, block, inst, type);
497 } else if (opc == Opcode::LoadStatic) {
498 PopulateLoadStatic(graph, block, inst);
499 } else if (opc == Opcode::Monitor) {
500 PopulateMonitor(graph, block, inst);
501 } else if (opc == Opcode::LoadType || opc == Opcode::LoadString) {
502 PopulateLoadType(graph, block, inst);
503 } else if (opc == Opcode::IsInstance) {
504 PopulateIsInstance(graph, block, inst);
505 } else if (opc == Opcode::NewArray) {
506 PopulateNewArray(graph, block, inst, n);
507 } else if (opc == Opcode::NewObject) {
508 PopulateNewObject(graph, block, inst, n);
509 } else {
510 PopulateDefault(graph, inst, type, n);
511 }
512
513 Finalize(graph, block, inst);
514 }
515
Finalize(Graph * graph,BasicBlock * block,Inst * inst)516 void GraphCreator::Finalize(Graph *graph, BasicBlock *block, Inst *inst)
517 {
518 auto opc = inst->GetOpcode();
519 if (opc == Opcode::Constant || opc == Opcode::Parameter || opc == Opcode::NullPtr) {
520 graph->GetStartBlock()->AppendInst(inst);
521 } else {
522 block->AppendInst(inst);
523 }
524 if (!inst->IsControlFlow()) {
525 if (!inst->NoDest() || IsPseudoUserOfMultiOutput(inst)) {
526 auto ret = graph->CreateInstReturn(inst->GetType(), INVALID_PC, inst);
527 block->AppendInst(ret);
528 } else {
529 auto ret = graph->CreateInstReturnVoid();
530 block->AppendInst(ret);
531 }
532 }
533
534 if (opc == Opcode::SaveState || opc == Opcode::SafePoint) {
535 auto *saveState = static_cast<SaveStateInst *>(inst);
536 for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
537 saveState->SetVirtualRegister(i, VirtualRegister(i, VRegType::VREG));
538 }
539 SetNumVRegsArgs(0U, saveState->GetInputsCount());
540 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
541 }
542 if (inst->GetType() == DataType::REFERENCE) {
543 if (inst->GetOpcode() == Opcode::StoreArray) {
544 inst->CastToStoreArray()->SetNeedBarrier(true);
545 }
546 if (inst->GetOpcode() == Opcode::StoreArrayI) {
547 inst->CastToStoreArrayI()->SetNeedBarrier(true);
548 }
549 if (inst->GetOpcode() == Opcode::StoreStatic) {
550 inst->CastToStoreStatic()->SetNeedBarrier(true);
551 }
552 if (inst->GetOpcode() == Opcode::StoreObject) {
553 inst->CastToStoreObject()->SetNeedBarrier(true);
554 }
555 if (inst->GetOpcode() == Opcode::StoreArrayPair) {
556 inst->CastToStoreArrayPair()->SetNeedBarrier(true);
557 }
558 if (inst->GetOpcode() == Opcode::StoreArrayPairI) {
559 inst->CastToStoreArrayPairI()->SetNeedBarrier(true);
560 }
561 }
562 }
563
CreateCheckInstByPackArgs(const PackArgsForCkeckInst & pack)564 Inst *GraphCreator::CreateCheckInstByPackArgs(const PackArgsForCkeckInst &pack)
565 {
566 Inst *ret = nullptr;
567 DataType::Type type = pack.type;
568 if (pack.inst->GetOpcode() == Opcode::CheckCast) {
569 pack.inst->SetType(DataType::NO_TYPE);
570 ret = pack.graph->CreateInstReturn(type, INVALID_PC, pack.param1);
571 } else {
572 auto newInst = pack.graph->CreateInst(pack.opcode);
573 if (pack.opcode == Opcode::NewArray || pack.opcode == Opcode::NewObject) {
574 auto initInst = pack.graph->CreateInstLoadAndInitClass(DataType::REFERENCE, INVALID_PC);
575 initInst->SetSaveState(pack.saveState);
576 pack.block->AppendInst(initInst);
577 if (pack.opcode == Opcode::NewArray) {
578 newInst->SetInput(NewArrayInst::INDEX_CLASS, initInst);
579 newInst->SetInput(NewArrayInst::INDEX_SIZE, pack.inst);
580 } else {
581 newInst->SetInput(0U, initInst);
582 }
583 newInst->SetSaveState(pack.saveState);
584 type = DataType::REFERENCE;
585 } else if (pack.opcode == Opcode::LoadArray) {
586 newInst->SetInput(0U, pack.param1);
587 newInst->SetInput(1U, pack.param2);
588 type = DataType::REFERENCE;
589 } else {
590 newInst->SetInput(0U, pack.param1);
591 newInst->SetInput(1U, pack.inst);
592 type = DataType::UINT64;
593 }
594 newInst->SetType(type);
595 pack.block->AppendInst(newInst);
596
597 ret = pack.graph->CreateInstReturn();
598 if (pack.opcode == Opcode::NewArray) {
599 ret->SetType(DataType::UINT32);
600 ret->SetInput(0U, pack.param2);
601 } else {
602 ret->SetType(type);
603 ret->SetInput(0U, newInst);
604 }
605 }
606 return ret;
607 }
608
GenerateCheckOperation(Inst * inst)609 Graph *GraphCreator::GenerateCheckOperation(Inst *inst)
610 {
611 Opcode opcode;
612 DataType::Type type;
613 if (inst->GetOpcode() == Opcode::ZeroCheck) {
614 opcode = Opcode::Div;
615 type = DataType::UINT64;
616 } else if (inst->GetOpcode() == Opcode::NegativeCheck) {
617 opcode = Opcode::NewArray;
618 type = DataType::INT32;
619 } else if (inst->GetOpcode() == Opcode::NullCheck) {
620 opcode = Opcode::NewObject;
621 type = DataType::REFERENCE;
622 } else {
623 opcode = Opcode::LoadArray;
624 type = DataType::REFERENCE;
625 }
626 auto graph = CreateGraphWithOneBasicBlock();
627 ASSERT(graph->GetVectorBlocks().size() > 2U);
628 auto block = graph->GetVectorBlocks()[2U];
629 auto param1 = CreateParamInst(graph, type, 0U);
630 auto param2 = CreateParamInst(graph, DataType::UINT32, 1U);
631 auto saveState = static_cast<SaveStateInst *>(graph->CreateInstSaveState());
632 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
633 saveState->AppendInput(param1);
634 for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
635 saveState->SetVirtualRegister(i, VirtualRegister(i, VRegType::VREG));
636 }
637 SetNumVRegsArgs(0U, saveState->GetInputsCount());
638 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
639 block->AppendInst(saveState);
640 inst->SetInput(0U, param1);
641 inst->SetSaveState(saveState);
642 inst->SetType(type);
643 if (inst->GetOpcode() == Opcode::CheckCast) {
644 auto loadClass = graph->CreateInstLoadClass(DataType::REFERENCE, INVALID_PC, nullptr, TypeIdMixin {0, nullptr},
645 reinterpret_cast<RuntimeInterface::ClassPtr>(1));
646 loadClass->SetSaveState(saveState);
647 block->AppendInst(loadClass);
648 inst->SetInput(1U, loadClass);
649 }
650 block->AppendInst(inst);
651
652 Inst *ret = CreateCheckInstByPackArgs({opcode, type, inst, param1, param2, saveState, block, graph});
653 block->AppendInst(ret);
654 return graph;
655 }
656
GenerateSSOperation(Inst * inst)657 Graph *GraphCreator::GenerateSSOperation(Inst *inst)
658 {
659 DataType::Type type = DataType::UINT64;
660
661 auto graph = CreateGraphWithOneBasicBlock();
662 ASSERT(graph->GetVectorBlocks().size() > 2U);
663 auto block = graph->GetVectorBlocks()[2U];
664 auto param1 = CreateParamInst(graph, type, 0U);
665 auto saveState = static_cast<SaveStateInst *>(graph->CreateInstSaveState());
666 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
667 saveState->AppendInput(param1);
668 for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
669 saveState->SetVirtualRegister(i, VirtualRegister(i, VRegType::VREG));
670 }
671 SetNumVRegsArgs(0U, saveState->GetInputsCount());
672 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
673 block->AppendInst(saveState);
674 if (!inst->IsOperandsDynamic()) {
675 inst->SetInput(0U, saveState);
676 } else {
677 (static_cast<DynamicInputsInst *>(inst))->AppendInput(saveState);
678 }
679 inst->SetType(type);
680 block->AppendInst(inst);
681
682 auto ret = graph->CreateInstReturn(type, INVALID_PC, inst);
683 block->AppendInst(ret);
684 return graph;
685 }
686
GenerateBoundaryCheckOperation(Inst * inst)687 Graph *GraphCreator::GenerateBoundaryCheckOperation(Inst *inst)
688 {
689 auto graph = CreateGraphWithOneBasicBlock();
690 ASSERT(graph->GetVectorBlocks().size() > 2U);
691 auto block = graph->GetVectorBlocks()[2U];
692 auto param1 = CreateParamInst(graph, DataType::REFERENCE, 0U);
693 auto param2 = CreateParamInst(graph, DataType::UINT32, 1U);
694
695 auto saveState = static_cast<SaveStateInst *>(graph->CreateInstSaveState());
696 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
697 saveState->AppendInput(param1);
698 saveState->AppendInput(param2);
699 for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
700 saveState->SetVirtualRegister(i, VirtualRegister(i, VRegType::VREG));
701 }
702 block->AppendInst(saveState);
703
704 auto lenArr = graph->CreateInstLenArray(DataType::INT32, INVALID_PC, param1);
705 block->AppendInst(lenArr);
706 auto boundsCheck = static_cast<FixedInputsInst3 *>(inst);
707 boundsCheck->SetInput(0U, lenArr);
708 boundsCheck->SetType(DataType::INT32);
709 if (inst->GetOpcode() == Opcode::BoundsCheck) {
710 boundsCheck->SetInput(1U, param2);
711 boundsCheck->SetInput(2U, saveState);
712 } else {
713 boundsCheck->SetInput(1U, saveState);
714 }
715 block->AppendInst(boundsCheck);
716
717 Inst *ldArr = nullptr;
718 if (inst->GetOpcode() == Opcode::BoundsCheck) {
719 ldArr = graph->CreateInstLoadArray(DataType::UINT32, INVALID_PC, param1, boundsCheck);
720 } else {
721 ldArr = graph->CreateInstLoadArrayI(DataType::UINT32, INVALID_PC, param1, 1U);
722 }
723 block->AppendInst(ldArr);
724
725 auto ret = graph->CreateInstReturn(DataType::UINT32, INVALID_PC, ldArr);
726 block->AppendInst(ret);
727 SetNumVRegsArgs(0U, saveState->GetInputsCount());
728 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
729 return graph;
730 }
731
GenerateMultiArrayOperation(Inst * inst)732 Graph *GraphCreator::GenerateMultiArrayOperation(Inst *inst)
733 {
734 auto graph = CreateGraphWithOneBasicBlock();
735 ASSERT(graph->GetVectorBlocks().size() > 2U);
736 auto block = graph->GetVectorBlocks()[2U];
737 auto param1 = CreateParamInst(graph, DataType::INT32, 0U);
738 auto param2 = CreateParamInst(graph, DataType::INT32, 1U);
739
740 auto saveState = graph->CreateInstSaveState();
741 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
742 block->AppendInst(saveState);
743
744 auto initInst = graph->CreateInstLoadAndInitClass(DataType::REFERENCE, INVALID_PC, saveState,
745 TypeIdMixin {0U, nullptr}, nullptr);
746 auto arraysInst = inst->CastToMultiArray();
747 arraysInst->SetInputs(&allocator_, {{initInst, DataType::REFERENCE},
748 {param1, DataType::INT32},
749 {param2, DataType::INT32},
750 {saveState, DataType::NO_TYPE}});
751
752 block->AppendInst(initInst);
753 block->AppendInst(inst);
754 for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
755 saveState->SetVirtualRegister(i, VirtualRegister(i, VRegType::VREG));
756 }
757 SetNumVRegsArgs(0U, saveState->GetInputsCount());
758 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
759 return graph;
760 }
761
GenerateThrowOperation(Inst * inst)762 Graph *GraphCreator::GenerateThrowOperation(Inst *inst)
763 {
764 auto graph = CreateGraphWithOneBasicBlock();
765 ASSERT(graph->GetVectorBlocks().size() > 2U);
766 auto block = graph->GetVectorBlocks()[2U];
767 auto param1 = CreateParamInst(graph, DataType::REFERENCE, 0U);
768
769 auto saveState = graph->CreateInstSaveState();
770 saveState->SetMethod(reinterpret_cast<RuntimeInterface::MethodPtr>(runtime_.METHOD));
771 saveState->AppendInput(param1);
772 for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
773 saveState->SetVirtualRegister(i, VirtualRegister(i, VRegType::VREG));
774 }
775 SetNumVRegsArgs(0U, saveState->GetInputsCount());
776 graph->SetVRegsCount(saveState->GetInputsCount() + 1U);
777 block->AppendInst(saveState);
778
779 inst->SetInput(0U, param1);
780 inst->SetInput(1U, saveState);
781 block->AppendInst(inst);
782 return graph;
783 }
784
GeneratePhiOperation(Inst * inst)785 Graph *GraphCreator::GeneratePhiOperation(Inst *inst)
786 {
787 auto *phi = static_cast<PhiInst *>(inst);
788 auto graph = CreateGraphWithFourBasicBlock();
789 ASSERT(graph->GetVectorBlocks().size() == 6U);
790 auto param1 = CreateParamInst(graph, inst->GetType(), 0U);
791 auto param2 = CreateParamInst(graph, inst->GetType(), 1U);
792 auto param3 = CreateParamInst(graph, DataType::BOOL, 2U);
793 auto add = graph->CreateInstAdd();
794 auto sub = graph->CreateInstSub();
795 auto ifInst = graph->CreateInstIfImm(DataType::NO_TYPE, INVALID_PC, param3, 0U, DataType::BOOL, CC_NE);
796 graph->GetVectorBlocks()[2U]->AppendInst(ifInst);
797 if (inst->GetType() != DataType::REFERENCE) {
798 add->SetInput(0U, param1);
799 add->SetInput(1U, param2);
800 add->SetType(inst->GetType());
801 graph->GetVectorBlocks()[3U]->AppendInst(add);
802
803 sub->SetInput(0U, param1);
804 sub->SetInput(1U, param2);
805 sub->SetType(inst->GetType());
806 graph->GetVectorBlocks()[4U]->AppendInst(sub);
807
808 phi->AppendInput(add);
809 phi->AppendInput(sub);
810 } else {
811 phi->AppendInput(param1);
812 phi->AppendInput(param2);
813 }
814 graph->GetVectorBlocks()[5U]->AppendPhi(phi);
815 auto ret = graph->CreateInstReturn(phi->GetType(), INVALID_PC, phi);
816 graph->GetVectorBlocks()[5U]->AppendInst(ret);
817 return graph;
818 }
819
CreateGraphWithOneBasicBlock()820 Graph *GraphCreator::CreateGraphWithOneBasicBlock()
821 {
822 Graph *graph = CreateGraph();
823 auto entry = graph->CreateStartBlock();
824 auto exit = graph->CreateEndBlock();
825 auto block = graph->CreateEmptyBlock();
826 entry->AddSucc(block);
827 block->AddSucc(exit);
828 return graph;
829 }
830
CreateGraphWithTwoBasicBlock()831 Graph *GraphCreator::CreateGraphWithTwoBasicBlock()
832 {
833 Graph *graph = CreateGraph();
834 auto entry = graph->CreateStartBlock();
835 auto exit = graph->CreateEndBlock();
836 auto block1 = graph->CreateEmptyBlock();
837 auto block2 = graph->CreateEmptyBlock();
838 entry->AddSucc(block1);
839 block1->AddSucc(block2);
840 block2->AddSucc(exit);
841 return graph;
842 }
843
CreateGraphWithThreeBasicBlock()844 Graph *GraphCreator::CreateGraphWithThreeBasicBlock()
845 {
846 Graph *graph = CreateGraph();
847 auto entry = graph->CreateStartBlock();
848 auto exit = graph->CreateEndBlock();
849 auto blockMain = graph->CreateEmptyBlock();
850 auto blockTrue = graph->CreateEmptyBlock();
851 auto blockFalse = graph->CreateEmptyBlock();
852 auto ret1 = graph->CreateInstReturnVoid();
853 auto ret2 = graph->CreateInstReturnVoid();
854 blockTrue->AppendInst(ret1);
855 blockFalse->AppendInst(ret2);
856 entry->AddSucc(blockMain);
857 blockMain->AddSucc(blockTrue);
858 blockMain->AddSucc(blockFalse);
859 blockTrue->AddSucc(exit);
860 blockFalse->AddSucc(exit);
861 return graph;
862 }
863
CreateGraphWithFourBasicBlock()864 Graph *GraphCreator::CreateGraphWithFourBasicBlock()
865 {
866 Graph *graph = CreateGraph();
867 auto entry = graph->CreateStartBlock();
868 auto exit = graph->CreateEndBlock();
869 auto blockMain = graph->CreateEmptyBlock();
870 auto blockTrue = graph->CreateEmptyBlock();
871 auto blockFalse = graph->CreateEmptyBlock();
872 auto blockPhi = graph->CreateEmptyBlock();
873
874 entry->AddSucc(blockMain);
875 blockMain->AddSucc(blockTrue);
876 blockMain->AddSucc(blockFalse);
877 blockTrue->AddSucc(blockPhi);
878 blockFalse->AddSucc(blockPhi);
879 blockPhi->AddSucc(exit);
880 return graph;
881 }
882
CreateParamInst(Graph * graph,DataType::Type type,uint8_t slot)883 ParameterInst *GraphCreator::CreateParamInst(Graph *graph, DataType::Type type, uint8_t slot)
884 {
885 auto param = graph->CreateInstParameter(slot, type);
886 graph->GetStartBlock()->AppendInst(param);
887 return param;
888 }
889
890 template <class T>
GenerateOperations(Opcode opCode)891 std::vector<Inst *> &InstGenerator::GenerateOperations(Opcode opCode)
892 {
893 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
894 auto inst = Inst::New<T>(&allocator_, opCode);
895 inst->SetType(opcodeXPossibleTypes_[opCode][i]);
896 insts_.push_back(inst);
897 }
898 return insts_;
899 }
900
901 template <class T>
GenerateOperationsImm(Opcode opCode)902 std::vector<Inst *> &InstGenerator::GenerateOperationsImm(Opcode opCode)
903 {
904 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
905 auto inst = Inst::New<T>(&allocator_, opCode);
906 auto type = opcodeXPossibleTypes_[opCode][i];
907 inst->SetType(type);
908 inst->SetImm(type == DataType::REFERENCE ? 0U : 1U);
909 insts_.push_back(inst);
910 }
911 return insts_;
912 }
913
914 template <class T>
GenerateOperationsShiftedRegister(Opcode opCode)915 std::vector<Inst *> &InstGenerator::GenerateOperationsShiftedRegister(Opcode opCode)
916 {
917 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
918 for (auto &shiftType : opcodeXPossibleShiftTypes_[opCode]) {
919 auto inst = Inst::New<T>(&allocator_, opCode);
920 auto type = opcodeXPossibleTypes_[opCode][i];
921 inst->SetType(type);
922 inst->SetShiftType(shiftType);
923 inst->SetImm(type == DataType::REFERENCE ? 0U : 1U);
924 insts_.push_back(inst);
925 }
926 }
927 return insts_;
928 }
929
930 template <>
GenerateOperations(Opcode opCode)931 std::vector<Inst *> &InstGenerator::GenerateOperations<CallInst>(Opcode opCode)
932 {
933 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
934 auto inst = Inst::New<CallInst>(&allocator_, opCode);
935 inst->SetType(opcodeXPossibleTypes_[opCode][i]);
936 insts_.push_back(inst);
937 }
938 return insts_;
939 }
940
941 template <>
GenerateOperations(Opcode opCode)942 std::vector<Inst *> &InstGenerator::GenerateOperations<CastInst>(Opcode opCode)
943 {
944 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
945 auto inst = Inst::New<CastInst>(&allocator_, opCode);
946 inst->SetType(opcodeXPossibleTypes_[opCode][i]);
947 inst->CastToCast()->SetOperandsType(opcodeXPossibleTypes_[opCode][i]);
948 insts_.push_back(inst);
949 }
950 return insts_;
951 }
952
953 template <>
GenerateOperations(Opcode opCode)954 std::vector<Inst *> &InstGenerator::GenerateOperations<CompareInst>(Opcode opCode)
955 {
956 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
957 auto type = opcodeXPossibleTypes_[opCode][i];
958 for (int ccInt = ConditionCode::CC_FIRST; ccInt != ConditionCode::CC_LAST; ccInt++) {
959 auto cc = static_cast<ConditionCode>(ccInt);
960 if (type == DataType::REFERENCE && cc != ConditionCode::CC_NE) {
961 continue;
962 }
963 if (IsFloatType(type) && (cc == ConditionCode::CC_TST_EQ || cc == ConditionCode::CC_TST_NE)) {
964 continue;
965 }
966 auto inst = Inst::New<CompareInst>(&allocator_, opCode);
967 inst->SetType(DataType::BOOL);
968 inst->SetCc(cc);
969 inst->SetOperandsType(type);
970 insts_.push_back(inst);
971 }
972 }
973 return insts_;
974 }
975
976 template <>
GenerateOperations(Opcode opCode)977 std::vector<Inst *> &InstGenerator::GenerateOperations<CmpInst>(Opcode opCode)
978 {
979 auto inst = Inst::New<CmpInst>(&allocator_, opCode);
980 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
981 inst->SetOperandsType(DataType::FLOAT64);
982 inst->SetFcmpg();
983 insts_.push_back(inst);
984 inst = Inst::New<CmpInst>(&allocator_, opCode);
985 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
986 inst->SetOperandsType(DataType::FLOAT64);
987 inst->SetFcmpl();
988 insts_.push_back(inst);
989 return insts_;
990 }
991
992 template <>
GenerateOperations(Opcode opCode)993 std::vector<Inst *> &InstGenerator::GenerateOperations<IfInst>(Opcode opCode)
994 {
995 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
996 auto type = opcodeXPossibleTypes_[opCode][i];
997 for (int ccInt = ConditionCode::CC_FIRST; ccInt != ConditionCode::CC_LAST; ccInt++) {
998 auto cc = static_cast<ConditionCode>(ccInt);
999 if (type == DataType::REFERENCE && cc != ConditionCode::CC_NE) {
1000 continue;
1001 }
1002 auto inst = Inst::New<IfInst>(&allocator_, opCode);
1003 inst->SetCc(cc);
1004 inst->SetOperandsType(type);
1005 insts_.push_back(inst);
1006 }
1007 }
1008 return insts_;
1009 }
1010
1011 template <>
GenerateOperationsImm(Opcode opCode)1012 std::vector<Inst *> &InstGenerator::GenerateOperationsImm<IfImmInst>(Opcode opCode)
1013 {
1014 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
1015 auto type = opcodeXPossibleTypes_[opCode][i];
1016 for (int ccInt = ConditionCode::CC_FIRST; ccInt != ConditionCode::CC_LAST; ccInt++) {
1017 auto cc = static_cast<ConditionCode>(ccInt);
1018 if (type == DataType::REFERENCE && cc != ConditionCode::CC_NE && cc != ConditionCode::CC_EQ) {
1019 continue;
1020 }
1021 auto inst = Inst::New<IfImmInst>(&allocator_, opCode);
1022 inst->SetCc(cc);
1023 inst->SetOperandsType(type);
1024 inst->SetImm(type == DataType::REFERENCE ? 0U : 1U);
1025 insts_.push_back(inst);
1026 }
1027 }
1028 return insts_;
1029 }
1030
SetFlagsNoCseNoHoistIfReference(Inst * inst,DataType::Type dstType)1031 void InstGenerator::SetFlagsNoCseNoHoistIfReference(Inst *inst, DataType::Type dstType)
1032 {
1033 if (dstType == DataType::REFERENCE) {
1034 inst->SetFlag(inst_flags::NO_CSE);
1035 inst->SetFlag(inst_flags::NO_HOIST);
1036 }
1037 }
1038
1039 template <>
GenerateOperations(Opcode opCode)1040 std::vector<Inst *> &InstGenerator::GenerateOperations<SelectInst>(Opcode opCode)
1041 {
1042 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
1043 auto cmpType = opcodeXPossibleTypes_[opCode][i];
1044 for (int ccInt = ConditionCode::CC_FIRST; ccInt != ConditionCode::CC_LAST; ccInt++) {
1045 auto cc = static_cast<ConditionCode>(ccInt);
1046 if (cmpType == DataType::REFERENCE && cc != ConditionCode::CC_NE && cc != ConditionCode::CC_EQ) {
1047 continue;
1048 }
1049 for (size_t j = 0; j < opcodeXPossibleTypes_[opCode].size(); ++j) {
1050 auto dstType = opcodeXPossibleTypes_[opCode][j];
1051 auto inst = Inst::New<SelectInst>(&allocator_, opCode);
1052 inst->SetOperandsType(cmpType);
1053 inst->SetType(dstType);
1054 inst->SetCc(cc);
1055 SetFlagsNoCseNoHoistIfReference(inst, dstType);
1056 insts_.push_back(inst);
1057 }
1058 }
1059 }
1060 return insts_;
1061 }
1062
1063 template <>
GenerateOperationsImm(Opcode opCode)1064 std::vector<Inst *> &InstGenerator::GenerateOperationsImm<SelectImmInst>(Opcode opCode)
1065 {
1066 for (size_t i = 0; i < opcodeXPossibleTypes_[opCode].size(); ++i) {
1067 auto cmpType = opcodeXPossibleTypes_[opCode][i];
1068 for (int ccInt = ConditionCode::CC_FIRST; ccInt != ConditionCode::CC_LAST; ccInt++) {
1069 auto cc = static_cast<ConditionCode>(ccInt);
1070 if (cmpType == DataType::REFERENCE && cc != ConditionCode::CC_NE && cc != ConditionCode::CC_EQ) {
1071 continue;
1072 }
1073 for (size_t j = 0; j < opcodeXPossibleTypes_[opCode].size(); ++j) {
1074 auto dstType = opcodeXPossibleTypes_[opCode][j];
1075 auto inst = Inst::New<SelectImmInst>(&allocator_, opCode);
1076 inst->SetOperandsType(cmpType);
1077 inst->SetType(dstType);
1078 inst->SetCc(cc);
1079 inst->SetImm(cmpType == DataType::REFERENCE ? 0U : 1U);
1080 SetFlagsNoCseNoHoistIfReference(inst, dstType);
1081 insts_.push_back(inst);
1082 }
1083 }
1084 }
1085 return insts_;
1086 }
1087
1088 template <>
GenerateOperations(Opcode opCode)1089 std::vector<Inst *> &InstGenerator::GenerateOperations<SpillFillInst>(Opcode opCode)
1090 {
1091 auto inst = Inst::New<SpillFillInst>(&allocator_, opCode);
1092 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
1093 inst->AddSpill(0U, 2U, DataType::UINT64);
1094 insts_.push_back(inst);
1095
1096 inst = Inst::New<SpillFillInst>(&allocator_, opCode);
1097 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
1098 inst->AddFill(0U, 2U, DataType::UINT64);
1099 insts_.push_back(inst);
1100
1101 inst = Inst::New<SpillFillInst>(&allocator_, opCode);
1102 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
1103 inst->AddMove(0U, 2U, DataType::UINT64);
1104 insts_.push_back(inst);
1105
1106 inst = Inst::New<SpillFillInst>(&allocator_, opCode);
1107 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
1108 inst->AddMemCopy(0U, 2U, DataType::UINT64);
1109 insts_.push_back(inst);
1110 return insts_;
1111 }
1112
1113 template <>
GenerateOperations(Opcode opCode)1114 std::vector<Inst *> &InstGenerator::GenerateOperations<MonitorInst>(Opcode opCode)
1115 {
1116 auto inst = Inst::New<MonitorInst>(&allocator_, opCode);
1117 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
1118 inst->SetEntry();
1119 insts_.push_back(inst);
1120
1121 inst = Inst::New<MonitorInst>(&allocator_, opCode);
1122 inst->SetType(opcodeXPossibleTypes_[opCode][0U]);
1123 inst->SetExit();
1124 insts_.push_back(inst);
1125
1126 return insts_;
1127 }
1128
1129 #include "generate_operations_intrinsic_inst.inl"
1130
1131 // CC-OFFNXT(huge_method, huge_cyclomatic_complexity, G.FUN.01) big switch-case
Generate(Opcode opCode)1132 std::vector<Inst *> &InstGenerator::Generate(Opcode opCode)
1133 {
1134 insts_.clear();
1135 switch (opCode) {
1136 case Opcode::Neg:
1137 case Opcode::Abs:
1138 case Opcode::Not:
1139 return GenerateOperations<UnaryOperation>(opCode);
1140 case Opcode::Add:
1141 case Opcode::Sub:
1142 case Opcode::Mul:
1143 case Opcode::Div:
1144 case Opcode::Mod:
1145 case Opcode::Min:
1146 case Opcode::Max:
1147 case Opcode::Shl:
1148 case Opcode::Shr:
1149 case Opcode::AShr:
1150 case Opcode::And:
1151 case Opcode::Or:
1152 case Opcode::Xor:
1153 case Opcode::AndNot:
1154 case Opcode::OrNot:
1155 case Opcode::XorNot:
1156 case Opcode::MNeg:
1157 return GenerateOperations<BinaryOperation>(opCode);
1158 case Opcode::Compare:
1159 return GenerateOperations<CompareInst>(opCode);
1160 case Opcode::Constant:
1161 return GenerateOperations<ConstantInst>(opCode);
1162 case Opcode::NewObject:
1163 return GenerateOperations<NewObjectInst>(opCode);
1164 case Opcode::If:
1165 return GenerateOperations<IfInst>(opCode);
1166 case Opcode::IfImm:
1167 return GenerateOperationsImm<IfImmInst>(opCode);
1168 case Opcode::IsInstance:
1169 return GenerateOperations<IsInstanceInst>(opCode);
1170 case Opcode::LenArray:
1171 return GenerateOperations<LengthMethodInst>(opCode);
1172 case Opcode::Return:
1173 case Opcode::ReturnInlined:
1174 return GenerateOperations<FixedInputsInst1>(opCode);
1175 case Opcode::NewArray:
1176 return GenerateOperations<NewArrayInst>(opCode);
1177 case Opcode::Cmp:
1178 return GenerateOperations<CmpInst>(opCode);
1179 case Opcode::CheckCast:
1180 return GenerateOperations<CheckCastInst>(opCode);
1181 case Opcode::NullCheck:
1182 case Opcode::ZeroCheck:
1183 case Opcode::NegativeCheck:
1184 return GenerateOperations<FixedInputsInst2>(opCode);
1185 case Opcode::Throw:
1186 return GenerateOperations<ThrowInst>(opCode);
1187 case Opcode::BoundsCheck:
1188 case Opcode::MAdd:
1189 case Opcode::MSub:
1190 return GenerateOperations<FixedInputsInst3>(opCode);
1191 case Opcode::Parameter:
1192 return GenerateOperations<ParameterInst>(opCode);
1193 case Opcode::LoadArray:
1194 return GenerateOperations<LoadInst>(opCode);
1195 case Opcode::StoreArray:
1196 return GenerateOperations<StoreInst>(opCode);
1197 case Opcode::LoadArrayI:
1198 return GenerateOperationsImm<LoadInstI>(opCode);
1199 case Opcode::StoreArrayI:
1200 return GenerateOperationsImm<StoreInstI>(opCode);
1201 case Opcode::NullPtr:
1202 case Opcode::ReturnVoid:
1203 return GenerateOperations<FixedInputsInst0>(opCode);
1204 case Opcode::SaveState:
1205 case Opcode::SafePoint:
1206 return GenerateOperations<SaveStateInst>(opCode);
1207 case Opcode::Phi:
1208 return GenerateOperations<PhiInst>(opCode);
1209 case Opcode::CallStatic:
1210 case Opcode::CallVirtual:
1211 return GenerateOperations<CallInst>(opCode);
1212 case Opcode::Monitor:
1213 return GenerateOperations<MonitorInst>(opCode);
1214 case Opcode::AddI:
1215 case Opcode::SubI:
1216 case Opcode::ShlI:
1217 case Opcode::ShrI:
1218 case Opcode::AShrI:
1219 case Opcode::AndI:
1220 case Opcode::OrI:
1221 case Opcode::XorI:
1222 return GenerateOperationsImm<BinaryImmOperation>(opCode);
1223 case Opcode::AndSR:
1224 case Opcode::SubSR:
1225 case Opcode::AddSR:
1226 case Opcode::OrSR:
1227 case Opcode::XorSR:
1228 case Opcode::AndNotSR:
1229 case Opcode::OrNotSR:
1230 case Opcode::XorNotSR:
1231 return GenerateOperationsShiftedRegister<BinaryShiftedRegisterOperation>(opCode);
1232 case Opcode::NegSR:
1233 return GenerateOperationsShiftedRegister<UnaryShiftedRegisterOperation>(opCode);
1234 case Opcode::SpillFill:
1235 return GenerateOperations<SpillFillInst>(opCode);
1236 case Opcode::LoadObject:
1237 return GenerateOperations<LoadObjectInst>(opCode);
1238 case Opcode::StoreObject:
1239 return GenerateOperations<StoreObjectInst>(opCode);
1240 case Opcode::LoadStatic:
1241 return GenerateOperations<LoadStaticInst>(opCode);
1242 case Opcode::StoreStatic:
1243 return GenerateOperations<StoreStaticInst>(opCode);
1244 case Opcode::LoadString:
1245 case Opcode::LoadType:
1246 return GenerateOperations<LoadFromPool>(opCode);
1247 case Opcode::BoundsCheckI:
1248 return GenerateOperationsImm<BoundsCheckInstI>(opCode);
1249 case Opcode::ReturnI:
1250 return GenerateOperationsImm<ReturnInstI>(opCode);
1251 case Opcode::Intrinsic:
1252 return GenerateOperations<IntrinsicInst>(opCode);
1253 case Opcode::Select:
1254 return GenerateOperations<SelectInst>(opCode);
1255 case Opcode::SelectImm:
1256 return GenerateOperationsImm<SelectImmInst>(opCode);
1257 case Opcode::LoadArrayPair:
1258 return GenerateOperations<LoadArrayPairInst>(opCode);
1259 case Opcode::LoadArrayPairI:
1260 return GenerateOperationsImm<LoadArrayPairInstI>(opCode);
1261 case Opcode::StoreArrayPair:
1262 return GenerateOperations<StoreArrayPairInst>(opCode);
1263 case Opcode::StoreArrayPairI:
1264 return GenerateOperationsImm<StoreArrayPairInstI>(opCode);
1265 case Opcode::Cast:
1266 return GenerateOperations<CastInst>(opCode);
1267 case Opcode::Builtin:
1268 ASSERT_DO(0U, std::cerr << "Unexpected Opcode Builtin\n");
1269 return insts_;
1270 default:
1271 ASSERT_DO(0U, std::cerr << GetOpcodeString(opCode) << "\n");
1272 return insts_;
1273 }
1274 }
1275
1276 constexpr std::array<const char *, 15U> LABELS = {"NO_TYPE", "REF", "BOOL", "UINT8", "INT8",
1277 "UINT16", "INT16", "UINT32", "INT32", "UINT64",
1278 "INT64", "FLOAT32", "FLOAT64", "ANY", "VOID"};
1279
FillHTMLPageHeadPart(std::ofstream & htmlPage)1280 void StatisticGenerator::FillHTMLPageHeadPart(std::ofstream &htmlPage)
1281 {
1282 htmlPage << "<!DOCTYPE html>\n"
1283 << "<html>\n"
1284 << "<head>\n"
1285 << "\t<style>table, th, td {border: 1px solid black; border-collapse: collapse;}</style>\n"
1286 << "\t<title>Codegen coverage statistic</title>\n"
1287 << "</head>\n"
1288 << "<body>\n"
1289 << "\t<header><h1>Codegen coverage statistic</h1></header>"
1290 << "\t<h3>Legend</h3>"
1291 << "\t<table style=\"width:300px%\">\n"
1292 << "\t\t<tr><th align=\"left\">Codegen successfully translate IR</th><td align=\"center\""
1293 << "bgcolor=\"#00fd00\" width=\"90px\">+</td></tr>\n"
1294 << "\t\t<tr><th align=\"left\">Codegen UNsuccessfully translate IR</th><td align=\"center\""
1295 << "bgcolor=\"#fd0000\">-</td></tr>\n"
1296 << "\t\t<tr><th align=\"left\">IR does't support instruction with this type </th><td></td></tr>\n"
1297 << "\t\t<tr><th align=\"left\">Test generator not implement for this opcode</th><td "
1298 << "bgcolor=\"#808080\"></td></tr>\n"
1299 << "\t</table>\n"
1300 << "\t<br>\n"
1301 << "\t<h3>Summary information</h3>\n"
1302 << "\t<table>\n"
1303 << "\t\t<tr><th>Positive tests</th><td>" << positiveInstNumber_ << "</td></tr>\n"
1304 << "\t\t<tr><th>All generated tests</th><td>" << allInstNumber_ << "</td></tr>\n"
1305 << "\t\t<tr><th></th><td>" << positiveInstNumber_ * 100.0F / allInstNumber_ << "%</td></tr>\n"
1306 << "\t</table>\n"
1307 << "\t<br>\n"
1308 << "\t<table>"
1309 << "\t\t<tr><th align=\"left\">Number of opcodes for which tests were generated</th><td>"
1310 << implementedOpcodeNumber_ << "</td></tr>"
1311 << "\t\t<tr><th align=\"left\">Full number of opcodes</th><td>" << allOpcodeNumber_ << "</td></tr>"
1312 << "\t\t<tr><th></th><td>" << implementedOpcodeNumber_ * 100.0F / allOpcodeNumber_ << "%</td></tr>"
1313 << "\t</table>\n"
1314 << "\t<h3>Detailed information</h3>"
1315 << "\t\t<table>"
1316 << "\t\t<tr><th>Opcode\\Type</th>";
1317 }
1318
FillHTMLPageOpcodeStatistic(std::ofstream & htmlPage,Opcode opc)1319 void StatisticGenerator::FillHTMLPageOpcodeStatistic(std::ofstream &htmlPage, Opcode opc)
1320 {
1321 htmlPage << "\t\t<tr>";
1322 htmlPage << "<th>" << GetOpcodeString(opc) << "</th>";
1323 if (statistic_.first.find(opc) != statistic_.first.end()) {
1324 auto item = statistic_.first[opc];
1325 int positivCount = 0;
1326 int negativCount = 0;
1327 for (auto &j : item) {
1328 std::string flag;
1329 std::string color;
1330 switch (j.second) {
1331 case 0U:
1332 flag = "-";
1333 color = "bgcolor=\"#fd0000\"";
1334 negativCount++;
1335 break;
1336 case 1U:
1337 flag = "+";
1338 color = "bgcolor=\"#00fd00\"";
1339 positivCount++;
1340 break;
1341 default:
1342 break;
1343 }
1344 htmlPage << "<td align=\"center\" " << color << ">" << flag << "</td>";
1345 }
1346 if (positivCount + negativCount != 0U) {
1347 htmlPage << "<td align=\"right\">" << positivCount * 100.0F / (positivCount + negativCount) << "</td>";
1348 }
1349 } else {
1350 for (auto j = tmplt_.begin(); j != tmplt_.end(); ++j) {
1351 htmlPage << R"(<td align=" center " bgcolor=" #808080"></td>)";
1352 }
1353 htmlPage << "<td align=\"right\">0</td>";
1354 }
1355 htmlPage << "</tr>\n";
1356 }
1357
GenerateHTMLPage(const std::string & fileName)1358 void StatisticGenerator::GenerateHTMLPage(const std::string &fileName)
1359 {
1360 std::ofstream htmlPage;
1361 htmlPage.open(fileName);
1362 FillHTMLPageHeadPart(htmlPage);
1363 for (auto label : LABELS) {
1364 htmlPage << "<th style=\"width:90px\">" << label << "</th>";
1365 }
1366 htmlPage << "<th>%</th>";
1367 htmlPage << "<tr>\n";
1368 for (auto i = 0; i != static_cast<int>(Opcode::NUM_OPCODES); ++i) {
1369 auto opc = static_cast<Opcode>(i);
1370 if (opc == Opcode::NOP || opc == Opcode::Intrinsic || opc == Opcode::LoadPairPart) {
1371 continue;
1372 }
1373 FillHTMLPageOpcodeStatistic(htmlPage, opc);
1374 }
1375 htmlPage << "\t</table>\n";
1376
1377 htmlPage << "\t<h3>Intrinsics</h3>\n";
1378 htmlPage << "\t<table>\n";
1379 htmlPage << "\t\t<tr><th>IntrinsicId</th><th>Status</th></tr>";
1380 for (auto i = 0; i != static_cast<int>(RuntimeInterface::IntrinsicId::COUNT); ++i) {
1381 auto intrinsicId = static_cast<RuntimeInterface::IntrinsicId>(i);
1382 auto intrinsicName = GetIntrinsicName(intrinsicId);
1383 if (intrinsicName.empty()) {
1384 continue;
1385 }
1386 htmlPage << "<tr><th>" << intrinsicName << "</th>";
1387 if (statistic_.second.find(intrinsicId) != statistic_.second.end()) {
1388 std::string flag;
1389 std::string color;
1390 if (statistic_.second[intrinsicId]) {
1391 flag = "+";
1392 color = "bgcolor=\"#00fd00\"";
1393 } else {
1394 flag = "-";
1395 color = "bgcolor=\"#fd0000\"";
1396 }
1397 htmlPage << "<td align=\"center\" " << color << ">" << flag << "</td></tr>";
1398 } else {
1399 htmlPage << R"(<td align=" center " bgcolor=" #808080"></td></tr>)";
1400 }
1401 htmlPage << "\n";
1402 }
1403 htmlPage << "</table>\n";
1404 htmlPage << "</body>\n"
1405 << "</html>";
1406 htmlPage.close();
1407 }
1408 } // namespace ark::compiler
1409