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