mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
Add loop exit for loop peeling
Issue: I6QTH5 Signed-off-by: sunzhe23 <sunzhe23@huawei.com>
This commit is contained in:
parent
13caea9137
commit
f717c511ce
@ -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",
|
||||
|
@ -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 ¤tPhi)
|
||||
{
|
||||
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
|
||||
|
@ -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 ¤tPhi);
|
||||
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_;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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++;
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
155
ecmascript/compiler/loop_analysis.cpp
Normal file
155
ecmascript/compiler/loop_analysis.cpp
Normal 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
|
62
ecmascript/compiler/loop_analysis.h
Normal file
62
ecmascript/compiler/loop_analysis.h
Normal 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
|
@ -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();
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
|
@ -12,3 +12,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
90300.25
|
||||
10
|
||||
-1
|
||||
-10
|
||||
-110
|
||||
-10
|
||||
0
|
||||
10
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user