• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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