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