* 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_GRAPH_BUILDER_H
#define ECMASCRIPT_ARKSTEED_GRAPH_BUILDER_H
#include "ecmascript/arksteed/arksteed_bytecode_context.h"
#include "ecmascript/arksteed/arksteed_bytecode_iterator.h"
#include "ecmascript/arksteed/arksteed_compiler.h"
#include "ecmascript/arksteed/arksteed_framestate.h"
#include "ecmascript/arksteed/arksteed_graph.h"
#include "ecmascript/arksteed/arksteed_helper.h"
#include "ecmascript/arksteed/arksteed_pgo_context.h"
#include "ecmascript/compiler/bytecodes.h"
#include "ecmascript/compiler/jit_compilation_env.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/jspandafile/method_literal.h"
#include "ecmascript/mem/chunk_containers.h"
namespace panda::ecmascript::arksteed {
using namespace panda::ecmascript::kungfu;
class BytecodeAnalysis;
class ValueVertex;
class ControlVertex;
class ArkSteedGraphBuilder : public ArkSteedHelper<ArkSteedGraphBuilder> {
public:
ArkSteedGraphBuilder(JSThread *compilerThread, uintptr_t glueAddr, Graph *graph, JitCompilationEnv *env)
: ArkSteedHelper<ArkSteedGraphBuilder>(graph, this),
compilerThread_(compilerThread),
glueAddr_(glueAddr),
env_(env),
pgoContext_(compilerThread, env),
bytecodeContext_(graph->GetChunk()),
mergeStates_(graph->GetChunk()),
predecessorCountReductions_(graph->GetChunk()),
jumpTargets_(graph->GetChunk()),
currentFrameState_(nullptr),
bytecodeAnalysis_(nullptr)
{}
~ArkSteedGraphBuilder() = default;
bool Build();
VRegIDType NumLocalVRegs() const
{
return numLocal_;
}
VRegIDType NumParamVRegs() const
{
return numParams_;
}
ValueVertex *GetActualArgc()
{
return NewVertexNoInput<ActualArgcVertex>();
}
ValueVertex *GetGlue()
{
return glue_;
}
ValueVertex *GetGlobalEnv() const
{
ASSERT(currentFrameState_ != nullptr);
ValueVertex *lexicalEnv = currentFrameState_->GetEnv();
int32_t globalEnvOffset = static_cast<int32_t>(GlobalEnv::HEADER_SIZE);
return const_cast<ArkSteedGraphBuilder *>(this)->NewVertex<LoadTaggedFieldVertex>({lexicalEnv},
globalEnvOffset);
}
ValueVertex *GetSharedConstPool()
{
ValueVertex *jsFunc = currentFrameState_->GetParam(CALL_TARGET_PARAM_INDEX);
int32_t methodOffset = static_cast<int32_t>(JSFunctionBase::METHOD_OFFSET);
ValueVertex *method = NewVertex<LoadTaggedFieldVertex>({jsFunc}, methodOffset);
int32_t constpoolOffset = static_cast<int32_t>(Method::CONSTANT_POOL_OFFSET);
return NewVertex<LoadTaggedFieldVertex>({method}, constpoolOffset);
}
ValueVertex *GetModuleFromFunction()
{
ValueVertex *jsFunc = currentFrameState_->GetParam(CALL_TARGET_PARAM_INDEX);
int32_t moduleOffset = static_cast<int32_t>(JSFunction::ECMA_MODULE_OFFSET);
return NewVertex<LoadTaggedFieldVertex>({jsFunc}, moduleOffset);
}
ValueVertex *GetStringFromConstPool(ValueVertex *stringId)
{
ValueVertex *glue = GetGlue();
ValueVertex *constpool = GetSharedConstPool();
return NewCommonStubCall({glue, constpool, stringId}, CommonStubCSigns::GetStringFromConstPool);
}
ValueVertex *GetObjectFromConstPool(ValueVertex *index)
{
ValueVertex *glue = GetGlue();
ValueVertex *constpool = GetSharedConstPool();
ValueVertex *module = GetModuleFromFunction();
return NewCommonStubCall({glue, constpool, index, module}, CommonStubCSigns::GetObjectFromConstPool);
}
ValueVertex *GetMethodFromConstPool(ValueVertex *index)
{
ValueVertex *constpool = GetSharedConstPool();
return NewVertex<CallRuntimeVertex>({constpool, index}, RTSTUB_ID(GetMethodFromCache));
}
ValueVertex *GetValueFromTaggedArray(ValueVertex *array, uint32_t index)
{
int32_t offset = static_cast<int32_t>(TaggedArray::DATA_OFFSET + index * JSTaggedValue::TaggedTypeSize());
return NewVertex<LoadTaggedFieldVertex>({array}, offset);
}
ValueVertex *SetValueToTaggedArray(ValueVertex *array, uint32_t index, ValueVertex *value)
{
int32_t offset = static_cast<int32_t>(TaggedArray::DATA_OFFSET + index * JSTaggedValue::TaggedTypeSize());
return NewVertex<StoreTaggedFieldVertex>({array, value}, offset);
}
ValueVertex *GetTaggedArrayFromValueIn(uint32_t inputSize, uint32_t startIndex = 0)
{
ASSERT(startIndex + inputSize <= GetInputSize());
ValueVertex *taggedLength = NewTaggedVertexFromRawInt32(static_cast<int>(inputSize));
ValueVertex *taggedArray = NewVertex<CallRuntimeVertex>({taggedLength}, RTSTUB_ID(NewTaggedArray));
for (uint32_t idx = 0; idx < inputSize; ++idx) {
ValueVertex *arg = LoadRegister(startIndex + idx);
SetValueToTaggedArray(taggedArray, idx, arg);
}
return taggedArray;
}
ValueVertex *GetTaggedLength(uint32_t inputSize)
{
return NewTaggedVertexFromRawInt32(static_cast<int>(inputSize));
}
ValueVertex *GetLexicalEnv(ValueVertex *jsFunc)
{
int32_t lexEnvOffset = static_cast<int32_t>(JSFunction::LEXICAL_ENV_OFFSET);
return NewVertex<LoadTaggedFieldVertex>({jsFunc}, lexEnvOffset);
}
ValueVertex *LoadRegister(int index) const
{
auto info = iterator_.GetCurrentBytecodeInfo();
auto &input = info.inputs[index];
ASSERT(std::holds_alternative<VirtualRegister>(input));
return currentFrameState_->Get(std::get<VirtualRegister>(input));
}
ValueVertex *NewTaggedVertexFromRawInt32(int number)
{
return GetTaggedConstant(JSTaggedValue(number).GetRawData());
}
ValueVertex *GetHeapConstant(const ArkSteedHeapRef &ref)
{
ASSERT(ref.IsSafeForCompile());
if (!ref.IsHeapObject()) {
return GetTaggedConstant(ref.Value().GetRawData());
}
LOG_COMPILER(FATAL) << "AccessInfo heap objects are compile-time only and must not be embedded in codegen.";
UNREACHABLE();
}
ICSlotIdType GetICSlotId(int index) const
{
auto info = iterator_.GetCurrentBytecodeInfo();
auto &input = info.inputs[index];
ASSERT(std::holds_alternative<ICSlotId>(input));
return std::get<ICSlotId>(input).GetId();
}
uint16_t GetConstDataId(int index) const
{
auto info = iterator_.GetCurrentBytecodeInfo();
auto &input = info.inputs[index];
ASSERT(std::holds_alternative<ConstDataId>(input));
return std::get<ConstDataId>(input).GetId();
}
ImmValueType GetImmediate(int index) const
{
auto info = iterator_.GetCurrentBytecodeInfo();
auto &input = info.inputs[index];
ASSERT(std::holds_alternative<Immediate>(input));
return std::get<Immediate>(input).GetValue();
}
uint32_t GetInputSize() const
{
auto info = iterator_.GetCurrentBytecodeInfo();
return info.inputs.size();
}
InterpreterFrameState *CurrentFrameState()
{
return currentFrameState_;
}
const InterpreterFrameState *CurrentFrameState() const
{
return currentFrameState_;
}
template <typename ControlVertexT, typename... Args>
BB *FinishBlock(std::initializer_list<ValueVertex *> controlInputs, Args &&...args)
{
ControlVertexT *control = NewControlVertex<ControlVertexT>(controlInputs, std::forward<Args>(args)...);
BB *block = CurrentBlock();
GetGraph()->Add(block);
SetCurrentBlock(nullptr);
LOG_COMPILER(DEBUG) << "Block #" << block->GetId() << " finished";
return block;
}
class ReduceResult {
public:
enum class Kind : uint8_t {
DONE_WITH_PAYLOAD,
DONE_WITHOUT_PAYLOAD,
DONE_WITH_ABORT,
};
static ReduceResult Done(ValueVertex *value)
{
ASSERT(value != nullptr);
return ReduceResult(Kind::DONE_WITH_PAYLOAD, value);
}
static ReduceResult Done()
{
return ReduceResult(Kind::DONE_WITHOUT_PAYLOAD, nullptr);
}
static ReduceResult DoneWithAbort()
{
return ReduceResult(Kind::DONE_WITH_ABORT, nullptr);
}
bool IsDoneWithValue() const
{
return kind_ == Kind::DONE_WITH_PAYLOAD;
}
bool IsDoneWithAbort() const
{
return kind_ == Kind::DONE_WITH_ABORT;
}
ValueVertex *Value() const
{
ASSERT(IsDoneWithValue());
return value_;
}
private:
explicit ReduceResult(Kind kind, ValueVertex *value) : kind_(kind), value_(value) {}
Kind kind_;
ValueVertex *value_;
};
enum class BranchResult : uint8_t {
DEFAULT,
ALWAYS_TRUE,
ALWAYS_FALSE,
ABORT,
};
private:
enum class BranchType : uint8_t { TRUE_BRANCH, FALSE_BRANCH };
class BranchBuilder;
public:
ReduceResult Select(CallbackRef<BranchResult(BranchBuilder &)> cond, CallbackRef<ReduceResult()> ifTrue,
CallbackRef<ReduceResult()> ifFalse);
private:
ValueVertex *NewCallStubWithIC(const CommonStubCSigns::ID stubId, const std::vector<ValueVertex *> &args);
void LowerCallStubWithIC(const CommonStubCSigns::ID stubId, const std::vector<ValueVertex *> &args);
void LowerCallStubWithICPreserveAcc(const CommonStubCSigns::ID stubId, const std::vector<ValueVertex *> &args);
ValueVertex *NewCommonStubCall(std::initializer_list<ValueVertex *> args, const CommonStubCSigns::ID stubId);
void ValidateCommonStubCallArgs(const CommonStubCSigns::ID stubId, const std::vector<ValueVertex *> &args) const;
void MergeCurrentFrameStateTo(BB *predecessor, uint32_t destIndex);
void StartNewBlock(BB *predecessor, MergePointFrameState *mergeState, BBRef *refsToBlock);
void StartNewBlockWithMergeState(uint32_t index);
void ProcessMergePointPredecessors(MergePointFrameState *mergeState, BBRef *ref, BB *mergeBlock);
void TrySplitCriticalEdge(MergePointFrameState *mergeState, BBRef *ref, BB *mergeBlock, uint32_t predIndex);
class ArkSteedSubGraphBuilder {
public:
class SubGraphVariable {
public:
explicit SubGraphVariable(int index) : pseudoRegister_(VRegOfLocal(index)) {}
private:
friend class ArkSteedSubGraphBuilder;
VirtualRegister pseudoRegister_;
};
class Label {
public:
Label(ArkSteedSubGraphBuilder *subBuilder, uint32_t predecessorCount);
Label(ArkSteedSubGraphBuilder *subBuilder, uint32_t predecessorCount,
std::initializer_list<SubGraphVariable *> liveVariables);
private:
friend class ArkSteedSubGraphBuilder;
friend class BranchBuilder;
ArkSteedSubGraphBuilder *subBuilder_;
uint32_t predecessorCount_;
MergePointFrameState *variableMergeState_ = nullptr;
LivenessBitSet *mergeLiveSet_ = nullptr;
BBRef ref_;
};
class LoopLabel {
public:
LoopLabel(ArkSteedSubGraphBuilder *subBuilder, MergePointFrameState *mergeState, BBRef *loopHeaderRef,
BB *loopHeaderBlock)
: subBuilder_(subBuilder),
mergeState_(mergeState),
loopHeaderRef_(loopHeaderRef),
loopHeaderBlock_(loopHeaderBlock)
{}
private:
friend class ArkSteedSubGraphBuilder;
ArkSteedSubGraphBuilder *subBuilder_;
MergePointFrameState *mergeState_;
BBRef *loopHeaderRef_;
BB *loopHeaderBlock_;
};
ArkSteedSubGraphBuilder(ArkSteedGraphBuilder *builder, int variableCount);
void Set(const SubGraphVariable &var, ValueVertex *value)
{
subGraphFrame_->Set(var.pseudoRegister_, value);
}
ValueVertex *Get(const SubGraphVariable &var) const
{
return subGraphFrame_->Get(var.pseudoRegister_);
}
LoopLabel BeginLoop(std::initializer_list<SubGraphVariable *> loopVars);
void EndLoop(LoopLabel *loopLabel);
template <typename ControlVertexT, typename... Args>
ReduceResult GotoIfTrue(Label *trueTarget, std::initializer_list<ValueVertex *> controlInputs, Args &&...args);
template <typename ControlVertexT, typename... Args>
ReduceResult GotoIfFalse(Label *falseTarget, std::initializer_list<ValueVertex *> controlInputs,
Args &&...args);
void Goto(Label *label);
void GotoOrTrim(Label *label);
void Bind(Label *label);
ReduceResult TrimPredecessorsAndBind(Label *label);
void TrimUnmergedPredecessors(Label *label, uint32_t num = 1);
ReduceResult Branch(std::initializer_list<SubGraphVariable *> vars,
CallbackRef<BranchResult(BranchBuilder &)> cond,
CallbackRef<ReduceResult()> ifTrue,
CallbackRef<ReduceResult()> ifFalse);
private:
friend class BranchBuilder;
void MergeIntoLabel(Label *label, BB *predecessor);
ArkSteedGraphBuilder *builder_;
VRegIDType numLocal_;
VRegIDType numParams_;
InterpreterFrameState *subGraphFrame_;
};
static inline BranchType ReverseBranchType(BranchType jumpType)
{
switch (jumpType) {
case BranchType::TRUE_BRANCH:
return BranchType::FALSE_BRANCH;
case BranchType::FALSE_BRANCH:
return BranchType::TRUE_BRANCH;
}
}
class BranchBuilder {
public:
enum Mode {
JUMP_BYTECODE_TARGET,
JUMP_LABEL_TARGET,
};
struct BytecodeJumpTarget {
BytecodeJumpTarget(uint32_t jumpTargetBcIndex, uint32_t fallthroughBcIndex)
: jumpTargetBcIndex(jumpTargetBcIndex), fallthroughBcIndex(fallthroughBcIndex)
{}
uint32_t jumpTargetBcIndex;
uint32_t fallthroughBcIndex;
};
struct JumpLabel {
explicit JumpLabel(ArkSteedSubGraphBuilder::Label *jumpLabel) : jumpLabel(jumpLabel), fallthroughTarget {}
{}
ArkSteedSubGraphBuilder::Label *jumpLabel;
BBRef fallthroughTarget;
BB *fallthroughBlock = nullptr;
};
union Data {
Data(uint32_t jumpTargetBcIndex, uint32_t fallthroughBcIndex)
: bytecodeTarget(jumpTargetBcIndex, fallthroughBcIndex)
{}
explicit Data(ArkSteedSubGraphBuilder::Label *jumpLabel) : labelTarget(jumpLabel) {}
BytecodeJumpTarget bytecodeTarget;
JumpLabel labelTarget;
};
BranchBuilder(ArkSteedGraphBuilder *builder, BranchType jumpType)
: builder_(builder),
subBuilder_(nullptr),
jumpType_(jumpType),
data_(builder_->iterator_.GetJumpTargetBcIndex(), builder_->iterator_.NextIndex())
{}
BranchBuilder(ArkSteedGraphBuilder *builder, ArkSteedSubGraphBuilder *subBuilder, BranchType jumpType,
ArkSteedSubGraphBuilder::Label *jumpLabel)
: builder_(builder), subBuilder_(subBuilder), jumpType_(jumpType), data_(jumpLabel)
{}
Mode GetMode() const
{
return subBuilder_ == nullptr ? JUMP_BYTECODE_TARGET : JUMP_LABEL_TARGET;
}
BranchType GetCurrentBranchType() const
{
return jumpType_;
}
uint32_t JumpTargetBcIndex() const
{
ASSERT(GetMode() == JUMP_BYTECODE_TARGET);
return data_.bytecodeTarget.jumpTargetBcIndex;
}
uint32_t FallthroughBcIndex() const
{
ASSERT(GetMode() == JUMP_BYTECODE_TARGET);
return data_.bytecodeTarget.fallthroughBcIndex;
}
ArkSteedSubGraphBuilder::Label *JumpLabel() const
{
ASSERT(GetMode() == JUMP_LABEL_TARGET);
return data_.labelTarget.jumpLabel;
}
ArkSteedSubGraphBuilder *SubBuilder() const
{
ASSERT(GetMode() == JUMP_LABEL_TARGET);
return subBuilder_;
}
void SwapTargets()
{
jumpType_ = ReverseBranchType(jumpType_);
}
BBRef *JumpTarget();
BBRef *FallThrough();
BBRef *TrueTarget();
BBRef *FalseTarget();
template <typename ControlVertexT, typename... Args>
void Build(std::initializer_list<ValueVertex *> inputs, Args &&...args);
private:
ArkSteedGraphBuilder *builder_;
ArkSteedSubGraphBuilder *subBuilder_;
BranchType jumpType_;
Data data_;
void StartFallthroughBlock(BB *predecessor);
};
BranchBuilder CreateBranchBuilder(BranchType jumpType)
{
return BranchBuilder(this, jumpType);
}
BranchResult BuildBranchIfTrue(BranchBuilder &builder, ValueVertex *vertex);
void InitializeGraph();
void InitializeGlobalsAndParameters();
void InitializeCurrentFrameState();
void BuildMergeStates();
void BuildBody();
void ValidateAfterBuilding();
uint32_t PredecessorCount(uint32_t index) const;
void ReduceBytecodePredecessorCount(uint32_t index, uint32_t num = 1);
void MarkDeadLoopBackedge(uint32_t index);
void MarkDeadPredecessorsForSuccessors(uint32_t index, const BytecodeInfo &bytecodeInfo);
const LivenessBitSet *GetInLivenessFor(uint32_t index) const;
void ValidateMergeStateAfterBuilding(uint32_t index, MergePointFrameState *mergeState);
void ProcessBytecode();
void LowerLoadString();
void LowerLoadBigInt();
void LowerLoadConst(const BytecodeInfo &info, kungfu::EcmaOpcode opcode);
void LowerMoveValues(const BytecodeInfo &info);
void LowerCreateEmptyObject();
void LowerCreateEmptyArray();
void LowerCreateObjectWithBuffer();
void LowerCreateArrayWithBuffer();
void LowerCreateObjectWithExcludedKeys();
void LowerCreateRegExpWithLiteral();
void LowerNewObjRange();
void LowerAdd2();
void LowerSub2();
void LowerMul2();
void LowerDiv2();
void LowerMod2();
void LowerExp();
void LowerNeg();
void LowerInc();
void LowerDec();
void LowerShl2();
void LowerShr2();
void LowerAshr2();
void LowerAnd2();
void LowerOr2();
void LowerXor2();
void LowerNot();
void LowerEq();
void LowerNotEq();
void LowerLess();
void LowerLessEq();
void LowerGreater();
void LowerGreaterEq();
void LowerStrictEq();
void LowerStrictNotEq();
void LowerTypeOf();
void LowerToNumber();
void LowerToNumeric();
void LowerIsIn();
void LowerInstanceOf();
void LowerTestIn();
void LowerJumpConstant();
void LowerJumpIfTrue();
void LowerJumpIfFalse();
void LowerCallArg0();
void LowerCallArg1();
void LowerCallArgs2();
void LowerCallArgs3();
void LowerCallRange();
void LowerReturn(kungfu::EcmaOpcode opcode);
void LowerThrow();
void LowerLoadObjByName();
void LowerStoreObjByName();
void LowerLoadObjByValue();
void LowerStoreObjByValue();
void LowerLdObjByIndex();
void LowerStObjByIndex();
void LowerGetIterator();
void LowerGetPropIterator();
void LowerCloseIterator();
void LowerGetNextPropName();
void LowerGetTemplateObject();
void LowerStoreArraySpread();
void LowerCallThis0();
void LowerCallThis1();
void LowerCallThis2();
void LowerCallThis3();
void LowerCallThisRange();
void LowerCallSpread();
void LowerGetUnmappedArgs();
void LowerCreateIterResultObj();
void LowerTryLdGlobalByName();
void LowerStGlobalVar();
void LowerNewObjApply();
void LowerThrowConstAssignment();
void LowerThrowNotExists();
void LowerThrowPatternNonCoercible();
void LowerThrowIfNotObject();
void LowerThrowUndefinedIfHole();
void LowerThrowUndefinedIfHoleWithName();
void LowerThrowIfSuperNotCorrectCall();
void LowerThrowDeleteSuperProperty();
void LowerLdSymbol();
void LowerLdGlobal();
void LowerDelObjProp();
void LowerDefineMethod();
void LowerStModuleVar();
void LowerSetObjectWithProto();
void LowerDynamicImport();
void LowerLdExternalModuleVar();
void LowerGetModuleNamespace();
void LowerSuperCallThisRange();
void LowerSuperCallArrowRange();
void LowerSuperCallSpread();
void LowerSuperCallForwardAllArgs();
void LowerIsTrueOrFalse(bool isTrue);
void LowerCopyDataProperties();
void LowerStOwnByValue();
void LowerStOwnByIndex();
void LowerStOwnByName();
void LowerNewLexicalEnv();
void LowerNewLexicalEnvWithName();
void LowerPopLexicalEnv();
void LowerLdSuperByValue();
void LowerStSuperByValue();
void LowerTryStGlobalByName();
void LowerStConstToGlobalRecord(bool isConst);
void LowerStOwnByValueWithNameSet();
void LowerStOwnByNameWithNameSet();
void LowerLdGlobalVar();
void LowerDefineGetterSetterByValue();
void LowerLdThisByValue();
void LowerStThisByValue();
void LowerLdSuperByName();
void LowerStSuperByName();
void LowerLdLexVar();
void LowerStLexVar();
void LowerDefineClassWithBuffer();
void LowerDefineFunc();
void LowerCopyRestArgs();
void LowerLdPatchVar();
void LowerStPatchVar();
void LowerLdLocalModuleVar();
void LowerLdThisByName();
void LowerStThisByName();
void LowerLdPrivateProperty();
void LowerStPrivateProperty();
void LowerNotifyConcurrentResult();
void LowerDefinePropertyByName();
void LowerDefineFieldByName();
void LowerDefineFieldByValue();
void LowerDefineFieldByIndex();
void LowerToPropertyKey();
void LowerCreatePrivateProperty();
void LowerDefinePrivateProperty();
void BuildThrow(kungfu::RuntimeStubCSigns::ID id, ValueVertex *input);
bool HasTryCatch() const
{
return bytecodeContext_.HasTryCatch();
}
const ExceptionInfo &GetExceptionInfo() const
{
return bytecodeContext_.GetExceptionInfo();
}
std::string VRegDisplayString(VirtualRegister vreg) const
{
return arksteed::VRegDisplayString(vreg, numLocal_, numParams_);
}
[[maybe_unused]] JSThread *compilerThread_;
uintptr_t glueAddr_{0};
JitCompilationEnv *env_;
ArkSteedPGOContext pgoContext_;
ValueVertex *glue_{nullptr};
ArkSteedCompilationOptions options_;
BytecodeContext bytecodeContext_;
BytecodeIterator iterator_;
ChunkVector<MergePointFrameState *> mergeStates_;
ChunkVector<uint32_t> predecessorCountReductions_;
ChunkVector<BBRef> jumpTargets_;
BB *startBlock_{nullptr};
MethodLiteral *method_{nullptr};
InterpreterFrameState *currentFrameState_{nullptr};
BytecodeAnalysis *bytecodeAnalysis_{nullptr};
VRegIDType numLocal_;
VRegIDType numParams_;
size_t entryPoint_ = 0;
};
template <typename ControlVertexT, typename... Args>
inline ArkSteedGraphBuilder::ReduceResult ArkSteedGraphBuilder::ArkSteedSubGraphBuilder::GotoIfTrue(
Label *trueTarget, std::initializer_list<ValueVertex *> controlInputs, Args &&...args)
{
if (builder_->CurrentBlock() == nullptr) {
TrimUnmergedPredecessors(trueTarget);
return ReduceResult::DoneWithAbort();
}
BranchBuilder branchBuilder(builder_, this, BranchType::TRUE_BRANCH, trueTarget);
branchBuilder.Build<ControlVertexT>(controlInputs, std::forward<Args>(args)...);
return ReduceResult::Done();
}
template <typename ControlVertexT, typename... Args>
inline ArkSteedGraphBuilder::ReduceResult ArkSteedGraphBuilder::ArkSteedSubGraphBuilder::GotoIfFalse(
Label *falseTarget, std::initializer_list<ValueVertex *> controlInputs, Args &&...args)
{
if (builder_->CurrentBlock() == nullptr) {
TrimUnmergedPredecessors(falseTarget);
return ReduceResult::DoneWithAbort();
}
BranchBuilder branchBuilder(builder_, this, BranchType::FALSE_BRANCH, falseTarget);
branchBuilder.Build<ControlVertexT>(controlInputs, std::forward<Args>(args)...);
return ReduceResult::Done();
}
template <typename ControlVertexT, typename... Args>
inline void ArkSteedGraphBuilder::BranchBuilder::Build(std::initializer_list<ValueVertex *> controlInputs,
Args &&...args)
{
BB *result =
builder_->FinishBlock<ControlVertexT>(controlInputs, std::forward<Args>(args)..., TrueTarget(), FalseTarget());
StartFallthroughBlock(result);
}
}
#endif