Add loop exit for loop peeling

Issue: I6QTH5
Signed-off-by: sunzhe23 <sunzhe23@huawei.com>
This commit is contained in:
sunzhe23 2023-04-03 16:33:32 +08:00
parent 13caea9137
commit f717c511ce
19 changed files with 699 additions and 196 deletions

View File

@ -99,6 +99,7 @@ ohos_source_set("libark_jsoptimizer_set") {
"later_elimination.cpp",
"llvm_codegen.cpp",
"llvm_ir_builder.cpp",
"loop_analysis.cpp",
"new_object_stub_builder.cpp",
"number_speculative_lowering.cpp",
"number_speculative_retype.cpp",

View File

@ -47,6 +47,7 @@ void BytecodeCircuitBuilder::BuildRegionInfo()
auto &info = infoData_[index];
auto pc = pcOffsets_[index];
info.metaData_ = bytecodes_->GetBytecodeMetaData(pc);
ASSERT(!info.metaData_.IsInvalid());
BytecodeInfo::InitBytecodeInfo(this, info, pc);
CollectRegionInfo(index);
}
@ -614,34 +615,12 @@ void BytecodeCircuitBuilder::CollectPredsInfo()
succ->numOfStatePreds++;
}
}
// collect loopback edges
std::vector<VisitState> visitState(graph_.size(), VisitState::UNVISITED);
std::function<void(size_t)> dfs = [&](size_t bbId) -> void {
visitState[bbId] = VisitState::PENDING;
std::vector<BytecodeRegion *> merge;
merge.insert(merge.end(), graph_[bbId].succs.begin(), graph_[bbId].succs.end());
merge.insert(merge.end(), graph_[bbId].catchs.begin(), graph_[bbId].catchs.end());
auto it = merge.crbegin();
while (it != merge.crend()) {
auto succBlock = *it;
it++;
if (visitState[succBlock->id] == VisitState::UNVISITED) {
dfs(succBlock->id);
} else {
if (visitState[succBlock->id] == VisitState::PENDING) {
graph_[succBlock->id].loopbackBlocks.insert(bbId);
}
}
}
visitState[bbId] = VisitState::VISITED;
};
dfs(graph_[0].id);
loopAnalysis_.Run();
for (auto &bb: graph_) {
if (bb.isDead) {
continue;
}
bb.phiAcc = (bb.numOfStatePreds > 1) || (!bb.trys.empty());
bb.numOfLoopBacks = bb.loopbackBlocks.size();
}
}
@ -654,43 +633,49 @@ void BytecodeCircuitBuilder::NewMerge(GateRef &state, GateRef &depend, size_t nu
gateAcc_.NewIn(depend, 0, state);
}
void BytecodeCircuitBuilder::NewLoopBegin(BytecodeRegion &bb)
void BytecodeCircuitBuilder::NewLoopBegin(BytecodeRegion &bb, GateRef &state, GateRef &depend)
{
if (bb.id == 0 && bb.numOfStatePreds == 1) {
bb.mergeForwardEdges = circuit_->NewGate(circuit_->Merge(bb.numOfStatePreds),
std::vector<GateRef>(bb.numOfStatePreds,
circuit_->GetStateRoot()));
bb.depForward = circuit_->NewGate(circuit_->DependSelector(bb.numOfStatePreds),
std::vector<GateRef>(bb.numOfStatePreds + 1, Circuit::NullGate()));
gateAcc_.NewIn(bb.depForward, 0, bb.mergeForwardEdges);
gateAcc_.NewIn(bb.depForward, 1, circuit_->GetDependRoot());
} else {
NewMerge(bb.mergeForwardEdges, bb.depForward, bb.numOfStatePreds - bb.numOfLoopBacks);
if (bb.numOfLoopBacks > 1) {
NewMerge(bb.loopBackStateMerge, bb.loopBackDependMerge, bb.numOfLoopBacks);
}
NewMerge(bb.mergeLoopBackEdges, bb.depLoopBack, bb.numOfLoopBacks);
auto loopBack = circuit_->NewGate(circuit_->LoopBack(),
{ bb.mergeLoopBackEdges });
bb.stateStart = circuit_->NewGate(circuit_->LoopBegin(),
{ bb.mergeForwardEdges, loopBack });
auto loopBack = circuit_->NewGate(circuit_->LoopBack(), { Circuit::NullGate() });
auto loopBegin = circuit_->NewGate(circuit_->LoopBegin(), { Circuit::NullGate(), loopBack });
// 2: the number of depend inputs and it is in accord with LOOP_BEGIN
bb.dependStart = circuit_->NewGate(circuit_->DependSelector(2),
{ bb.stateStart, bb.depForward, bb.depLoopBack });
auto loopDepend = circuit_->NewGate(circuit_->DependSelector(2),
{ loopBegin, Circuit::NullGate(), Circuit::NullGate() });
state = loopBegin;
depend = loopDepend;
}
void BytecodeCircuitBuilder::BuildBlockCircuitHead()
void BytecodeCircuitBuilder::NewLoopExit(BytecodeRegion &bb, GateRef &state, GateRef &depend)
{
for (auto &bb: graph_) {
if (bb.isDead) {
continue;
}
if (bb.numOfStatePreds == 0) {
bb.stateStart = circuit_->GetStateRoot();
bb.dependStart = circuit_->GetDependRoot();
} else if (bb.numOfLoopBacks > 0) {
NewLoopBegin(bb);
} else {
NewMerge(bb.stateStart, bb.dependStart, bb.numOfStatePreds);
}
auto loopExit = circuit_->NewGate(circuit_->LoopExit(),
{ Circuit::NullGate(), Circuit::NullGate() });
depend = circuit_->NewGate(circuit_->LoopExitDepend(),
{ loopExit, Circuit::NullGate() });
state = loopExit;
bb.loopExitState = loopExit;
bb.loopExitDepend = depend;
}
void BytecodeCircuitBuilder::BuildBlockCircuitHead(BytecodeRegion &bb, GateRef &state, GateRef &depend)
{
auto mergeCount = bb.numOfStatePreds - bb.numOfLoopBacks;
if (mergeCount == 0) {
state = circuit_->GetStateRoot();
depend = circuit_->GetDependRoot();
}
if (bb.isLoopExit) {
NewLoopExit(bb, state, depend);
}
if (mergeCount > 1) {
NewMerge(bb.stateMerge, bb.dependMerge, mergeCount);
state = bb.stateMerge;
depend = bb.dependMerge;
}
if (bb.numOfLoopBacks > 0) {
NewLoopBegin(bb, state, depend);
}
}
@ -736,24 +721,97 @@ std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
return inList;
}
void BytecodeCircuitBuilder::SetBlockPred(BytecodeRegion &bbNext, const GateRef &state,
const GateRef &depend, bool isLoopBack)
void BytecodeCircuitBuilder::SetLoopBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext,
GateRef &state, GateRef &depend)
{
if (bbNext.numOfLoopBacks == 0) {
gateAcc_.NewIn(bbNext.stateStart, bbNext.statePredIndex, state);
gateAcc_.NewIn(bbNext.dependStart, bbNext.statePredIndex + 1, depend);
} else {
if (isLoopBack) {
gateAcc_.NewIn(bbNext.mergeLoopBackEdges, bbNext.loopBackIndex, state);
gateAcc_.NewIn(bbNext.depLoopBack, bbNext.loopBackIndex + 1, depend);
bbNext.loopBackIndex++;
ASSERT(bbNext.loopBackIndex <= bbNext.numOfLoopBacks);
} else {
gateAcc_.NewIn(bbNext.mergeForwardEdges, bbNext.forwardIndex, state);
gateAcc_.NewIn(bbNext.depForward, bbNext.forwardIndex + 1, depend);
bbNext.forwardIndex++;
ASSERT(bbNext.forwardIndex <= bbNext.numOfStatePreds - bbNext.numOfLoopBacks);
ASSERT(bbNext.numOfLoopBacks > 0);
ASSERT(gateAcc_.GetOpCode(bbNext.stateCurrent) == OpCode::LOOP_BEGIN);
ASSERT(gateAcc_.GetOpCode(bbNext.dependCurrent) == OpCode::DEPEND_SELECTOR);
// loop back
if (bbNext.loopbackBlocks.count(bb.id)) {
if (bbNext.loopBackStateMerge != Circuit::NullGate()) {
ASSERT(bbNext.loopBackDependMerge != Circuit::NullGate());
gateAcc_.NewIn(bbNext.loopBackStateMerge, bbNext.loopBackIndex, state);
gateAcc_.NewIn(bbNext.loopBackDependMerge, bbNext.loopBackIndex + 1, depend);
state = bbNext.loopBackStateMerge;
depend = bbNext.loopBackDependMerge;
}
if (bbNext.loopBackIndex == 0) {
auto loopBack = gateAcc_.GetState(bbNext.stateCurrent, 1); // 1: LoopBack
gateAcc_.NewIn(loopBack, 0, state);
gateAcc_.NewIn(bbNext.dependCurrent, 2, depend); // 2: loopback depend
}
bbNext.loopBackIndex++;
ASSERT(bbNext.loopBackIndex <= bbNext.numOfLoopBacks);
} else {
if (bbNext.stateMerge != Circuit::NullGate()) {
ASSERT(bbNext.dependMerge != Circuit::NullGate());
gateAcc_.NewIn(bbNext.stateMerge, bbNext.forwardIndex, state);
gateAcc_.NewIn(bbNext.dependMerge, bbNext.forwardIndex + 1, depend);
state = bbNext.stateMerge;
depend = bbNext.dependMerge;
}
if (bbNext.forwardIndex == 0) {
gateAcc_.NewIn(bbNext.stateCurrent, 0, state);
gateAcc_.NewIn(bbNext.dependCurrent, 1, depend); // 1: first depend
}
bbNext.forwardIndex++;
ASSERT(bbNext.forwardIndex <= bbNext.numOfStatePreds - bbNext.numOfLoopBacks);
}
}
void BytecodeCircuitBuilder::SetLoopExitBlockPred(
BytecodeRegion &bb, GateRef &state, GateRef &depend)
{
// for two loopexit merge case
if (!gateAcc_.IsInGateNull(bb.loopExitState, 0)) {
return;
}
ASSERT(gateAcc_.GetOpCode(bb.loopExitState) == OpCode::LOOP_EXIT);
ASSERT(gateAcc_.GetOpCode(bb.loopExitDepend) == OpCode::LOOP_EXIT_DEPEND);
auto &loopHead = graph_[bb.loopHead];
ASSERT(gateAcc_.GetOpCode(loopHead.stateCurrent) == OpCode::LOOP_BEGIN);
ASSERT(gateAcc_.GetOpCode(loopHead.dependCurrent) == OpCode::DEPEND_SELECTOR);
gateAcc_.NewIn(bb.loopExitState, 0, state);
gateAcc_.NewIn(bb.loopExitState, 1, loopHead.stateCurrent); // 1: loop begin
gateAcc_.NewIn(bb.loopExitDepend, 1, depend); // 1: dependMerge
state = bb.loopExitState;
depend = bb.loopExitDepend;
}
void BytecodeCircuitBuilder::SetBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext,
const GateRef &state, const GateRef &depend)
{
// Init block head if not exists
if (bbNext.stateCurrent == Circuit::NullGate()) {
ASSERT(bbNext.dependCurrent == Circuit::NullGate());
BuildBlockCircuitHead(bbNext, bbNext.stateCurrent, bbNext.dependCurrent);
// no loop exit, no loop head, no merge bb
if (bbNext.stateCurrent == Circuit::NullGate()) {
ASSERT(bbNext.dependCurrent == Circuit::NullGate());
bbNext.stateCurrent = state;
bbNext.dependCurrent = depend;
bbNext.statePredIndex++;
return;
}
}
auto stateCur = state;
auto dependCur = depend;
// Init loop exit
if (bbNext.isLoopExit && bb.isLoopBody && bb.loopHead == bbNext.loopHead) {
SetLoopExitBlockPred(bbNext, stateCur, dependCur);
}
// loop bb
if (bbNext.numOfLoopBacks > 0) {
SetLoopBlockPred(bb, bbNext, stateCur, dependCur);
bbNext.statePredIndex++;
return;
}
// merge bb
if (bbNext.stateMerge != Circuit::NullGate()) {
ASSERT(bbNext.dependMerge != Circuit::NullGate());
gateAcc_.NewIn(bbNext.stateMerge, bbNext.statePredIndex, stateCur);
gateAcc_.NewIn(bbNext.dependMerge, bbNext.statePredIndex + 1, dependCur); // 1: skip state
}
bbNext.statePredIndex++;
ASSERT(bbNext.statePredIndex <= bbNext.numOfStatePreds);
@ -868,8 +926,7 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateR
if (!bb.catchs.empty()) {
auto &bbNext = bb.catchs.at(0);
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
SetBlockPred(*bbNext, gate, gate, isLoopBack);
SetBlockPred(bb, *bbNext, gate, gate);
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
} else {
auto constant = circuit_->GetConstantGate(MachineType::I64,
@ -885,8 +942,7 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateR
auto ifException = circuit_->NewGate(circuit_->IfException(), {gate, gate});
auto &bbNext = bb.catchs.at(0);
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
SetBlockPred(*bbNext, ifException, ifException, isLoopBack);
SetBlockPred(bb, *bbNext, ifException, ifException);
if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
bbNext->expandedPreds.push_back({bb.id, iterator.Index() + 1, true}); // 1: next pc
} else {
@ -909,12 +965,6 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateR
suspendAndResumeGates_.emplace_back(gate);
}
depend = gate;
if (iterator.Index() == bb.end) {
auto &bbNext = graph_[bb.id + 1];
auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
SetBlockPred(bbNext, state, depend, isLoopBack);
bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
}
}
void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef &depend)
@ -924,7 +974,6 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
auto offset = GetJumpOffset(iterator.Index());
if (bytecodeInfo.IsCondJump()) {
ASSERT(!bytecodeInfo.Deopt());
size_t pcOffset = GetPcOffset(iterator.Index());
auto meta = circuit_->JSBytecode(numValueInputs, bytecodeInfo.GetOpcode(), pcOffset, false, false);
auto numValues = meta->GetNumIns();
@ -947,9 +996,8 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
if (bb.succs.size() == 1) {
auto &bbNext = bb.succs[0];
ASSERT(bbNext->id == bb.id + 1);
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
SetBlockPred(*bbNext, ifFalse, falseRelay, isLoopBack);
SetBlockPred(*bbNext, ifTrue, trueRelay, isLoopBack);
SetBlockPred(bb, *bbNext, ifFalse, falseRelay);
SetBlockPred(bb, *bbNext, ifTrue, trueRelay);
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
} else {
@ -957,13 +1005,11 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
[[maybe_unused]] uint32_t bitSet = 0;
for (auto &bbNext: bb.succs) {
if (bbNext->id == bb.id + 1) {
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
SetBlockPred(*bbNext, ifFalse, falseRelay, isLoopBack);
SetBlockPred(bb, *bbNext, ifFalse, falseRelay);
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
bitSet |= 1;
} else {
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
SetBlockPred(*bbNext, ifTrue, trueRelay, isLoopBack);
SetBlockPred(bb, *bbNext, ifTrue, trueRelay);
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
bitSet |= 2; // 2:verify
}
@ -974,7 +1020,6 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
} else {
ASSERT(bb.succs.size() == 1);
auto &bbNext = bb.succs.at(0);
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
if (offset < 0) {
// place update hotness Gate when offset is negative.
auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
@ -982,10 +1027,10 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
GateType::NJSValue());
GateRef jsFunc = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate, jsFunc});
SetBlockPred(*bbNext, updateHotness, updateHotness, isLoopBack);
} else {
SetBlockPred(*bbNext, state, depend, isLoopBack);
state = updateHotness;
depend = updateHotness;
}
SetBlockPred(bb, *bbNext, state, depend);
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
}
}
@ -1024,12 +1069,6 @@ void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb, GateRef &state, Gat
// handle bytecode command to get constants
GateRef gate = NewConst(bytecodeInfo);
byteCodeToJSGate_[iterator.Index()] = gate;
if (iterator.Index() == bb.end) {
auto &bbNext = graph_[bb.id + 1];
auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
SetBlockPred(bbNext, state, depend, isLoopBack);
bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
}
} else if (bytecodeInfo.IsGeneral()) {
// handle general ecma.* bytecodes
NewJSGate(bb, state, depend);
@ -1039,17 +1078,7 @@ void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb, GateRef &state, Gat
} else if (bytecodeInfo.IsReturn()) {
// handle return.dyn and returnundefined bytecodes
NewReturn(bb, state, depend);
} else if (bytecodeInfo.IsMov()) {
// handle mov.dyn lda.dyn sta.dyn bytecodes
if (iterator.Index() == bb.end) {
auto &bbNext = graph_[bb.id + 1];
auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
SetBlockPred(bbNext, state, depend, isLoopBack);
bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
}
} else if (bytecodeInfo.IsDiscarded()) {
return;
} else {
} else if (!bytecodeInfo.IsDiscarded() && !bytecodeInfo.IsMov()) {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
@ -1057,12 +1086,13 @@ void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb, GateRef &state, Gat
void BytecodeCircuitBuilder::BuildSubCircuit()
{
for (auto &bb: graph_) {
if (bb.isDead) {
continue;
}
auto stateCur = bb.stateStart;
auto dependCur = bb.dependStart;
ChunkVector<size_t>& dfsList = loopAnalysis_.DfsList();
auto &entryBlock = graph_[0];
BuildBlockCircuitHead(entryBlock, entryBlock.stateCurrent, entryBlock.dependCurrent);
for (auto &bbId: dfsList) {
auto &bb = graph_[bbId];
auto stateCur = bb.stateCurrent;
auto dependCur = bb.dependCurrent;
ASSERT(stateCur != Circuit::NullGate());
ASSERT(dependCur != Circuit::NullGate());
if (!bb.trys.empty()) {
@ -1077,48 +1107,94 @@ void BytecodeCircuitBuilder::BuildSubCircuit()
}
return true;
});
const BytecodeInfo& bytecodeInfo = GetBytecodeInfo(bb.end);
if (bytecodeInfo.needFallThrough()) {
auto &bbNext = graph_[bb.id + 1];
SetBlockPred(bb, bbNext, stateCur, dependCur);
bbNext.expandedPreds.push_back({bb.id, bb.end, false});
}
}
}
GateRef BytecodeCircuitBuilder::NewLoopBackPhi(BytecodeRegion &bb, uint16_t reg, bool acc)
{
if (bb.numOfLoopBacks == 1) {
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
if (bb.loopbackBlocks.count(predId)) {
return ResolveDef(predId, predBcIdx, reg, acc);
}
}
UNREACHABLE();
LOG_COMPILER(FATAL) << "this branch is unreachable";
}
auto inList = std::vector<GateRef>(1 + bb.numOfLoopBacks, Circuit::NullGate());
auto loopBackValue = circuit_->NewGate(circuit_->ValueSelector(bb.numOfLoopBacks),
MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
gateAcc_.NewIn(loopBackValue, 0, bb.loopBackStateMerge);
size_t loopBackIndex = 1; // 1: start index of value inputs
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
if (bb.loopbackBlocks.count(predId)) {
gateAcc_.NewIn(loopBackValue, loopBackIndex++, ResolveDef(predId, predBcIdx, reg, acc));
}
}
return loopBackValue;
}
GateRef BytecodeCircuitBuilder::NewLoopForwardPhi(BytecodeRegion &bb, uint16_t reg, bool acc)
{
auto mergeCount = bb.numOfStatePreds - bb.numOfLoopBacks;
if (mergeCount == 1) {
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
if (!bb.loopbackBlocks.count(predId)) {
return ResolveDef(predId, predBcIdx, reg, acc);
}
}
UNREACHABLE();
LOG_COMPILER(FATAL) << "this branch is unreachable";
}
auto inList = std::vector<GateRef>(1 + mergeCount, Circuit::NullGate());
auto forwardValue = circuit_->NewGate(
circuit_->ValueSelector(mergeCount), MachineType::I64,
inList.size(), inList.data(), GateType::AnyType());
gateAcc_.NewIn(forwardValue, 0, bb.stateMerge);
size_t forwardIndex = 1; // 1: start index of value inputs
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
if (!bb.loopbackBlocks.count(predId)) {
gateAcc_.NewIn(forwardValue, forwardIndex++, ResolveDef(predId, predBcIdx, reg, acc));
}
}
return forwardValue;
}
void BytecodeCircuitBuilder::NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc, GateRef &currentPhi)
{
if (bb.numOfLoopBacks == 0) {
if (bb.numOfStatePreds == 1) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(0);
currentPhi = ResolveDef(predId, predBcIdx, reg, acc);
return;
}
ASSERT(bb.stateMerge != Circuit::NullGate());
auto inList = std::vector<GateRef>(1 + bb.numOfStatePreds, Circuit::NullGate());
currentPhi =
circuit_->NewGate(circuit_->ValueSelector(bb.numOfStatePreds), MachineType::I64,
inList.size(), inList.data(), GateType::AnyType());
gateAcc_.NewIn(currentPhi, 0, bb.stateStart);
gateAcc_.NewIn(currentPhi, 0, bb.stateMerge);
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
gateAcc_.NewIn(currentPhi, i + 1, ResolveDef(predId, predBcIdx, reg, acc));
}
} else {
ASSERT(gateAcc_.GetOpCode(bb.stateCurrent) == OpCode::LOOP_BEGIN);
// 2: the number of value inputs and it is in accord with LOOP_BEGIN
currentPhi = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I64,
{bb.stateStart, Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
auto inList = std::vector<GateRef>(1 + bb.numOfLoopBacks, Circuit::NullGate());
auto loopBackValue = circuit_->NewGate(circuit_->ValueSelector(bb.numOfLoopBacks),
MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
gateAcc_.NewIn(loopBackValue, 0, bb.mergeLoopBackEdges);
size_t loopBackIndex = 1; // 1: start index of value inputs
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
if (bb.loopbackBlocks.count(predId)) {
gateAcc_.NewIn(loopBackValue, loopBackIndex++, ResolveDef(predId, predBcIdx, reg, acc));
}
}
inList = std::vector<GateRef>(1 + bb.numOfStatePreds - bb.numOfLoopBacks, Circuit::NullGate());
auto forwardValue = circuit_->NewGate(
circuit_->ValueSelector(bb.numOfStatePreds - bb.numOfLoopBacks), MachineType::I64,
inList.size(), inList.data(), GateType::AnyType());
gateAcc_.NewIn(forwardValue, 0, bb.mergeForwardEdges);
size_t forwardIndex = 1; // 1: start index of value inputs
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
if (!bb.loopbackBlocks.count(predId)) {
gateAcc_.NewIn(forwardValue, forwardIndex++, ResolveDef(predId, predBcIdx, reg, acc));
}
}
{bb.stateCurrent, Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
auto loopBackValue = NewLoopBackPhi(bb, reg, acc);
auto forwardValue = NewLoopForwardPhi(bb, reg, acc);
gateAcc_.NewIn(currentPhi, 1, forwardValue); // 1: index of forward value input
gateAcc_.NewIn(currentPhi, 2, loopBackValue); // 2: index of loop-back value input
}
@ -1186,11 +1262,16 @@ GateRef BytecodeCircuitBuilder::ResolveDef(const size_t bbId, int32_t bcId, cons
// find GET_EXCEPTION gate if this is a catch block
if (ans == Circuit::NullGate() && tmpAcc) {
if (!bb.trys.empty()) {
std::vector<GateRef> outList;
gateAcc_.GetOuts(bb.dependStart, outList);
ASSERT(outList.size() == 1);
const auto &getExceptionGate = outList.at(0);
ASSERT(gateAcc_.GetOpCode(getExceptionGate) == OpCode::GET_EXCEPTION);
GateRef getExceptionGate = Circuit::NullGate();
auto uses = gateAcc_.Uses(bb.dependCurrent);
for (auto it = uses.begin(); it != uses.end(); it++) {
if (gateAcc_.IsDependIn(it)) {
getExceptionGate = *it;
ASSERT(gateAcc_.GetOpCode(getExceptionGate) == OpCode::GET_EXCEPTION);
break;
}
}
ASSERT(getExceptionGate != Circuit::NullGate());
ans = getExceptionGate;
}
}
@ -1232,7 +1313,6 @@ void BytecodeCircuitBuilder::BuildCircuit()
// create arg gates array
BuildCircuitArgs();
CollectPredsInfo();
BuildBlockCircuitHead();
// build states sub-circuit of each block
BuildSubCircuit();
// verification of soundness of CFG

View File

@ -27,8 +27,10 @@
#include "ecmascript/compiler/bytecode_info_collector.h"
#include "ecmascript/compiler/bytecodes.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/compiler_log.h"
#include "ecmascript/compiler/ecma_opcode_des.h"
#include "ecmascript/compiler/frame_states.h"
#include "ecmascript/compiler/loop_analysis.h"
#include "ecmascript/compiler/type_recorder.h"
#include "ecmascript/interpreter/interpreter-inl.h"
#include "ecmascript/jspandafile/js_pandafile.h"
@ -37,13 +39,6 @@
#include "ecmascript/pgo_profiler/pgo_profiler_loader.h"
namespace panda::ecmascript::kungfu {
enum class VisitState : uint8_t {
UNVISITED,
PENDING,
VISITED
};
struct ExceptionItem {
uint8_t* startPc;
uint8_t* endPc;
@ -175,6 +170,9 @@ struct BytecodeRegion {
std::set<size_t> loopbackBlocks {}; // List of loopback block ids
bool isDead {false};
bool phiAcc {false};
bool isLoopExit {false};
bool isLoopBody {false};
size_t loopHead {0};
std::set<uint16_t> phi {}; // phi node
size_t numOfStatePreds {0};
size_t numOfLoopBacks {0};
@ -182,12 +180,14 @@ struct BytecodeRegion {
size_t forwardIndex {0};
size_t loopBackIndex {0};
std::vector<std::tuple<size_t, size_t, bool>> expandedPreds {};
GateRef stateStart {Circuit::NullGate()};
GateRef dependStart {Circuit::NullGate()};
GateRef mergeForwardEdges {Circuit::NullGate()};
GateRef mergeLoopBackEdges {Circuit::NullGate()};
GateRef depForward {Circuit::NullGate()};
GateRef depLoopBack {Circuit::NullGate()};
GateRef loopExitState {Circuit::NullGate()};
GateRef loopExitDepend {Circuit::NullGate()};
GateRef stateCurrent {Circuit::NullGate()};
GateRef dependCurrent {Circuit::NullGate()};
GateRef stateMerge {Circuit::NullGate()};
GateRef dependMerge {Circuit::NullGate()};
GateRef loopBackStateMerge {Circuit::NullGate()};
GateRef loopBackDependMerge {Circuit::NullGate()};
std::unordered_map<uint16_t, GateRef> vregToValSelectorGate {}; // corresponding ValueSelector gates of vregs
GateRef valueSelectorAccGate {Circuit::NullGate()};
BytecodeIterator bytecodeIterator_ {};
@ -271,7 +271,9 @@ public:
typeRecorder_(jsPandaFile, method_, tsManager, recordName, loader), hasTypes_(hasTypes),
enableLog_(enableLog), enableTypeLowering_(enableTypeLowering),
pcOffsets_(methodPCInfo.pcOffsets),
frameStateBuilder_(this, circuit, methodLiteral), methodName_(name), recordName_(recordName),
frameStateBuilder_(this, circuit, methodLiteral),
loopAnalysis_(this, circuit->chunk()),
methodName_(name), recordName_(recordName),
bytecodes_(bytecodes)
{
}
@ -440,10 +442,14 @@ private:
void BuildCircuitArgs();
void CollectPredsInfo();
void NewMerge(GateRef &state, GateRef &depend, size_t numOfIns);
void NewLoopBegin(BytecodeRegion &bb);
void BuildBlockCircuitHead();
void NewLoopBegin(BytecodeRegion &bb, GateRef &state, GateRef &depend);
void NewLoopExit(BytecodeRegion &bb, GateRef &state, GateRef &depend);
void BuildBlockCircuitHead(BytecodeRegion &bb, GateRef &state, GateRef &depend);
std::vector<GateRef> CreateGateInList(const BytecodeInfo &info, const GateMetaData *meta);
void SetBlockPred(BytecodeRegion &bbNext, const GateRef &state, const GateRef &depend, bool isLoopBack);
void SetBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext, const GateRef &state, const GateRef &depend);
void SetLoopBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext,
GateRef &state, GateRef &depend);
void SetLoopExitBlockPred(BytecodeRegion &bb, GateRef &state, GateRef &depend);
GateRef NewConst(const BytecodeInfo &info);
void NewJSGate(BytecodeRegion &bb, GateRef &state, GateRef &depend);
void NewJump(BytecodeRegion &bb, GateRef &state, GateRef &depend);
@ -451,6 +457,8 @@ private:
void NewByteCode(BytecodeRegion &bb, GateRef &state, GateRef &depend);
void BuildSubCircuit();
void NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc, GateRef &currentPhi);
GateRef NewLoopBackPhi(BytecodeRegion &bb, uint16_t reg, bool acc);
GateRef NewLoopForwardPhi(BytecodeRegion &bb, uint16_t reg, bool acc);
GateRef ResolveDef(const size_t bbId, int32_t bcId, const uint16_t reg, const bool acc);
void BuildCircuit();
GateRef GetExistingRestore(GateRef resumeGate, uint16_t tmpReg) const;
@ -489,6 +497,7 @@ private:
std::vector<const uint8_t*> pcOffsets_;
std::map<std::pair<kungfu::GateRef, uint16_t>, kungfu::GateRef> resumeRegToRestore_ {};
FrameStateBuilder frameStateBuilder_;
LoopAnalysis loopAnalysis_;
std::string methodName_;
const CString &recordName_;
Bytecodes *bytecodes_;

View File

@ -196,6 +196,11 @@ public:
return OpcodeField::Get(value_);
}
bool IsInvalid() const
{
return value_ == 0;
}
private:
BytecodeMetaData() = default;
DEFAULT_NOEXCEPT_MOVE_SEMANTIC(BytecodeMetaData);
@ -567,6 +572,11 @@ public:
return metaData_.IsGeneral();
}
bool needFallThrough() const
{
return !IsJump() && !IsReturn() && !IsThrow();
}
bool IsGeneratorRelative() const
{
return metaData_.IsGeneratorRelative();

View File

@ -31,6 +31,12 @@
#include "securec.h"
namespace panda::ecmascript::kungfu {
enum class VisitState : uint8_t {
UNVISITED,
PENDING,
VISITED
};
class Circuit { // note: calling NewGate could make all saved Gate* invalid
public:
explicit Circuit(NativeAreaAllocator* allocator, bool isArch64 = true);

View File

@ -166,11 +166,18 @@ GateRef FrameStateBuilder::GetPhiComponent(BytecodeRegion *bb, BytecodeRegion *p
auto predId = std::get<0>(bb->expandedPreds.at(i));
if (bb->loopbackBlocks.count(predId)) {
if (predId == predBb->id) {
if (bb->numOfLoopBacks == 1) {
return loopBackValue;
}
return gateAcc_.GetValueIn(loopBackValue, backIndex);
}
backIndex++;
} else {
if (predId == predBb->id) {
auto mergeCount = bb->numOfStatePreds - bb->numOfLoopBacks;
if (mergeCount == 1) {
return forwardValue;
}
return gateAcc_.GetValueIn(forwardValue, forwardIndex);
}
forwardIndex++;

View File

@ -216,12 +216,14 @@ void Gate::CheckStateOutput() const
const Gate *curGate = this;
if (!curGate->IsFirstOutNull()) {
const Out *curOut = curGate->GetFirstOutConst();
if (curOut->IsStateEdge() && curOut->GetGateConst()->GetMetaData()->IsState()) {
auto meta = curOut->GetGateConst()->GetMetaData();
if (curOut->IsStateEdge() && meta->IsState() && !meta->IsVirtualState()) {
cnt++;
}
while (!curOut->IsNextOutNull()) {
curOut = curOut->GetNextOutConst();
if (curOut->IsStateEdge() && curOut->GetGateConst()->GetMetaData()->IsState()) {
meta = curOut->GetGateConst()->GetMetaData();
if (curOut->IsStateEdge() && meta->IsState() && !meta->IsVirtualState()) {
cnt++;
}
}

View File

@ -585,7 +585,7 @@ void GateAccessor::ReplaceHirWithIfBranch(GateRef hirGate, StateDepend success,
} else if (op == OpCode::IF_EXCEPTION) {
ifException = *it;
it = ReplaceHirIfException(it, exception);
} else if (op == OpCode::STATE_SPLIT) {
} else if (GetMetaData(*it)->IsVirtualState()) {
it = ReplaceIn(it, success.State());
} else {
ExceptionReturn(exception.State(), exception.Depend());

View File

@ -79,8 +79,15 @@ bool GateMetaData::IsProlog() const
bool GateMetaData::IsFixed() const
{
return (opcode_ == OpCode::VALUE_SELECTOR) || (opcode_ == OpCode::DEPEND_SELECTOR) ||
(opcode_ == OpCode::DEPEND_RELAY);
switch (opcode_) {
case OpCode::VALUE_SELECTOR:
case OpCode::DEPEND_SELECTOR:
case OpCode::DEPEND_RELAY:
case OpCode::LOOP_EXIT_DEPEND:
return true;
default:
return false;
}
}
bool GateMetaData::IsSchedulable() const
@ -107,6 +114,7 @@ bool GateMetaData::IsGeneralState() const
case OpCode::DEFAULT_CASE:
case OpCode::MERGE:
case OpCode::LOOP_BEGIN:
case OpCode::LOOP_EXIT:
case OpCode::ORDINARY_BLOCK:
case OpCode::STATE_ENTRY:
case OpCode::TYPED_BINARY_OP:
@ -140,6 +148,17 @@ bool GateMetaData::IsTerminalState() const
}
}
bool GateMetaData::IsVirtualState() const
{
switch (opcode_) {
case OpCode::GET_EXCEPTION:
case OpCode::STATE_SPLIT:
return true;
default:
return false;
}
}
bool GateMetaData::IsCFGMerge() const
{
return (opcode_ == OpCode::MERGE) || (opcode_ == OpCode::LOOP_BEGIN);

View File

@ -194,6 +194,8 @@ std::string MachineTypeToStr(MachineType machineType);
V(IfFalse, IF_FALSE, GateFlags::CONTROL, 1, 0, 0) \
V(LoopBegin, LOOP_BEGIN, GateFlags::CONTROL, 2, 0, 0) \
V(LoopBack, LOOP_BACK, GateFlags::CONTROL, 1, 0, 0) \
V(LoopExit, LOOP_EXIT, GateFlags::CONTROL_ROOT, 1, 0, 0) \
V(LoopExitDepend, LOOP_EXIT_DEPEND, GateFlags::FIXED, 1, 1, 0) \
V(DependRelay, DEPEND_RELAY, GateFlags::FIXED, 1, 1, 0) \
V(IfSuccess, IF_SUCCESS, GateFlags::CONTROL, 1, 0, 0) \
V(IfException, IF_EXCEPTION, GateFlags::CONTROL, 1, 1, 0) \
@ -311,6 +313,7 @@ enum GateFlags : uint8_t {
HAS_ROOT = 1 << 1,
HAS_FRAME_STATE = 1 << 2,
CONTROL = NO_WRITE,
CONTROL_ROOT = NO_WRITE | HAS_ROOT,
CHECKABLE = NO_WRITE | HAS_FRAME_STATE,
ROOT = NO_WRITE | HAS_ROOT,
FIXED = NO_WRITE,
@ -407,6 +410,7 @@ public:
bool IsState() const; // note: IsState(STATE_ENTRY) == false
bool IsGeneralState() const;
bool IsTerminalState() const;
bool IsVirtualState() const;
bool IsCFGMerge() const;
bool IsControlCase() const;
bool IsLoopHead() const;

View File

@ -51,6 +51,8 @@ void GraphEditor::RemoveGate()
switch (opcode) {
case OpCode::NOP:
case OpCode::DEAD:
case OpCode::VALUE_SELECTOR:
case OpCode::DEPEND_SELECTOR:
// dead op, just continue
break;
case OpCode::MERGE:
@ -78,7 +80,7 @@ void GraphEditor::PropagateGate(const Edge& edge)
return;
}
// IsDependIn
// IsValueIn
if (acc_.IsValueIn(gate, edge.GetIndex())) {
// value gate
ReplaceGate(gate);

View File

@ -213,7 +213,8 @@ void LLVMIRBuilder::InitializeHandlers()
OpCode::DEAD, OpCode::RETURN_LIST,
OpCode::ARG_LIST, OpCode::THROW,
OpCode::DEPEND_SELECTOR, OpCode::DEPEND_RELAY,
OpCode::FRAME_STATE, OpCode::STATE_SPLIT, OpCode::FRAME_ARGS
OpCode::FRAME_STATE, OpCode::STATE_SPLIT, OpCode::FRAME_ARGS,
OpCode::LOOP_EXIT_DEPEND, OpCode::LOOP_EXIT
};
}

View File

@ -0,0 +1,155 @@
/*
* Copyright (c) 2023 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 "ecmascript/compiler/bytecode_circuit_builder.h"
#include "ecmascript/compiler/loop_analysis.h"
namespace panda::ecmascript::kungfu {
void LoopAnalysis::Run()
{
CollectLoopBack();
if (loopCount_ == 1 && !builder_->HasTryCatch()) { // 1: sampe loop
for (auto &it : loopInfoVector_) {
CollectLoopBody(it);
CollectLoopExits(it);
}
}
}
void LoopAnalysis::CollectLoopExits(LoopInfo* loopInfo)
{
for (const auto &it : loopInfo->loopBody) {
auto &bb = builder_->GetBasicBlockById(it);
for (const auto &succBlock: bb.succs) {
size_t succId = succBlock->id;
if (!loopInfo->loopBody.count(succId)) {
auto &succBB = builder_->GetBasicBlockById(succId);
succBB.isLoopExit = true;
succBB.loopHead = loopInfo->loopHead;
loopInfo->loopExits.emplace_back(succId);
}
}
bb.isLoopBody = true;
bb.loopHead = loopInfo->loopHead;
}
if (builder_->IsLogEnabled()) {
LOG_COMPILER(INFO) << "loopHead: " << loopInfo->loopHead;
std::string log("LoopBody: ");
for (const auto &it : loopInfo->loopBody) {
log += std::to_string(it) + " , ";
}
LOG_COMPILER(INFO) << log;
std::string log1("LoopExits: ");
for (const auto &it : loopInfo->loopExits) {
log1 += std::to_string(it) + " , ";
}
LOG_COMPILER(INFO) << log1;
}
}
void LoopAnalysis::CollectLoopBody(LoopInfo* loopInfo)
{
auto size = builder_->GetBasicBlockCount();
// clear state
visitState_.insert(visitState_.begin(), size, VisitState::UNVISITED);
workList_.emplace_back(loopInfo->loopHead);
loopInfo->loopBody.insert(loopInfo->loopHead);
while (!workList_.empty()) {
size_t bbId = workList_.back();
auto &bb = builder_->GetBasicBlockById(bbId);
visitState_[bbId] = VisitState::PENDING;
bool allVisited = true;
for (const auto &succBlock: bb.succs) {
size_t succId = succBlock->id;
if (visitState_[succId] == VisitState::UNVISITED) {
// dfs
workList_.emplace_back(succId);
allVisited = false;
break;
// new path to loop body
} else if (loopInfo->loopBody.count(succId) && !loopInfo->loopBody.count(bbId)) {
ASSERT(visitState_[succId] != VisitState::UNVISITED);
for (const auto &it : workList_) {
loopInfo->loopBody.insert(it);
}
}
}
if (allVisited) {
workList_.pop_back();
visitState_[bbId] = VisitState::VISITED;
}
}
}
void LoopAnalysis::CountLoopBackEdge(size_t fromId, size_t toId)
{
auto &toBlock = builder_->GetBasicBlockById(toId);
if (toBlock.numOfLoopBacks == 0) {
loopCount_++;
auto loopInfo = chunk_->New<LoopInfo>(chunk_, toId);
loopInfoVector_.emplace_back(loopInfo);
}
toBlock.loopbackBlocks.insert(fromId);
toBlock.numOfLoopBacks++;
}
void LoopAnalysis::CollectLoopBack()
{
auto size = builder_->GetBasicBlockCount();
visitState_.resize(size, VisitState::UNVISITED);
size_t entryId = 0; // entry id
workList_.emplace_back(entryId);
dfsList_.emplace_back(entryId);
while (!workList_.empty()) {
size_t bbId = workList_.back();
auto &bb = builder_->GetBasicBlockById(bbId);
visitState_[bbId] = VisitState::PENDING;
bool allVisited = true;
for (const auto &succBlock: bb.succs) {
size_t succId = succBlock->id;
if (visitState_[succId] == VisitState::UNVISITED) {
// dfs
workList_.emplace_back(succId);
allVisited = false;
dfsList_.emplace_back(succId);
break;
} else if (visitState_[succId] == VisitState::PENDING) {
// back edge
CountLoopBackEdge(bbId, succId);
}
}
for (const auto &succBlock: bb.catchs) {
size_t succId = succBlock->id;
if (visitState_[succId] == VisitState::UNVISITED) {
// dfs
workList_.emplace_back(succId);
dfsList_.emplace_back(succId);
allVisited = false;
break;
} else if (visitState_[succId] == VisitState::PENDING) {
// back edge
CountLoopBackEdge(bbId, succId);
}
}
if (allVisited) {
workList_.pop_back();
visitState_[bbId] = VisitState::VISITED;
}
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 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_COMPILER_LOOP_ANALYSIS_H
#define ECMASCRIPT_COMPILER_LOOP_ANALYSIS_H
#include "ecmascript/mem/chunk_containers.h"
namespace panda::ecmascript::kungfu {
class BytecodeCircuitBuilder;
class LoopAnalysis {
public:
struct LoopInfo {
LoopInfo(Chunk* chunk, size_t headId)
: loopHead(headId), loopBody(chunk), loopExits(chunk) {}
size_t loopHead;
ChunkSet<size_t> loopBody;
ChunkVector<size_t> loopExits;
};
LoopAnalysis(BytecodeCircuitBuilder *builder, Chunk* chunk)
: builder_(builder), chunk_(chunk),
visitState_(chunk), workList_(chunk),
loopInfoVector_(chunk), dfsList_(chunk) {}
~LoopAnalysis() = default;
void Run();
ChunkVector<size_t>& DfsList()
{
return dfsList_;
}
private:
void CollectLoopBack();
void CollectLoopBody(LoopInfo* loopInfo);
void CollectLoopExits(LoopInfo* loopInfo);
void CountLoopBackEdge(size_t fromId, size_t toId);
BytecodeCircuitBuilder *builder_{nullptr};
Chunk* chunk_{nullptr};
ChunkVector<VisitState> visitState_;
ChunkVector<size_t> workList_;
ChunkVector<LoopInfo*> loopInfoVector_;
ChunkVector<size_t> dfsList_;
size_t loopCount_{0};
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_LOOP_ANALYSIS_H

View File

@ -44,30 +44,48 @@ void SlowPathLowering::CallRuntimeLowering()
for (const auto &gate : gateList) {
auto op = acc_.GetOpCode(gate);
if (op == OpCode::JS_BYTECODE) {
Lower(gate);
} else if (op == OpCode::GET_EXCEPTION) {
// initialize label manager
Environment env(gate, circuit_, &builder_);
LowerExceptionHandler(gate);
} else if (op == OpCode::GET_CONSTPOOL) {
// initialize label manager
Environment env(gate, circuit_, &builder_);
LowerGetConstPool(gate);
} else if (op == OpCode::CONST_DATA) {
LowerConstPoolData(gate);
} else if (op == OpCode::DEOPT_CHECK) {
LowerDeoptCheck(gate);
} else if (op == OpCode::CONSTRUCT) {
LowerConstruct(gate);
} else if (op == OpCode::TYPEDAOTCALL) {
LowerTypedAotCall(gate);
} else if (op == OpCode::UPDATE_HOTNESS) {
LowerUpdateHotness(gate);
} else if (op == OpCode::STATE_SPLIT) {
DeleteStateSplit(gate);
} else if (op == OpCode::GET_ENV) {
LowerGetEnv(gate);
switch (op) {
case OpCode::JS_BYTECODE:
Lower(gate);
break;
case OpCode::GET_EXCEPTION: {
// initialize label manager
Environment env(gate, circuit_, &builder_);
LowerExceptionHandler(gate);
break;
}
case OpCode::GET_CONSTPOOL: {
// initialize label manager
Environment env(gate, circuit_, &builder_);
LowerGetConstPool(gate);
break;
}
case OpCode::CONST_DATA:
LowerConstPoolData(gate);
break;
case OpCode::DEOPT_CHECK:
LowerDeoptCheck(gate);
break;
case OpCode::CONSTRUCT:
LowerConstruct(gate);
break;
case OpCode::TYPEDAOTCALL:
LowerTypedAotCall(gate);
break;
case OpCode::UPDATE_HOTNESS:
LowerUpdateHotness(gate);
break;
case OpCode::STATE_SPLIT:
DeleteStateSplit(gate);
break;
case OpCode::GET_ENV:
LowerGetEnv(gate);
break;
case OpCode::LOOP_EXIT:
DeleteLoopExit(gate);
break;
default:
break;
}
}
@ -88,6 +106,12 @@ void SlowPathLowering::DeleteStateSplit(GateRef gate)
acc_.ReplaceGate(gate, Circuit::NullGate(), depend, Circuit::NullGate());
}
void SlowPathLowering::DeleteLoopExit(GateRef gate)
{
auto state = acc_.GetState(gate);
acc_.ReplaceGate(gate, state, Circuit::NullGate(), Circuit::NullGate());
}
void SlowPathLowering::LowerToJSCall(GateRef hirGate, const std::vector<GateRef> &args)
{
GateRef stateInGate = builder_.GetState();

View File

@ -298,6 +298,7 @@ private:
void LowerNotifyConcurrentResult(GateRef gate);
void DeleteStateSplit(GateRef gate);
void LowerGetEnv(GateRef gate);
void DeleteLoopExit(GateRef gate);
TSManager *tsManager_ {nullptr};
const MethodLiteral *methodLiteral_ {nullptr};

View File

@ -44,7 +44,7 @@ void TypeLowering::RunTypeLowering()
void TypeLowering::LowerType(GateRef gate)
{
GateRef glue = acc_.GetGlueFromArgList();
auto op = OpCode(acc_.GetOpCode(gate));
auto op = acc_.GetOpCode(gate);
switch (op) {
case OpCode::PRIMITIVE_TYPE_CHECK:
LowerPrimitiveTypeCheck(gate);

View File

@ -12,3 +12,10 @@
# limitations under the License.
90300.25
10
-1
-10
-110
-10
0
10

View File

@ -22,4 +22,117 @@ function foo(n: number) {
return x;
}
print(foo(300));
print(foo(300));
function forLoop(n: number): number {
let sum = 0;
for (let i = 0; i < n; i++) {
sum++;
}
return sum;
}
function forLoopWithBreak(n: number): number {
let sum = 0;
for (let i = 0; i < n; i++) {
if (sum >= 5) {
sum++;
} else {
sum--;
break;
}
}
return sum;
}
function forLoopWithContinue(n: number): number {
let sum = 0;
for (let i = 0; i < n; i++) {
if (sum >= 5) {
sum++;
} else {
sum--;
continue;
}
}
return sum;
}
function forNestedLoop0(n: number): number {
let sum = 0;
a: for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (sum >= 5) {
sum++;
break a;
}
sum--;
}
sum--;
}
return sum;
}
function forNestedLoop1(n: number): number {
let sum = 0;
a: for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (sum >= 5) {
sum++;
continue a;
}
}
sum--;
}
return sum;
}
function forNestedLoop2(n: number): number {
let sum = 0;
a:
for (let i = 0; i < n; i++) {
if (i % 2 == 0) {
for (let j = 0; j < n; j++) {
if (sum >= 5) {
sum++;
continue a;
}
}
return sum;
}
sum--;
}
return sum;
}
function forNestedLoop3(n: number): number {
let sum = 0;
let j = 0;
for (let i = 0; i < n; i++) {
if (i % 2 == 0) {
while (j < n) {
j++;
sum++;
}
return sum;
}
sum--;
}
return sum;
}
let n = 10;
let ret1 = forLoop(n);
print(ret1);
let ret2 = forLoopWithBreak(n);
print(ret2);
let ret3 = forLoopWithContinue(n);
print(ret3);
let ret4 = forNestedLoop0(n);
print(ret4);
let ret5 = forNestedLoop1(n);
print(ret5);
let ret6 = forNestedLoop2(n);
print(ret6);
let ret7 = forNestedLoop3(n);
print(ret7);