* Copyright (c) 2026 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.
*/
#ifndef ECMASCRIPT_ARKSTEED_ARKSTEED_REGALLOC_PROCESSORS_H
#define ECMASCRIPT_ARKSTEED_ARKSTEED_REGALLOC_PROCESSORS_H
#include "ecmascript/arksteed/arksteed_framestate.h"
#include "ecmascript/arksteed/arksteed_graph_processor.h"
#include "ecmascript/arksteed/arksteed_opcode.h"
#include "ecmascript/arksteed/arksteed_regalloc.h"
#include "ecmascript/arksteed/arksteed_regalloc_vertex_info.h"
#include "ecmascript/arksteed/arksteed_vertex.h"
namespace panda::ecmascript::arksteed {
class VertexInfoAllocateProcessor {
public:
void PreProcessGraph(Graph *graph)
{
chunk_ = graph->GetChunk();
}
void PreProcessBlock(BB *block) {}
void PostProcessBlock(BB *block) {}
void PostProcessGraph(Graph *graph) {}
void PostPhiProcessing() {}
void ProcessVertex(ValueVertex *vertex, const ArkSteedState &state)
{
vertex->SetRegallocInfo(
chunk_->New<RegallocValueVertexInfo>(chunk_, vertex->GetInputCount(), vertex->GetMachineRepresentation()));
}
void ProcessVertex(Vertex *vertex, const ArkSteedState &state)
{
vertex->SetRegallocInfo(chunk_->New<RegallocVertexInfo>(chunk_, vertex->GetInputCount()));
}
private:
Chunk *chunk_ = nullptr;
};
class ValueLocationConstraintProcessor {
public:
void PreProcessGraph(Graph *graph) {}
void PreProcessBlock(BB *block) {}
void PostProcessBlock(BB *block) {}
void PostProcessGraph(Graph *graph) {}
void PostPhiProcessing() {}
#define DEF_PROCESS_VERTEX(NAME) \
void ProcessVertex(NAME##Vertex *vertex, const ArkSteedState &state) \
{ \
vertex->SetValueLocationConstraints(); \
return; \
}
ALL_VERTEX_LIST(DEF_PROCESS_VERTEX)
#undef DEF_PROCESS_VERTEX
};
class MaxCallDepthProcessor {
public:
void PreProcessGraph(Graph *graph) {}
void PreProcessBlock(BB *block) {}
void PostProcessBlock(BB *block) {}
void PostProcessGraph(Graph *graph)
{
graph->SetMaxCallStackArgs(maxCallStackArgs_);
}
void PostPhiProcessing() {}
template <typename T>
void ProcessVertex(T *vertex, const ArkSteedState &state)
{
constexpr bool isCall = T::PROPERTIES.IsCall();
constexpr bool needsRegSnapshot = T::PROPERTIES.NeedsRegisterSnapshot();
if constexpr (isCall || needsRegSnapshot) {
int vertexStackArgs = static_cast<int>(vertex->GetInputCount());
if constexpr (needsRegSnapshot) {
vertexStackArgs += ALLOCATABLE_GENERAL_REGISTER_COUNT + ALLOCATABLE_DOUBLE_REGISTER_COUNT;
}
maxCallStackArgs_ = std::max(maxCallStackArgs_, vertexStackArgs);
}
}
private:
int maxCallStackArgs_{0};
static constexpr int ALLOCATABLE_GENERAL_REGISTER_COUNT = 32;
static constexpr int ALLOCATABLE_DOUBLE_REGISTER_COUNT = 32;
};
class LivenessProcessor {
public:
void PreProcessGraph(Graph *graph) {}
void PreProcessBlock(BB *block)
{
if (block->IsLoopHeader()) {
LoopUsedVertices loopVertex;
loopVertex.header = block;
loopUsedVertices_.push_back(loopVertex);
}
}
void PostProcessBlock(BB *block) {}
void PostProcessGraph(Graph *graph)
{
ASSERT(loopUsedVertices_.empty());
}
void PostPhiProcessing() {}
template <typename T>
void ProcessVertex(T *vertex, const ArkSteedState &state)
{
vertex->GetRegallocInfo()->SetId(nextVertexId_++);
MarkInputUses(vertex, state);
}
private:
struct LoopUsedVertices {
std::vector<ValueVertex *> usedVertices;
BB *header;
};
LoopUsedVertices *GetCurrentLoopUsedVertices()
{
if (loopUsedVertices_.empty()) {
return nullptr;
}
return &loopUsedVertices_.back();
}
template <typename T>
void MarkDirectInputUses(T *vertex, const ArkSteedState &state)
{
LoopUsedVertices *loopUsedVertices = GetCurrentLoopUsedVertices();
vertex->ForAllInputsInRegallocAssignmentOrder([&](const Input &input) {
MarkUse(static_cast<ValueVertex *>(input.vertex()), vertex->GetId(), input.GetLocation(), loopUsedVertices);
});
}
template <typename T>
void MarkCatchPhiInputUses(T *vertex, const ArkSteedState &state)
{
BB *catchBlock = vertex->CaughtBy();
if (catchBlock == nullptr || !catchBlock->HasPhi()) {
return;
}
uint32_t use = vertex->GetId();
uint32_t predId = vertex->GetCatchPredecessorIndex();
int predIdx = static_cast<int>(predId);
LoopUsedVertices *loopUsedVertices = GetCurrentLoopUsedVertices();
for (PhiVertex *phi : catchBlock->GetPhis()) {
const ValueVertex *input = phi->GetInput(predIdx);
InputLocation *location = phi->GetInputLocation(predIdx);
MarkUse(const_cast<ValueVertex *>(input), use, location, loopUsedVertices);
}
}
public:
template <typename T>
void MarkInputUses(T *vertex, const ArkSteedState &state)
{
MarkDirectInputUses(vertex, state);
}
void MarkInputUses(PhiVertex *vertex, const ArkSteedState &state) {}
void MarkInputUses(JumpVertex *vertex, const ArkSteedState &state)
{
BB *target = vertex->Target();
uint32_t use = vertex->GetId();
int predecessorIdx = state.GetBlock()->GetPredecessorId();
LoopUsedVertices *loopUsedVertices = GetCurrentLoopUsedVertices();
if (!target->HasPhi()) {
return;
}
const auto &phis = target->GetPhis();
for (PhiVertex *phi : phis) {
const ValueVertex *input = phi->GetPredecessor(predecessorIdx);
InputLocation *location = phi->GetInputLocation(predecessorIdx);
MarkUse(const_cast<ValueVertex *>(input), use, location, loopUsedVertices);
}
}
void MarkInputUses(CallCommonStubVertex *vertex, const ArkSteedState &state)
{
MarkDirectInputUses(vertex, state);
MarkCatchPhiInputUses(vertex, state);
}
void MarkInputUses(CallRuntimeVertex *vertex, const ArkSteedState &state)
{
MarkDirectInputUses(vertex, state);
MarkCatchPhiInputUses(vertex, state);
}
void MarkInputUses(ThrowVertex *vertex, const ArkSteedState &state)
{
MarkDirectInputUses(vertex, state);
MarkCatchPhiInputUses(vertex, state);
}
void MarkInputUses(JumpLoopVertex *vertex, const ArkSteedState &state)
{
BB *target = vertex->Target();
uint32_t use = vertex->GetId();
int predecessorIdx = state.GetBlock()->GetPredecessorId();
ASSERT(!loopUsedVertices_.empty());
LoopUsedVertices loopUsedVertices = std::move(loopUsedVertices_.back());
loopUsedVertices_.pop_back();
ASSERT(loopUsedVertices.header == target);
LoopUsedVertices *outerLoopUsedVertices = GetCurrentLoopUsedVertices();
if (target->HasPhi()) {
const auto &phis = target->GetPhis();
for (PhiVertex *phi : phis) {
const ValueVertex *input = phi->GetPredecessor(predecessorIdx);
InputLocation *location = phi->GetInputLocation(predecessorIdx);
MarkUse(const_cast<ValueVertex *>(input), use, location, outerLoopUsedVertices);
}
}
if (!loopUsedVertices.usedVertices.empty()) {
JumpLoopVertex::UsedVerticesType usedVertexInputs;
usedVertexInputs.reserve(loopUsedVertices.usedVertices.size());
for (size_t i = 0; i < loopUsedVertices.usedVertices.size(); i++) {
usedVertexInputs.emplace_back(loopUsedVertices.usedVertices[i], InputLocation());
MarkUse(loopUsedVertices.usedVertices[i], use, &usedVertexInputs[i].second, outerLoopUsedVertices);
}
vertex->SetUsedVertices(std::move(usedVertexInputs));
}
}
void MarkUse(ValueVertex *vertex, uint32_t useId, InputLocation *input, LoopUsedVertices *loopUsedVertices)
{
ASSERT(vertex->GetRegallocInfo() != nullptr);
vertex->GetRegallocInfo()->RecordUse(useId, input);
if (loopUsedVertices != nullptr) {
if (vertex->GetId() < loopUsedVertices->header->GetFirstId()) {
loopUsedVertices->usedVertices.push_back(vertex);
}
}
}
std::vector<LoopUsedVertices> loopUsedVertices_;
uint32_t nextVertexId_{0};
};
}
#endif