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