/** * Copyright (c) 2024-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ir_static.h" #include "datatype.h" #include "libabckit/include/c/ir_core.h" #include "libabckit/include/c/statuses.h" #include "libabckit/src/adapter_static/helpers_static.h" #include "libabckit/include/c/metadata_core.h" #include "libabckit/src/statuses_impl.h" #include "libabckit/src/macros.h" #include "libabckit/src/metadata_inspect_impl.h" #include "libabckit/src/helpers_common.h" #include "libabckit/src/ir_impl.h" #include "libabckit/src/wrappers/pandasm_wrapper.h" #include "static_core/assembler/assembly-program.h" #include "static_core/assembler/mangling.h" #include "static_core/compiler/optimizer/ir/graph.h" #include "static_core/compiler/optimizer/ir/basicblock.h" #include "static_core/compiler/optimizer/ir/inst.h" #include "static_core/compiler/optimizer/analysis/loop_analyzer.h" #include "generated/insn_info.h" #include "abckit_intrinsics_opcodes.inc" #include #include namespace libabckit { #include "inst_props_helpers_dynamic.inc" // helpers for getting inst operand's info // for dynamic insts helpers are autogenerated by inst_props_helpers_dynamic.inc.erb static bool HasMethodIdOperandStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_INITOBJECT: case ABCKIT_ISA_API_STATIC_OPCODE_CALL_STATIC: case ABCKIT_ISA_API_STATIC_OPCODE_CALL_VIRTUAL: return true; default: return false; } } static int GetMethodIdOperandIndexStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_INITOBJECT: case ABCKIT_ISA_API_STATIC_OPCODE_CALL_STATIC: case ABCKIT_ISA_API_STATIC_OPCODE_CALL_VIRTUAL: return 0; default: return 0; } } static bool HasStringIdOperandStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_LOADSTRING: return true; default: return false; } } static int GetStringIdOperandIndexStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_LOADSTRING: return 0; default: return 0; } } static bool HasLiteralArrayIdOperandStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_LOADCONSTARRAY: return true; default: return false; } } static int GetLiteralArrayIdOperandIndexStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_LOADCONSTARRAY: return 0; default: return 0; } } [[maybe_unused]] static bool HasTypeIdOperandStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_NEWARRAY: case ABCKIT_ISA_API_STATIC_OPCODE_NEWOBJECT: case ABCKIT_ISA_API_STATIC_OPCODE_CHECKCAST: case ABCKIT_ISA_API_STATIC_OPCODE_ISINSTANCE: return true; default: return false; } } [[maybe_unused]] static int GetTypeIdOperandIndexStatic(AbckitIsaApiStaticOpcode opcode) { switch (opcode) { case ABCKIT_ISA_API_STATIC_OPCODE_NEWARRAY: case ABCKIT_ISA_API_STATIC_OPCODE_NEWOBJECT: case ABCKIT_ISA_API_STATIC_OPCODE_CHECKCAST: case ABCKIT_ISA_API_STATIC_OPCODE_ISINSTANCE: return 0; default: return -1; } } // ======================================== // Api for Graph manipulation // ======================================== AbckitInst *GfindOrCreateConstantI64Static(AbckitGraph *graph, int64_t value) { LIBABCKIT_LOG_FUNC; if (graph == nullptr) { LIBABCKIT_LOG(DEBUG) << "nullptr argument\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto constantI64Impl = graph->impl->FindOrCreateConstant(value); return CreateInstFromImpl(graph, constantI64Impl); } AbckitInst *GfindOrCreateConstantI32Static(AbckitGraph *graph, int32_t value) { LIBABCKIT_LOG_FUNC; if (graph == nullptr) { LIBABCKIT_LOG(DEBUG) << "nullptr argument\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto constantI32Impl = graph->impl->FindOrCreateConstant(value); return CreateInstFromImpl(graph, constantI32Impl); } AbckitInst *GfindOrCreateConstantU64Static(AbckitGraph *graph, uint64_t value) { LIBABCKIT_LOG_FUNC; if (graph == nullptr) { LIBABCKIT_LOG(DEBUG) << "nullptr argument\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto constantU64Impl = graph->impl->FindOrCreateConstant(value); return CreateInstFromImpl(graph, constantU64Impl); } AbckitInst *GfindOrCreateConstantF64Static(AbckitGraph *graph, double value) { LIBABCKIT_LOG_FUNC; // check inputs are valid if (graph == nullptr) { LIBABCKIT_LOG(DEBUG) << "nullptr argument\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto constantF64Impl = graph->impl->FindOrCreateConstant(value); return CreateInstFromImpl(graph, constantF64Impl); } uint32_t GgetNumberOfBasicBlocksStatic(AbckitGraph *graph) { LIBABCKIT_LOG_FUNC; if (graph == nullptr) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return 0; } return graph->impl->GetVectorBlocks().size(); } AbckitBasicBlock *GgetBasicBlockStatic(AbckitGraph *graph, uint32_t id) { LIBABCKIT_LOG_FUNC; if (graph == nullptr) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } if (id >= graph->impl->GetVectorBlocks().size()) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *bbImpl = graph->impl->GetVectorBlocks()[id]; return graph->implToBB.at(bbImpl); } uint32_t GgetNumberOfParametersStatic(AbckitGraph *graph) { auto list = graph->impl->GetParameters(); auto ins = list.begin(); uint32_t size = 0; while (ins != list.end()) { ++ins; ++size; } return size; } AbckitInst *GgetParameterStatic(AbckitGraph *graph, uint32_t index) { LIBABCKIT_LOG_FUNC; if (graph == nullptr) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } if (index >= GgetNumberOfParametersStatic(graph)) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto list = graph->impl->GetParameters(); auto ins = list.begin(); for (uint32_t i = 0; i < index; i++) { if (ins != list.end()) { ++ins; } } return graph->implToInst.at(*ins); } void SetTryBlocks(AbckitGraph *graph, AbckitBasicBlock *tryLastBB, AbckitBasicBlock *tryBeginBB, AbckitBasicBlock *tryEndBB) { tryBeginBB->impl->SetTryBegin(true); tryBeginBB->impl->SetTryId(tryBeginBB->impl->GetId()); graph->impl->AppendTryBeginBlock(tryBeginBB->impl); AbckitInst *tryInst = IcreateTryStatic(graph); BBaddInstFrontStatic(tryBeginBB, tryInst); tryEndBB->impl->SetTryEnd(true); tryEndBB->impl->SetTryId(tryBeginBB->impl->GetTryId()); // NOTE(nsizov): NOTE, calculate guest pc for new created blocks (abckit-wise problem) tryEndBB->impl->SetGuestPc(tryLastBB->impl->GetGuestPc() - 1); tryInst->impl->CastToTry()->SetTryEndBlock(tryEndBB->impl); // NOTE(nsizov): NOTE, set proper typeid for catch blocks (abckit-wise problem) tryInst->impl->CastToTry()->AppendCatchTypeId(0, 1); } struct VisitorData { AbckitBasicBlock *cur; AbckitBasicBlock *tryBegin; AbckitBasicBlock *tryEnd; AbckitBasicBlock *catchEnd; std::unordered_set *visited; std::queue *toVisit; }; void VisitBbs(AbckitBasicBlock *tryFirstBB, AbckitBasicBlock *tryLastBB, AbckitBasicBlock *catchBeginBB, AbckitBasicBlock *tryBeginBB, std::unordered_set *visited, std::queue *toVisit, VisitorData visitorData) { visitorData.cur = tryFirstBB; // A data to pass into visitors traverse BBvisitPredBlocksStatic(tryFirstBB, &visitorData, [](AbckitBasicBlock *predBasicBlock, void *data) { AbckitBasicBlock *curBasicBlock = static_cast(data)->cur; AbckitBasicBlock *tryBeginBB = static_cast(data)->tryBegin; predBasicBlock->impl->ReplaceSucc(curBasicBlock->impl, tryBeginBB->impl); curBasicBlock->impl->RemovePred(predBasicBlock->impl); return true; }); BBappendSuccBlockStatic(tryBeginBB, tryFirstBB); BBappendSuccBlockStatic(tryBeginBB, catchBeginBB); visitorData.cur = tryLastBB; BBvisitPredBlocksStatic(tryLastBB, &visitorData, [](AbckitBasicBlock *predBasicBlock, void *data) { AbckitBasicBlock *curBasicBlock = static_cast(data)->cur; AbckitBasicBlock *tryEndBB = static_cast(data)->tryEnd; predBasicBlock->impl->ReplaceSucc(curBasicBlock->impl, tryEndBB->impl); curBasicBlock->impl->RemovePred(predBasicBlock->impl); return true; }); toVisit->push(tryBeginBB); while (!(*toVisit).empty()) { AbckitBasicBlock *curBB = toVisit->front(); visitorData.cur = curBB; toVisit->pop(); visited->insert(curBB); curBB->impl->SetTry(true); curBB->impl->SetTryId(tryBeginBB->impl->GetTryId()); BBvisitSuccBlocksStatic(curBB, &visitorData, [](AbckitBasicBlock *succBasicBlock, void *data) { if (succBasicBlock->impl->IsTryEnd() || succBasicBlock->impl->IsCatchBegin() || succBasicBlock->impl->IsEndBlock()) { return false; } auto *visited = static_cast(data)->visited; auto *toVisit = static_cast(data)->toVisit; auto it = visited->find(succBasicBlock); if (it == visited->end()) { toVisit->push(succBasicBlock); } return true; }); } } bool CheckCatchEnv(AbckitBasicBlock *tryFirstBB, AbckitBasicBlock *tryLastBB) { // NOTE(nsizov): check input for dominance tryFirstBB -> tryLastBB // and catchBeginBB -> catchEndBB if (BBisStartStatic(tryFirstBB) || BBisEndStatic(tryFirstBB)) { LIBABCKIT_LOG(DEBUG) << "tryFirstBB cannot be niether 'start' nor 'end' block"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return false; } if (BBisStartStatic(tryLastBB) || BBisEndStatic(tryLastBB)) { LIBABCKIT_LOG(DEBUG) << "tryLastBB cannot be niether 'start' nor 'end' block"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return false; } return true; } void GinsertTryCatchStatic(AbckitBasicBlock *tryFirstBB, AbckitBasicBlock *tryLastBB, AbckitBasicBlock *catchBeginBB, AbckitBasicBlock *catchEndBB) { LIBABCKIT_LOG_FUNC; if (!CheckCatchEnv(tryFirstBB, tryLastBB)) { return; } AbckitGraph *graph = tryFirstBB->graph; // NOTE(nsizov): implement for static mode as well if (!IsDynamic(graph->function->owningModule->target)) { libabckit::statuses::SetLastError(ABCKIT_STATUS_WRONG_TARGET); return; } if ((graph != tryLastBB->graph) || (graph != catchBeginBB->graph) || (graph != catchEndBB->graph)) { SetLastError(ABCKIT_STATUS_WRONG_CTX); return; } AbckitBasicBlock *tryBeginBB = BBcreateEmptyStatic(graph); AbckitBasicBlock *tryEndBB = BBcreateEmptyStatic(graph); SetTryBlocks(graph, tryLastBB, tryBeginBB, tryEndBB); catchBeginBB->impl->SetCatchBegin(true); if (catchBeginBB != catchEndBB) { catchEndBB->impl->SetCatch(true); } std::unordered_set visited; std::queue toVisit; auto visitorData = VisitorData {nullptr, tryBeginBB, tryEndBB, catchEndBB, &visited, &toVisit}; VisitBbs(tryFirstBB, tryLastBB, catchBeginBB, tryBeginBB, &visited, &toVisit, visitorData); visited.erase(visited.begin(), visited.end()); std::queue().swap(toVisit); while (!toVisit.empty()) { AbckitBasicBlock *curBB = toVisit.front(); toVisit.pop(); visited.insert(curBB); curBB->impl->SetCatch(true); curBB->impl->SetTryId(tryBeginBB->impl->GetTryId()); BBvisitSuccBlocksStatic(curBB, &visitorData, [](AbckitBasicBlock *succBasicBlock, void *data) { auto catchEndBB = static_cast(data)->catchEnd; // NOTE(ivagin) if (succBasicBlock->impl->IsCatchEnd() if (succBasicBlock == catchEndBB || succBasicBlock->impl->IsTry()) { return false; } auto *visited = static_cast(data)->visited; auto *toVisit = static_cast(data)->toVisit; if (visited->find(succBasicBlock) == visited->end()) { toVisit->push(succBasicBlock); } return true; }); } BBappendSuccBlockStatic(tryEndBB, tryLastBB); BBappendSuccBlockStatic(tryEndBB, catchBeginBB); BBappendSuccBlockStatic(catchEndBB, tryLastBB); } AbckitBasicBlock *GgetStartBasicBlockStatic(AbckitGraph *graph) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(graph, nullptr); ark::compiler::BasicBlock *bbImpl = graph->impl->GetStartBlock(); auto *bb = graph->implToBB.at(bbImpl); return bb; } AbckitBasicBlock *GgetEndBasicBlockStatic(AbckitGraph *graph) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(graph, nullptr); ark::compiler::BasicBlock *bbImpl = graph->impl->GetEndBlock(); auto *bb = graph->implToBB.at(bbImpl); return bb; } void IdumpStatic(AbckitInst *inst, int fd) { LIBABCKIT_LOG_FUNC; std::stringstream ss; inst->impl->Dump(&ss); write(fd, ss.str().data(), ss.str().size()); } void GdumpStatic(AbckitGraph *graph, int fd) { LIBABCKIT_LOG_FUNC; if (GraphHasUnreachableBlocks(graph->impl)) { LIBABCKIT_LOG(DEBUG) << "Cannot dump, there are unreachable blocks in graph\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } std::stringstream ss; graph->impl->Dump(&ss); write(fd, ss.str().data(), ss.str().size()); } void GrunPassRemoveUnreachableBlocksStatic(AbckitGraph *graph) { LIBABCKIT_LOG_FUNC; graph->impl->RemoveUnreachableBlocks(); GraphInvalidateAnalyses(graph->impl); } bool GvisitBlocksRPOStatic(AbckitGraph *graph, void *data, bool (*cb)(AbckitBasicBlock *bb, void *data)) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(graph, false) LIBABCKIT_BAD_ARGUMENT(cb, false) if (GraphHasUnreachableBlocks(graph->impl)) { LIBABCKIT_LOG(DEBUG) << "Cannot get blocks RPO, there are unreachable blocks in graph\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return false; } std::stringstream ss; for (auto *bbImpl : graph->impl->GetBlocksRPO()) { auto *bb = graph->implToBB.at(bbImpl); if (!cb(bb, data)) { return false; } } return true; } // ======================================== // Api for basic block manipulation // ======================================== bool BBvisitSuccBlocksStatic(AbckitBasicBlock *curBasicBlock, void *data, bool (*cb)(AbckitBasicBlock *succBasicBlock, void *data)) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(curBasicBlock, false) LIBABCKIT_BAD_ARGUMENT(cb, false) auto *graph = curBasicBlock->graph; auto *bbImpl = curBasicBlock->impl; auto succImpls = bbImpl->GetSuccsBlocks(); for (auto *succImpl : succImpls) { auto *succ = graph->implToBB.at(succImpl); if (!cb(succ, data)) { return false; } } return true; } bool BBvisitPredBlocksStatic(AbckitBasicBlock *curBasicBlock, void *data, bool (*cb)(AbckitBasicBlock *succBasicBlock, void *data)) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(curBasicBlock, false) LIBABCKIT_BAD_ARGUMENT(cb, false) auto *graph = curBasicBlock->graph; auto *bbImpl = curBasicBlock->impl; auto predImpls = bbImpl->GetPredsBlocks(); for (auto *predImpl : predImpls) { auto *pred = graph->implToBB.at(predImpl); if (!cb(pred, data)) { return false; } } return true; } AbckitBasicBlock *BBcreateEmptyStatic(AbckitGraph *graph) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(graph, nullptr); auto *bbImpl = graph->impl->CreateEmptyBlock(0U); auto *bb = graph->impl->GetLocalAllocator()->New(); bb->graph = graph; bb->impl = bbImpl; graph->implToBB.insert({bbImpl, bb}); GraphInvalidateAnalyses(graph->impl); return bb; } void BBaddInstFrontStatic(AbckitBasicBlock *basicBlock, AbckitInst *inst) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(basicBlock) LIBABCKIT_BAD_ARGUMENT_VOID(inst) LIBABCKIT_WRONG_CTX_VOID(basicBlock->graph, inst->graph); if (inst->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "can't use constant instruction as an argument"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } basicBlock->impl->PrependInst(inst->impl); } AbckitBasicBlock *BBsplitBlockAfterInstructionStatic(AbckitBasicBlock *basicBlock, AbckitInst *inst, bool makeEdge) { LIBABCKIT_BAD_ARGUMENT(basicBlock, nullptr); LIBABCKIT_BAD_ARGUMENT(inst, nullptr); auto *bbImpl = inst->impl->GetBasicBlock(); auto *newBbImpl = bbImpl->SplitBlockAfterInstruction(inst->impl, makeEdge); auto *iBb = IgetBasicBlockStatic(inst); if (iBb != basicBlock) { LIBABCKIT_LOG(DEBUG) << "Instruction should be in basic block"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *bb = inst->graph->impl->GetLocalAllocator()->New(); bb->graph = inst->graph; bb->impl = newBbImpl; inst->graph->implToBB.insert({newBbImpl, bb}); GraphInvalidateAnalyses(basicBlock->graph->impl); return bb; } void BBaddInstBackStatic(AbckitBasicBlock *basicBlock, AbckitInst *inst) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(basicBlock) LIBABCKIT_BAD_ARGUMENT_VOID(inst) LIBABCKIT_WRONG_CTX_VOID(basicBlock->graph, inst->graph); if (inst->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "can't use constant instruction as an argument"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } basicBlock->impl->AppendInst(inst->impl); } AbckitInst *BBgetLastInstStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, nullptr); auto *bb = basicBlock->impl; auto *inst = bb->GetLastInst(); if (inst == nullptr) { return nullptr; } return basicBlock->graph->implToInst.at(inst); } AbckitGraph *BBgetGraphStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, nullptr); return basicBlock->graph; } AbckitInst *BBgetFirstInstStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, nullptr); auto *bbImpl = basicBlock->impl; ark::compiler::Inst *instImpl = bbImpl->GetFirstPhi(); if (instImpl == nullptr) { instImpl = bbImpl->GetFirstInst(); } if (instImpl == nullptr) { return nullptr; } auto *inst = basicBlock->graph->implToInst.at(instImpl); return inst; } void BBdisconnectSuccBlockStatic(AbckitBasicBlock *bb, size_t index) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(bb) if (index >= bb->impl->GetSuccsBlocks().size()) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } auto succ = bb->impl->GetSuccessor(index); succ->RemovePred(bb->impl); bb->impl->RemoveSucc(succ); GraphInvalidateAnalyses(bb->graph->impl); } void BBremoveAllInstsStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; basicBlock->impl->Clear(); } AbckitBasicBlock *BBgetSuccBlockStatic(AbckitBasicBlock *basicBlock, uint32_t index) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, nullptr); if (index >= basicBlock->impl->GetSuccsBlocks().size()) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *succImpl = basicBlock->impl->GetSuccsBlocks()[index]; return basicBlock->graph->implToBB.at(succImpl); } uint64_t BBgetSuccBlockCountStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, 0); return basicBlock->impl->GetSuccsBlocks().size(); } uint32_t BBgetIdStatic([[maybe_unused]] AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, 0); return basicBlock->impl->GetId(); } AbckitBasicBlock *BBgetPredBlockStatic(AbckitBasicBlock *basicBlock, uint32_t index) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, nullptr); if (index >= basicBlock->impl->GetPredsBlocks().size()) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *predImpl = basicBlock->impl->GetPredsBlocks()[index]; return basicBlock->graph->implToBB.at(predImpl); } uint64_t BBgetPredBlockCountStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, 0); return basicBlock->impl->GetPredsBlocks().size(); } bool BBisStartStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsStartBlock(); } bool BBisEndStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsEndBlock(); } uint32_t BBgetNumberOfInstructionsStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, 0); return basicBlock->impl->CountInsts(); } bool BBisLoopHeadStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsLoopHeader(); } bool BBisLoopPreheadStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsLoopPreHeader(); } bool BBisTryBeginStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsTryBegin(); } bool BBisTryStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsTry(); } bool BBisTryEndStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsTryEnd(); } bool BBisCatchBeginStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsCatchBegin(); } bool BBisCatchStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); return basicBlock->impl->IsCatch(); } void BBdumpStatic(AbckitBasicBlock *basicBlock, int fd) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(basicBlock) std::stringstream ss; basicBlock->impl->Dump(&ss); write(fd, ss.str().data(), ss.str().size()); } bool BBcheckDominanceStatic(AbckitBasicBlock *basicBlock, AbckitBasicBlock *dominator) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false); LIBABCKIT_BAD_ARGUMENT(dominator, false); LIBABCKIT_WRONG_CTX(basicBlock->graph, dominator->graph, false); if (!GraphDominatorsTreeAnalysisIsValid(basicBlock->graph->impl)) { LIBABCKIT_LOG(DEBUG) << "DominatorsTree analysis is not valid\n"; statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return false; } return dominator->impl->IsDominate(basicBlock->impl); } AbckitBasicBlock *BBgetImmediateDominatorStatic(AbckitBasicBlock *basicBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, nullptr); if (!GraphDominatorsTreeAnalysisIsValid(basicBlock->graph->impl)) { LIBABCKIT_LOG(DEBUG) << "DominatorsTree analysis is not valid\n"; statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *bb = basicBlock->impl->GetDominator(); if (bb == nullptr) { return nullptr; } return basicBlock->graph->implToBB.at(bb); } bool BBvisitDominatedBlocksStatic(AbckitBasicBlock *basicBlock, void *data, bool (*cb)(AbckitBasicBlock *dominatedBasicBlock, void *data)) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(basicBlock, false) LIBABCKIT_BAD_ARGUMENT(cb, false) if (!GraphDominatorsTreeAnalysisIsValid(basicBlock->graph->impl)) { LIBABCKIT_LOG(DEBUG) << "DominatorsTree analysis is not valid\n"; statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return false; } for (auto *bbImpl : basicBlock->impl->GetDominatedBlocks()) { auto *bb = basicBlock->graph->implToBB.at(bbImpl); if (!cb(bb, data)) { return false; } } return true; } void BBinsertSuccBlockStatic(AbckitBasicBlock *basicBlock, AbckitBasicBlock *succBlock, uint32_t index) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(basicBlock) LIBABCKIT_BAD_ARGUMENT_VOID(succBlock) LIBABCKIT_WRONG_CTX_VOID(basicBlock->graph, succBlock->graph); auto &bbs = basicBlock->impl->GetSuccsBlocks(); if (index > bbs.size()) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } if (index == bbs.size()) { bbs.emplace_back(succBlock->impl); } else { bbs.resize(bbs.size() + 1); for (size_t i = index + 1; i < bbs.size(); i++) { bbs[i] = bbs[i - 1]; } bbs[index] = succBlock->impl; } succBlock->impl->GetPredsBlocks().emplace_back(basicBlock->impl); GraphInvalidateAnalyses(basicBlock->graph->impl); } void BBappendSuccBlockStatic(AbckitBasicBlock *basicBlock, AbckitBasicBlock *succBlock) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(basicBlock) LIBABCKIT_BAD_ARGUMENT_VOID(succBlock) LIBABCKIT_WRONG_CTX_VOID(basicBlock->graph, succBlock->graph); basicBlock->impl->GetSuccsBlocks().emplace_back(succBlock->impl); succBlock->impl->GetPredsBlocks().emplace_back(basicBlock->impl); GraphInvalidateAnalyses(basicBlock->graph->impl); } AbckitBasicBlock *BBgetTrueBranchStatic(AbckitBasicBlock *bb) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(bb, nullptr); if (bb->impl->GetSuccsBlocks().empty()) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *tb = bb->impl->GetTrueSuccessor(); ASSERT(tb != nullptr); return bb->graph->implToBB.at(tb); } AbckitBasicBlock *BBgetFalseBranchStatic(AbckitBasicBlock *bb) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT(bb, nullptr); if (bb->impl->GetSuccsBlocks().size() < 2U) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *fb = bb->impl->GetFalseSuccessor(); ASSERT(fb != nullptr); return bb->graph->implToBB.at(fb); } AbckitInst *BBcreatePhiStatic(AbckitBasicBlock *bb, size_t argCount, std::va_list args) { LIBABCKIT_LOG_FUNC; LIBABCKIT_LOG(DEBUG) << argCount << '\n'; if (argCount < 1) { LIBABCKIT_LOG(DEBUG) << "not enough inputs\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } std::vector inputs; for (size_t index = 0; index < argCount; ++index) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) AbckitInst *input = va_arg(args, AbckitInst *); LIBABCKIT_BAD_ARGUMENT(input, nullptr); inputs.emplace_back(input); } ark::compiler::DataType::Type type = inputs[0]->impl->GetType(); if (IsDynamic(bb->graph->function->owningModule->target)) { type = ark::compiler::DataType::ANY; } for (auto *inst : inputs) { if (IsDynamic(bb->graph->function->owningModule->target)) { if (inst->impl->GetType() != ark::compiler::DataType::INT64 && inst->impl->GetType() != ark::compiler::DataType::ANY) { LIBABCKIT_LOG(DEBUG) << "inconsistent input types\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } } else { if (type != inst->impl->GetType()) { LIBABCKIT_LOG(DEBUG) << "inconsistent input types\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } } } auto phiImpl = bb->graph->impl->CreateInstPhi(type, 0); bb->impl->AppendPhi(phiImpl); auto *phi = CreateInstFromImpl(bb->graph, phiImpl); for (auto *inst : inputs) { phiImpl->AppendInput(inst->impl); } return phi; } AbckitInst *BBcreateCatchPhiStatic(AbckitBasicBlock *catchBegin, size_t argCount, std::va_list args) { auto *instImpl = catchBegin->graph->impl->CreateInstCatchPhi(); auto *catchPhi = CreateInstFromImpl(catchBegin->graph, instImpl); BBaddInstFrontStatic(catchBegin, catchPhi); if (argCount == 0) { auto type = IsDynamic(catchBegin->graph->function->owningModule->target) ? ark::compiler::DataType::ANY : ark::compiler::DataType::REFERENCE; instImpl->SetIsAcc(); instImpl->SetType(type); return catchPhi; } std::vector types; for (size_t index = 0; index < argCount; ++index) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) AbckitInst *inputOrThrowable = va_arg(args, AbckitInst *); if (index % 2U == 0) { types.push_back(inputOrThrowable->impl->GetType()); catchPhi->impl->AppendInput(inputOrThrowable->impl); } else { catchPhi->impl->CastToCatchPhi()->AppendThrowableInst(inputOrThrowable->impl); } } ASSERT(!types.empty()); if (IsDynamic(catchBegin->graph->function->owningModule->target)) { catchPhi->impl->SetType(ark::compiler::DataType::ANY); } else { for (int i = 1, j = types.size(); i < j; ++i) { if (types[0] != types[i]) { LIBABCKIT_LOG(DEBUG) << "All inputs of a catchPhi should be of the same type " << '\n'; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); catchBegin->impl->EraseInst(instImpl, true); return nullptr; } } catchPhi->impl->SetType(types[0]); } return catchPhi; } // ======================================== // Api for instruction manipulation // ======================================== void IremoveStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto bbImpl = inst->impl->GetBasicBlock(); LIBABCKIT_BAD_ARGUMENT_VOID(bbImpl) bbImpl->RemoveInst(inst->impl); } uint32_t IgetIdStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto id = inst->impl->GetId(); LIBABCKIT_LOG(DEBUG) << id << '\n'; return id; } AbckitLiteralArray *IgetLiteralArrayStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; size_t idx = 0; if (IsDynamic(inst->graph->function->owningModule->target)) { auto instOpcode = GetDynamicOpcode(inst->impl); if (!HasLiteralArrayIdOperandDynamic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } idx = GetLiteralArrayIdOperandIndexDynamic(instOpcode); } else { auto instOpcode = GetStaticOpcode(inst->impl); if (!HasLiteralArrayIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } idx = GetLiteralArrayIdOperandIndexStatic(instOpcode); } auto &imms = inst->impl->CastToIntrinsic()->GetImms(); ASSERT(!imms.empty()); auto arrName = inst->graph->irInterface->literalarrays.at(imms[idx]); std::variant arrImpl { (panda::pandasm::LiteralArray *)nullptr}; if (IsDynamic(inst->graph->function->owningModule->target)) { arrImpl = reinterpret_cast( PandasmWrapper::GetUnwrappedLiteralArrayTable(inst->graph->file->GetDynamicProgram()).at(arrName)); } else { arrImpl = &inst->graph->file->GetStaticProgram()->literalarrayTable.at(arrName); } // Search through already created litarrs auto &abckitLitArrs = inst->graph->file->litarrs; for (auto &item : abckitLitArrs) { if (item->impl == arrImpl) { return item.get(); } } // Create new litarr auto litarr = std::make_unique(); litarr->file = inst->graph->file; litarr->impl = arrImpl; return abckitLitArrs.emplace_back(std::move(litarr)).get(); } void IsetLiteralArrayStatic(AbckitInst *inst, AbckitLiteralArray *la) { LIBABCKIT_LOG_FUNC; size_t idx = 0; if (IsDynamic(inst->graph->function->owningModule->target)) { auto instOpcode = GetDynamicOpcode(inst->impl); if (!HasLiteralArrayIdOperandDynamic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } idx = GetLiteralArrayIdOperandIndexDynamic(instOpcode); } else { auto instOpcode = GetStaticOpcode(inst->impl); if (!HasLiteralArrayIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } idx = GetLiteralArrayIdOperandIndexStatic(instOpcode); } auto &imms = inst->impl->CastToIntrinsic()->GetImms(); ASSERT(imms.size() == 2U); imms[idx] = GetLiteralArrayOffset(inst->graph, la); } AbckitString *IgetStringStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; size_t idx = 0; if (IsDynamic(inst->graph->function->owningModule->target)) { auto instOpcode = GetDynamicOpcode(inst->impl); if (!HasStringIdOperandDynamic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } idx = GetStringIdOperandIndexDynamic(instOpcode); } else { auto instOpcode = GetStaticOpcode(inst->impl); if (!HasStringIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } idx = GetStringIdOperandIndexStatic(instOpcode); } auto &imms = inst->impl->CastToIntrinsic()->GetImms(); auto strName = inst->graph->irInterface->strings.at(imms[idx]); auto strImpl = inst->graph->file->strings.at(strName).get(); return strImpl; } void IsetStringStatic(AbckitInst *inst, AbckitString *str) { LIBABCKIT_LOG_FUNC; size_t idx = 0; if (IsDynamic(inst->graph->function->owningModule->target)) { auto instOpcode = GetDynamicOpcode(inst->impl); if (!HasStringIdOperandDynamic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } idx = GetStringIdOperandIndexDynamic(instOpcode); } else { auto instOpcode = GetStaticOpcode(inst->impl); if (!HasStringIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } idx = GetStringIdOperandIndexStatic(instOpcode); } auto &imms = inst->impl->CastToIntrinsic()->GetImms(); imms[idx] = GetStringOffset(inst->graph, str); } AbckitIsaApiStaticOpcode IgetOpcodeStaticStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto opc = inst->impl->GetOpcode(); if (opc == ark::compiler::Opcode::Intrinsic) { return GetStaticIntrinsicOpcode(inst->impl->CastToIntrinsic()); } return GetStaticOpcode(inst->impl); } AbckitIsaApiDynamicOpcode IgetOpcodeDynamicStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto opc = inst->impl->GetOpcode(); if (opc == ark::compiler::Opcode::Intrinsic) { switch (inst->impl->CastToIntrinsic()->GetIntrinsicId()) { case ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_STRING: return ABCKIT_ISA_API_DYNAMIC_OPCODE_LOADSTRING; default: break; } return GetDynamicIntrinsicOpcode(inst->impl->CastToIntrinsic()); } return GetDynamicOpcode(inst->impl); } AbckitInst *IgetNextStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto *nextInstImpl = inst->impl->GetNext(); if (nextInstImpl == nullptr) { return nullptr; } auto *nextInst = inst->graph->implToInst.at(nextInstImpl); return nextInst; } AbckitInst *IgetPrevStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto *nextInstImpl = inst->impl->GetPrev(); if (nextInstImpl == nullptr) { return nullptr; } auto *nextInst = inst->graph->implToInst.at(nextInstImpl); return nextInst; } void IinsertAfterStatic(AbckitInst *inst, AbckitInst *next) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(inst) LIBABCKIT_BAD_ARGUMENT_VOID(next) LIBABCKIT_WRONG_CTX_VOID(inst->graph, next->graph); auto *bb = IgetBasicBlockStatic(next); LIBABCKIT_BAD_ARGUMENT_VOID(bb) if (inst->impl->IsConst() || next->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "can't use constant instruction as an argument"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } bb->impl->InsertAfter(inst->impl, next->impl); } void IinsertBeforeStatic(AbckitInst *inst, AbckitInst *prev) { LIBABCKIT_LOG_FUNC; LIBABCKIT_BAD_ARGUMENT_VOID(inst) LIBABCKIT_BAD_ARGUMENT_VOID(prev) LIBABCKIT_WRONG_CTX_VOID(inst->graph, prev->graph); auto *bb = IgetBasicBlockStatic(prev); LIBABCKIT_BAD_ARGUMENT_VOID(bb) if (inst->impl->IsConst() || prev->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "can't use constant instruction as an argument"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } bb->impl->InsertBefore(inst->impl, prev->impl); } bool IcheckDominanceStatic(AbckitInst *inst, AbckitInst *dominator) { LIBABCKIT_LOG_FUNC; LIBABCKIT_WRONG_CTX(inst->graph, dominator->graph, false); return inst->impl->IsDominate(dominator->impl); } bool IvisitUsersStatic(AbckitInst *inst, void *data, bool (*cb)(AbckitInst *user, void *data)) { LIBABCKIT_LOG_FUNC; auto *user = inst->impl->GetFirstUser(); while (user != nullptr) { auto *userInst = inst->graph->implToInst.at(user->GetInst()); if (!cb(userInst, data)) { return false; } user = user->GetNext(); } return true; } uint32_t IgetUserCountStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; uint32_t count = 0; auto *user = inst->impl->GetFirstUser(); while (user != nullptr) { count++; user = user->GetNext(); } return count; } bool IvisitInputsStatic(AbckitInst *inst, void *data, bool (*cb)(AbckitInst *input, size_t inputIdx, void *data)) { LIBABCKIT_LOG_FUNC; for (size_t i = 0; i < inst->impl->GetInputsCount(); i++) { auto *inputImpl = inst->impl->GetInput(i).GetInst(); auto *input = inst->graph->implToInst.at(inputImpl); if (!cb(input, i, data)) { return false; } } return true; } uint64_t IgetInputCountStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; return inst->impl->GetInputsCount(); } AbckitInst *IgetInputStatic(AbckitInst *inst, size_t index) { LIBABCKIT_LOG_FUNC; if (inst->impl->GetInputsCount() <= index) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto *inputImpl = inst->impl->GetInput(index).GetInst(); auto *input = inst->graph->implToInst.at(inputImpl); return input; } void IsetInputStatic(AbckitInst *inst, AbckitInst *input, int32_t index) { LIBABCKIT_LOG_FUNC; LIBABCKIT_LOG(DEBUG) << index << '\n'; LIBABCKIT_LOG(DEBUG) << inst->impl->GetInputs().size() << '\n'; inst->impl->SetInput(index, input->impl); } void IsetInputsStatic(AbckitInst *inst, size_t argCount, std::va_list args) { LIBABCKIT_LOG_FUNC; LIBABCKIT_LOG(DEBUG) << argCount << '\n'; LIBABCKIT_LOG(DEBUG) << inst->impl->GetInputs().size() << '\n'; for (size_t index = 0; index < argCount; ++index) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) AbckitInst *input = va_arg(args, AbckitInst *); inst->impl->SetInput(index, input->impl); } } void IappendInputStatic(AbckitInst *inst, AbckitInst *input) { LIBABCKIT_LOG_FUNC; auto instImpl = inst->impl; static size_t rangeInputsCount = -1; if (instImpl->IsOperandsDynamic()) { switch (instImpl->GetOpcode()) { case ark::compiler::Opcode::CallStatic: { instImpl->CastToCallStatic()->AppendInput(input->impl, input->impl->GetType()); return; } case ark::compiler::Opcode::CallVirtual: { instImpl->CastToCallVirtual()->AppendInput(input->impl, input->impl->GetType()); return; } case ark::compiler::Opcode::Intrinsic: { if (GetIntrinicMaxInputsCount(inst) == rangeInputsCount) { instImpl->CastToIntrinsic()->AppendInput(input->impl, input->impl->GetType()); return; } if (instImpl->GetInputsCount() >= GetIntrinicMaxInputsCount(inst)) { LIBABCKIT_LOG(DEBUG) << "The maximum number of inputs has been reached for the instruction\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } instImpl->CastToIntrinsic()->AppendInput(input->impl, input->impl->GetType()); return; } case ark::compiler::Opcode::Phi: { instImpl->AppendInput(input->impl); return; } default: break; } } LIBABCKIT_LOG(DEBUG) << "The instruction does not have the ability to add inputs\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } // Type helpers static AbckitType *CreateGeneralType(AbckitFile *file, AbckitTypeId typeId, AbckitCoreClass *klass) { return GetOrCreateType(file, typeId, 0, klass); } AbckitType *IgetTypeStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; AbckitTypeId typeId = TypeToTypeId(inst->impl->GetType()); AbckitCoreClass *klass = nullptr; if (typeId != ABCKIT_TYPE_ID_REFERENCE) { return CreateGeneralType(inst->graph->file, typeId, klass); } // Add get of ABCKIT_TYPE_ID_REFERENCE NOTE(ymolokanov) return CreateGeneralType(inst->graph->file, typeId, klass); } AbckitTypeId IgetTargetTypeStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; if (inst->impl->GetOpcode() != ark::compiler::Opcode::Cast) { LIBABCKIT_LOG(DEBUG) << "Instruction is not a cast\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return AbckitTypeId::ABCKIT_TYPE_ID_INVALID; } return TypeToTypeId(static_cast(inst->impl)->GetType()); } void IsetTargetTypeStatic(AbckitInst *inst, AbckitTypeId type) { LIBABCKIT_LOG_FUNC; if (inst->impl->GetOpcode() != ark::compiler::Opcode::Cast) { LIBABCKIT_LOG(DEBUG) << "Instruction is not a cast\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } inst->impl->SetType(TypeIdToType(type)); } bool IcheckIsCallStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; return IsCallInst(inst); } AbckitBasicBlock *IgetBasicBlockStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto *graph = inst->graph; auto *implBB = inst->impl->GetBasicBlock(); auto it = graph->implToBB.find(implBB); if (it != graph->implToBB.end()) { return it->second; } return nullptr; } AbckitGraph *IgetGraphStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; return inst->graph; } AbckitCoreFunction *IgetFunctionStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto *graph = inst->graph; ark::compiler::RuntimeInterface::MethodPtr methodPtr = nullptr; if (inst->impl->IsCall()) { auto *callInst = static_cast(inst->impl); methodPtr = callInst->GetCallMethod(); } else if (inst->impl->IsIntrinsic()) { size_t idx = 0; if (IsDynamic(inst->graph->function->owningModule->target)) { auto instOpcode = GetDynamicOpcode(inst->impl); if (!HasMethodIdOperandDynamic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } idx = GetMethodIdOperandIndexDynamic(instOpcode); } else { auto instOpcode = GetStaticOpcode(inst->impl); if (!HasMethodIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } idx = GetMethodIdOperandIndexStatic(instOpcode); } auto *intrinsic = inst->impl->CastToIntrinsic(); methodPtr = reinterpret_cast(intrinsic->GetImm(idx)); } else { LIBABCKIT_LOG(DEBUG) << "Instruction is not a call or intrinsic\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto it = graph->irInterface->methods.find(reinterpret_cast(methodPtr)); if (it == graph->irInterface->methods.end()) { LIBABCKIT_LOG(DEBUG) << "No requested call exists in current graph context\n"; SetLastError(ABCKIT_STATUS_UNSUPPORTED); return nullptr; } auto &nameToFunction = reinterpret_cast(graph->internal)->runtimeAdapter->IsMethodStatic(methodPtr) ? graph->file->nameToFunctionStatic : graph->file->nameToFunctionInstance; if (nameToFunction.count(it->second) == 0) { statuses::SetLastError(ABCKIT_STATUS_UNSUPPORTED); return nullptr; } return nameToFunction[it->second]; } void IsetFunctionStatic(AbckitInst *inst, AbckitCoreFunction *function) { LIBABCKIT_LOG_FUNC; auto *graph = inst->graph; auto methodOffset = GetMethodOffset(graph, function); if (inst->impl->IsCall()) { auto *callInst = static_cast(inst->impl); callInst->SetCallMethodId(methodOffset); } else if (inst->impl->IsIntrinsic()) { size_t idx = 0; if (IsDynamic(inst->graph->function->owningModule->target)) { auto instOpcode = GetDynamicOpcode(inst->impl); if (!HasMethodIdOperandDynamic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } idx = GetMethodIdOperandIndexDynamic(instOpcode); } else { auto instOpcode = GetStaticOpcode(inst->impl); if (!HasMethodIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } idx = GetMethodIdOperandIndexStatic(instOpcode); } auto *intrinsic = inst->impl->CastToIntrinsic(); intrinsic->SetImm(idx, methodOffset); } else { LIBABCKIT_LOG(DEBUG) << "Instruction is not a call or intrinsic\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } } void IsetClassStatic(AbckitInst *inst, AbckitCoreClass *klass) { LIBABCKIT_LOG_FUNC; auto *graph = inst->graph; auto *intrinsic = inst->impl->CastToIntrinsic(); auto instOpcode = GetStaticOpcode(inst->impl); if (!HasTypeIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } size_t idx = GetTypeIdOperandIndexStatic(instOpcode); auto klassOffset = GetClassOffset(graph, klass); intrinsic->SetImm(idx, klassOffset); } AbckitCoreClass *IgetClassStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; auto *graph = inst->graph; auto *intrinsic = inst->impl->CastToIntrinsic(); auto instOpcode = IgetOpcodeStaticStatic(inst); if (!HasTypeIdOperandStatic(instOpcode)) { statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } size_t idx = GetTypeIdOperandIndexStatic(instOpcode); auto classPtr = reinterpret_cast(intrinsic->GetImm(idx)); auto it = graph->ptrToClass.find(reinterpret_cast(classPtr)); if (it == graph->ptrToClass.end()) { LIBABCKIT_LOG(DEBUG) << "No requested class exists in current graph context\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } return it->second; } AbckitInst *GcreateNullPtrStatic(AbckitGraph *graph) { auto instImpl = graph->impl->CreateInstNullPtr(ark::compiler::DataType::REFERENCE); auto *inst = CreateInstFromImpl(graph, instImpl); graph->impl->GetStartBlock()->AppendInst(instImpl); return inst; } int32_t IgetConstantValueI32Static(AbckitInst *inst) { if (!inst->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "Input instruction of " << LIBABCKIT_FUNC_NAME << " must be constant instruction" << '\n'; } if (inst->impl->GetType() != ark::compiler::DataType::INT32 && inst->impl->GetType() != ark::compiler::DataType::UINT32) { LIBABCKIT_LOG(DEBUG) << "Type of input constant instruction in " << LIBABCKIT_FUNC_NAME << " is wrong" << '\n'; } return static_cast(inst->impl)->GetInt32Value(); } int64_t IgetConstantValueI64Static(AbckitInst *inst) { if (!inst->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "Input instruction of " << LIBABCKIT_FUNC_NAME << " must be constant instruction" << '\n'; } if (inst->impl->GetType() != ark::compiler::DataType::INT64 && inst->impl->GetType() != ark::compiler::DataType::UINT64) { LIBABCKIT_LOG(DEBUG) << "Type of input constant instruction in " << LIBABCKIT_FUNC_NAME << " is wrong" << '\n'; } return static_cast(inst->impl)->GetInt64Value(); } uint64_t IgetConstantValueU64Static(AbckitInst *inst) { if (!inst->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "Input instruction of " << LIBABCKIT_FUNC_NAME << " must be constant instruction" << '\n'; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } if (inst->impl->GetType() != ark::compiler::DataType::INT64 && inst->impl->GetType() != ark::compiler::DataType::UINT64) { LIBABCKIT_LOG(DEBUG) << "Type of input constant instruction in " << LIBABCKIT_FUNC_NAME << " is wrong" << '\n'; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } return static_cast(inst->impl)->GetInt64Value(); } double IgetConstantValueF64Static(AbckitInst *inst) { if (!inst->impl->IsConst()) { LIBABCKIT_LOG(DEBUG) << "Input instruction of " << LIBABCKIT_FUNC_NAME << " must be constant instruction" << '\n'; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } if (inst->impl->GetType() != ark::compiler::DataType::FLOAT64) { LIBABCKIT_LOG(DEBUG) << "Type of input constant instruction in " << LIBABCKIT_FUNC_NAME << " is wrong" << '\n'; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } return static_cast(inst->impl)->GetDoubleValue(); } uint64_t IgetImmediateStatic(AbckitInst *inst, size_t idx) { LIBABCKIT_LOG_FUNC; if (IgetImmediateCountStatic(inst) <= idx) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return 0; } uint64_t ret = 0; if (inst->impl->IsBinaryImmInst()) { ret = (static_cast(inst->impl))->GetImm(); } else if (inst->impl->GetOpcode() == ark::compiler::Opcode::Intrinsic) { ret = inst->impl->CastToIntrinsic()->GetImm(idx); } else { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return 0; } return ret; } void IsetImmediateStatic(AbckitInst *inst, size_t idx, uint64_t imm) { LIBABCKIT_LOG_FUNC; if (IgetImmediateCountStatic(inst) <= idx) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } if (inst->impl->IsBinaryImmInst()) { if (GetBitLengthUnsigned(imm) <= GetBinaryImmOperationSize(inst->impl->GetOpcode())) { (static_cast(inst->impl))->SetImm(imm); } else { LIBABCKIT_LOG(DEBUG) << "Immediate type overflow\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } } else if (inst->impl->GetOpcode() == ark::compiler::Opcode::Intrinsic) { auto instr = inst->impl->CastToIntrinsic(); if (GetBitLengthUnsigned(imm) <= GetIntrinsicBitImmSize(instr->GetIntrinsicId(), idx)) { instr->SetImm(idx, imm); } else { LIBABCKIT_LOG(DEBUG) << "Immediate type overflow\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } } else { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } } AbckitBitImmSize IgetImmediateSizeStatic(AbckitInst *inst, size_t idx) { LIBABCKIT_LOG_FUNC; if (IgetImmediateCountStatic(inst) <= idx) { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return AbckitBitImmSize::BITSIZE_0; } auto immBitSize = AbckitBitImmSize::BITSIZE_0; if (inst->impl->IsBinaryImmInst()) { immBitSize = GetBinaryImmOperationSize(inst->impl->GetOpcode()); } else if (inst->impl->GetOpcode() == ark::compiler::Opcode::Intrinsic) { auto instr = inst->impl->CastToIntrinsic(); immBitSize = GetIntrinsicBitImmSize(instr->GetIntrinsicId(), idx); } else { SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); } return immBitSize; } uint64_t IgetImmediateCountStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; uint64_t ret = 0; if (inst->impl->IsBinaryImmInst()) { ret = 1; } else if (inst->impl->GetOpcode() == ark::compiler::Opcode::Intrinsic) { auto instr = inst->impl->CastToIntrinsic(); return instr->HasImms() ? instr->GetImms().size() : 0; } return ret; } AbckitCoreModule *IgetModuleStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; if (!inst->impl->IsIntrinsic()) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have module id\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto intrInst = inst->impl->CastToIntrinsic(); auto opcode = GetDynamicIntrinsicOpcode(intrInst); if (opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_GETMODULENAMESPACE && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_GETMODULENAMESPACE) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have module id\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } return inst->graph->function->owningModule->md[intrInst->GetImm(0)]; } uint64_t GetModuleIndex(AbckitGraph *graph, AbckitCoreModule *md) { uint64_t imm = 0; for (auto m : graph->function->owningModule->md) { if (m == md) { break; } imm++; } if (imm == graph->function->owningModule->md.size()) { LIBABCKIT_LOG(DEBUG) << "Can not find module descriptor for module with name '" << md->moduleName->impl << "'\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return 0; } return imm; } void IsetModuleStatic(AbckitInst *inst, AbckitCoreModule *md) { LIBABCKIT_LOG_FUNC; if (!inst->impl->IsIntrinsic()) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have module id\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } auto intrInst = inst->impl->CastToIntrinsic(); auto opcode = GetDynamicIntrinsicOpcode(intrInst); if (opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_GETMODULENAMESPACE && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_GETMODULENAMESPACE) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have module id\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } uint64_t imm = GetModuleIndex(inst->graph, md); if (statuses::GetLastError() != ABCKIT_STATUS_NO_ERROR) { return; } intrInst->SetImm(0, imm); } AbckitCoreImportDescriptor *GetImportDescriptorDynamic(AbckitInst *inst, uint64_t idx) { auto *module = inst->graph->function->owningModule; for (auto &id : module->id) { auto idPayload = GetDynImportDescriptorPayload(id.get()); if (!idPayload->isRegularImport) { continue; } if (idPayload->moduleRecordIndexOff == idx) { return id.get(); } } UNREACHABLE(); } AbckitCoreImportDescriptor *IgetImportDescriptorStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; ASSERT(IsDynamic(inst->graph->function->owningModule->target)); if (!inst->impl->IsIntrinsic()) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have import descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto intrInst = inst->impl->CastToIntrinsic(); auto opcode = GetDynamicIntrinsicOpcode(intrInst); if (opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_LDEXTERNALMODULEVAR) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have import descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } return GetImportDescriptorDynamic(inst, intrInst->GetImm(0)); } uint32_t GetImportDescriptorIdxDynamic(AbckitGraph *graph, AbckitCoreImportDescriptor *id) { AbckitCoreModule *m = graph->function->owningModule; auto found = std::find_if(m->id.begin(), m->id.end(), [&](std::unique_ptr const &d) { return d.get() == id; }); if (found == m->id.end()) { LIBABCKIT_LOG(DEBUG) << "Can not find the import in module imports\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return 0; } return GetDynImportDescriptorPayload(found->get())->moduleRecordIndexOff; } void IsetImportDescriptorStatic(AbckitInst *inst, AbckitCoreImportDescriptor *id) { LIBABCKIT_LOG_FUNC; ASSERT(IsDynamic(inst->graph->function->owningModule->target)); if (!inst->impl->IsIntrinsic()) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have import descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } auto intrInst = inst->impl->CastToIntrinsic(); auto opcode = GetDynamicIntrinsicOpcode(intrInst); if (opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_LDEXTERNALMODULEVAR) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have import descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } uint32_t imm = GetImportDescriptorIdxDynamic(inst->graph, id); if (statuses::GetLastError() != ABCKIT_STATUS_NO_ERROR) { return; } intrInst->SetImm(0, imm); } AbckitCoreExportDescriptor *GetExportDescriptorDynamic(AbckitInst *inst, uint64_t idx) { auto *module = inst->graph->function->owningModule; for (auto &ed : module->ed) { auto edPayload = GetDynExportDescriptorPayload(ed.get()); if (edPayload->kind != AbckitDynamicExportKind::ABCKIT_DYNAMIC_EXPORT_KIND_LOCAL_EXPORT) { continue; } if (edPayload->moduleRecordIndexOff == idx) { return ed.get(); } } UNREACHABLE(); } AbckitCoreExportDescriptor *IgetExportDescriptorStatic(AbckitInst *inst) { LIBABCKIT_LOG_FUNC; ASSERT(IsDynamic(inst->graph->function->owningModule->target)); if (!inst->impl->IsIntrinsic()) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have export descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } auto intrInst = inst->impl->CastToIntrinsic(); auto opcode = GetDynamicIntrinsicOpcode(intrInst); if (opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDLOCALMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_LDLOCALMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_STMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_STMODULEVAR) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have export descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return nullptr; } return GetExportDescriptorDynamic(inst, intrInst->GetImm(0)); } uint32_t GetExportDescriptorIdxDynamic(AbckitGraph *graph, AbckitCoreExportDescriptor *ed) { AbckitCoreModule *m = graph->function->owningModule; auto found = std::find_if(m->ed.begin(), m->ed.end(), [&](std::unique_ptr const &d) { return d.get() == ed; }); if (found == m->ed.end()) { LIBABCKIT_LOG(DEBUG) << "Can not find the import in module imports\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return 0; } return GetDynExportDescriptorPayload(found->get())->moduleRecordIndexOff; } void IsetExportDescriptorStatic(AbckitInst *inst, AbckitCoreExportDescriptor *ed) { LIBABCKIT_LOG_FUNC; ASSERT(IsDynamic(inst->graph->function->owningModule->target)); if (!inst->impl->IsIntrinsic()) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have export descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } auto intrInst = inst->impl->CastToIntrinsic(); auto opcode = GetDynamicIntrinsicOpcode(intrInst); if (opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDLOCALMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_LDLOCALMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_STMODULEVAR && opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_STMODULEVAR) { LIBABCKIT_LOG(DEBUG) << "Instruction doesn't have export descriptor\n"; SetLastError(ABCKIT_STATUS_BAD_ARGUMENT); return; } uint32_t imm = GetExportDescriptorIdxDynamic(inst->graph, ed); if (statuses::GetLastError() != ABCKIT_STATUS_NO_ERROR) { return; } intrInst->SetImm(0, imm); } AbckitIsaApiStaticConditionCode IgetConditionCodeStaticStatic(AbckitInst *inst) { return CcToStaticCc(inst->impl->CastToIf()->GetCc()); } AbckitIsaApiDynamicConditionCode IgetConditionCodeDynamicStatic(AbckitInst *inst) { return CcToDynamicCc(inst->impl->CastToIf()->GetCc()); } void IsetConditionCodeStaticStatic(AbckitInst *inst, AbckitIsaApiStaticConditionCode cc) { inst->impl->CastToIf()->SetCc(CcToCc(cc)); } void IsetConditionCodeDynamicStatic(AbckitInst *inst, AbckitIsaApiDynamicConditionCode cc) { inst->impl->CastToIf()->SetCc(CcToCc(cc)); } } // namespace libabckit