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