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