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