!2567 guard eliminating pass

Merge pull request !2567 from ChunyangWang/guard_eliminating_pass
This commit is contained in:
Gargoyle.h 2022-10-10 06:04:48 +00:00 committed by Gitee
commit ff92bd132a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
15 changed files with 246 additions and 40 deletions

View File

@ -63,6 +63,7 @@ source_set("libark_jsoptimizer_set") {
"frame_states.cpp",
"gate.cpp",
"gate_accessor.cpp",
"guard_eliminating.cpp",
"ic_stub_builder.cpp",
"interpreter_stub.cpp",
"llvm_codegen.cpp",

View File

@ -550,13 +550,13 @@ GateRef CircuitBuilder::BothAreString(GateRef x, GateRef y)
}
template<TypedBinOp Op>
GateRef CircuitBuilder::TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType)
GateRef CircuitBuilder::TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType, GateType gateType)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto numberBinaryOp = TypedBinaryOperator(MachineType::I64, Op, xType, yType,
{currentControl, currentDepend, x, y});
{currentControl, currentDepend, x, y}, gateType);
currentLabel->SetControl(numberBinaryOp);
currentLabel->SetDepend(numberBinaryOp);
return numberBinaryOp;
@ -571,7 +571,7 @@ GateRef CircuitBuilder::NumberBinaryOp(GateRef x, GateRef y)
auto currentDepend = currentLabel->GetDepend();
auto numberBinaryOp = TypedBinaryOperator(MachineType::I64, Op,
GateType::NumberType(), GateType::NumberType(),
{currentControl, currentDepend, x, y});
{currentControl, currentDepend, x, y}, GateType::AnyType());
currentLabel->SetControl(numberBinaryOp);
currentLabel->SetDepend(numberBinaryOp);
return numberBinaryOp;

View File

@ -154,7 +154,7 @@ GateRef CircuitBuilder::TypeCheck(GateType type, GateRef gate)
}
GateRef CircuitBuilder::TypedBinaryOperator(MachineType type, TypedBinOp binOp, GateType typeLeft, GateType typeRight,
std::vector<GateRef> inList)
std::vector<GateRef> inList, GateType gateType)
{
// get BinaryOpCode from a constant gate
auto bin = Int8(static_cast<int8_t>(binOp));
@ -162,7 +162,7 @@ GateRef CircuitBuilder::TypedBinaryOperator(MachineType type, TypedBinOp binOp,
// merge two expected types of valueIns
uint64_t operandTypes = (static_cast<uint64_t>(typeLeft.Value()) << OPRAND_TYPE_BITS) |
static_cast<uint64_t>(typeRight.Value());
return GetCircuit()->NewGate(OpCode(OpCode::TYPED_BINARY_OP), type, operandTypes, inList, GateType::AnyType());
return GetCircuit()->NewGate(OpCode(OpCode::TYPED_BINARY_OP), type, operandTypes, inList, gateType);
}
GateRef CircuitBuilder::TypeConvert(MachineType type, GateType typeFrom, GateType typeTo,

View File

@ -204,7 +204,7 @@ public:
// low level interface
GateRef TypeCheck(GateType type, GateRef gate);
GateRef TypedBinaryOperator(MachineType type, TypedBinOp binOp, GateType typeLeft, GateType typeRight,
std::vector<GateRef> inList);
std::vector<GateRef> inList, GateType gateType);
GateRef TypeConvert(MachineType type, GateType typeFrom, GateType typeTo, const std::vector<GateRef>& inList);
GateRef TypedUnaryOperator(MachineType type, TypedUnaryOp unaryOp, GateType typleVal,
const std::vector<GateRef>& inList);
@ -376,7 +376,7 @@ public:
// middle ir: operations with any type
template<TypedBinOp Op>
inline GateRef TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType);
inline GateRef TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType, GateType gateType);
// middle ir: Number operations
template<TypedBinOp Op>

View File

@ -1459,4 +1459,9 @@ bool OpCode::IsConstant() const
{
return (op_ == OpCode::CONSTANT);
}
bool OpCode::IsTypedOperator() const
{
return (op_ == OpCode::TYPED_BINARY_OP) || (op_ == OpCode::TYPE_CONVERT) || (op_ == OpCode::TYPED_UNARY_OP);
}
} // namespace panda::ecmascript::kungfu

View File

@ -241,6 +241,7 @@ public:
[[nodiscard]] bool IsLoopHead() const;
[[nodiscard]] bool IsNop() const;
[[nodiscard]] bool IsConstant() const;
[[nodiscard]] bool IsTypedOperator() const;
~OpCode() = default;
private:

View File

@ -221,6 +221,11 @@ bool GateAccessor::IsConstant(GateRef gate) const
return GetOpCode(gate).IsConstant();
}
bool GateAccessor::IsTypedOperator(GateRef gate) const
{
return GetOpCode(gate).IsTypedOperator();
}
bool GateAccessor::IsSchedulable(GateRef gate) const
{
return GetOpCode(gate).IsSchedulable();
@ -434,4 +439,16 @@ bool GateAccessor::IsValueIn(GateRef gate, size_t index) const
size_t valueEndIndex = valueStartIndex + GetInValueCount(gate);
return (index >= valueStartIndex && index < valueEndIndex);
}
void GateAccessor::DeleteGuardAndFrameState(GateRef gate)
{
GateRef guard = GetDep(gate);
if (GetOpCode(guard) == OpCode::GUARD) {
GateRef dep = GetDep(guard);
ReplaceDependIn(gate, dep);
GateRef frameState = GetValueIn(guard, 1);
DeleteGate(frameState);
DeleteGate(guard);
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -347,6 +347,7 @@ public:
bool IsLoopBack(GateRef gate) const;
bool IsState(GateRef gate) const;
bool IsConstant(GateRef gate) const;
bool IsTypedOperator(GateRef gate) const;
bool IsSchedulable(GateRef gate) const;
MarkCode GetMark(GateRef gate) const;
void SetMark(GateRef gate, MarkCode mark);
@ -361,6 +362,7 @@ public:
bool IsExceptionState(const UseIterator &useIt) const;
bool IsDependIn(GateRef gate, size_t index) const;
bool IsValueIn(GateRef gate, size_t index) const;
void DeleteGuardAndFrameState(GateRef gate);
private:
ConstUseIterator ConstUseBegin(GateRef gate) const

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2022 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 <stack>
#include "ecmascript/compiler/circuit_optimizer.h"
#include "ecmascript/compiler/guard_eliminating.h"
#include "ecmascript/compiler/scheduler.h"
namespace panda::ecmascript::kungfu {
bool GuardEliminating::HasGuard(GateRef gate) const
{
if (acc_.IsTypedOperator(gate)) {
auto guard = acc_.GetDep(gate);
auto op = acc_.GetOpCode(guard);
return op == OpCode::GUARD;
}
return false;
}
void GuardEliminating::Run()
{
// eliminate duplicate typecheck
GlobalValueNumbering(circuit_).Run();
// calculate dominator tree
std::vector<GateRef> bbGatesList;
std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
std::vector<size_t> immDom;
std::tie(bbGatesList, bbGatesAddrToIdx, immDom) = Scheduler::CalculateDominatorTree(circuit_);
std::vector<std::vector<size_t>> domTree(immDom.size(), std::vector<size_t>(0));
for (size_t idx = 1; idx < immDom.size(); ++idx) {
domTree[immDom[idx]].emplace_back(idx);
}
// dfs the dominator tree to eliminate guard
// which is domined by another guard with same condition
std::set<GateRef> conditionSet;
struct DFSState {
size_t curbb;
size_t idx;
};
std::stack<DFSState> dfsStack;
auto startGate = Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY));
DFSState startState = { bbGatesAddrToIdx[startGate], 0 };
dfsStack.push(startState);
while (!dfsStack.empty()) {
auto &curState = dfsStack.top();
auto &curbb = curState.curbb;
auto &idx = curState.idx;
if (idx == domTree[curbb].size()) {
auto curGate = bbGatesList[curbb];
if (HasGuard(curGate)) {
auto guard = acc_.GetDep(curGate);
auto condition = acc_.GetValueIn(guard, 0);
conditionSet.erase(condition);
}
dfsStack.pop();
continue;
}
auto succbb = domTree[curbb][idx];
auto succGate = bbGatesList[succbb];
if (HasGuard(succGate)) {
auto guard = acc_.GetDep(succGate);
auto condition = acc_.GetValueIn(guard, 0);
if (conditionSet.count(condition) > 0) {
acc_.DeleteGuardAndFrameState(succGate);
} else {
conditionSet.insert(condition);
}
}
DFSState newState = { succbb, 0 };
dfsStack.push(newState);
idx++;
}
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
<< "===================="
<< " After guard eliminating "
<< "[" << GetMethodName() << "]"
<< "===================="
<< "\033[0m";
circuit_->PrintAllGates(*bcBuilder_);
LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2022 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_GUARD_ELIMINATING_H
#define ECMASCRIPT_COMPILER_GUARD_ELIMINATING_H
#include "ecmascript/compiler/gate_accessor.h"
namespace panda::ecmascript::kungfu {
class GuardEliminating {
public:
GuardEliminating(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit, bool enableLog, const std::string& name)
: bcBuilder_(bcBuilder), circuit_(circuit), acc_(circuit), enableLog_(enableLog), methodName_(name) {}
~GuardEliminating() = default;
void Run();
private:
bool IsLogEnabled() const
{
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
bool HasGuard(GateRef gate) const;
BytecodeCircuitBuilder *bcBuilder_ {nullptr};
Circuit *circuit_ {nullptr};
GateAccessor acc_;
bool enableLog_ {false};
std::string methodName_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_GUARD_ELIMINATING_H

View File

@ -19,6 +19,7 @@
#include "ecmascript/compiler/async_function_lowering.h"
#include "ecmascript/compiler/bytecode_circuit_builder.h"
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/guard_eliminating.h"
#include "ecmascript/compiler/llvm_codegen.h"
#include "ecmascript/compiler/scheduler.h"
#include "ecmascript/compiler/slowpath_lowering.h"
@ -156,6 +157,16 @@ public:
}
};
class GuardEliminatingPass {
public:
bool Run(PassData* data, BytecodeCircuitBuilder *builder)
{
bool enableLog = data->GetEnableMethodLog() && data->GetLog()->OutputCIR();
GuardEliminating(builder, data->GetCircuit(), enableLog, data->GetMethodName()).Run();
return true;
}
};
class SchedulingPass {
public:
bool Run(PassData* data)

View File

@ -77,6 +77,7 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat
pipeline.RunPass<AsyncFunctionLoweringPass>(&builder, &cmpCfg);
if (EnableTypeLowering()) {
pipeline.RunPass<TSTypeLoweringPass>(&builder, &cmpCfg, tsManager);
pipeline.RunPass<GuardEliminatingPass>(&builder);
pipeline.RunPass<TypeLoweringPass>(&builder, &cmpCfg, tsManager);
}
pipeline.RunPass<SlowPathLoweringPass>(&builder, &cmpCfg, tsManager);

View File

@ -67,7 +67,7 @@ HWTEST_F_L0(LoweringRelateGateTests, TypedBinaryOperatorAddFramework)
auto arg1 = builder.Arguments(1);
auto nadd = builder.TypedBinaryOperator(MachineType::I64, TypedBinOp::TYPED_ADD,
GateType::NumberType(), GateType::NumberType(),
{entry, depend, arg0, arg1});
{entry, depend, arg0, arg1}, GateType::NumberType());
builder.Return(nadd, nadd, nadd);
EXPECT_TRUE(Verifier::Run(&circuit));
CompilationConfig config("x86_64-unknown-linux-gnu", false);
@ -87,7 +87,7 @@ HWTEST_F_L0(LoweringRelateGateTests, TypedBinaryOperatorLessFramework)
auto arg1 = builder.Arguments(1);
auto nless = builder.TypedBinaryOperator(MachineType::I64, TypedBinOp::TYPED_LESS,
GateType::NumberType(), GateType::NumberType(),
{entry, depend, arg0, arg1});
{entry, depend, arg0, arg1}, GateType::BooleanType());
builder.Return(nless, nless, nless);
EXPECT_TRUE(Verifier::Run(&circuit));
CompilationConfig config("x86_64-unknown-linux-gnu", false);

View File

@ -41,6 +41,29 @@ void TSTypeLowering::RunTSTypeLowering()
}
}
bool TSTypeLowering::IsTrustedType(GateRef gate) const
{
if (acc_.IsConstant(gate) || acc_.IsTypedOperator(gate)){
return true;
}
auto op = acc_.GetOpCode(gate);
if (op == OpCode::JS_BYTECODE) {
auto pc = bcBuilder_->GetJSBytecode(gate);
EcmaOpcode bc = bcBuilder_->PcToOpcode(pc);
switch (bc) {
case EcmaOpcode::ADD2_IMM8_V8:
case EcmaOpcode::SUB2_IMM8_V8:
case EcmaOpcode::MUL2_IMM8_V8:
case EcmaOpcode::INC_IMM8:
case EcmaOpcode::LESSEQ_IMM8_V8:
return true;
default:
break;
}
}
return false;
}
void TSTypeLowering::Lower(GateRef gate)
{
auto pc = bcBuilder_->GetJSBytecode(gate);
@ -129,18 +152,6 @@ void TSTypeLowering::DeleteGates(std::vector<GateRef> &unusedGate)
}
}
void TSTypeLowering::DeleteGuardAndFrameState(GateRef gate)
{
GateRef guard = acc_.GetDep(gate);
if (acc_.GetOpCode(guard) == OpCode::GUARD) {
GateRef dep = acc_.GetDep(guard);
acc_.ReplaceDependIn(gate, dep);
GateRef frameState = acc_.GetValueIn(guard, 1);
acc_.DeleteGate(frameState);
acc_.DeleteGate(guard);
}
}
void TSTypeLowering::ReplaceHIRGate(GateRef hir, GateRef outir, GateRef state, GateRef depend,
std::vector<GateRef> &unusedGate)
{
@ -187,7 +198,7 @@ void TSTypeLowering::LowerTypedAdd(GateRef gate)
SpeculateNumberCalculate<TypedBinOp::TYPED_ADD>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -201,7 +212,7 @@ void TSTypeLowering::LowerTypedSub(GateRef gate)
SpeculateNumberCalculate<TypedBinOp::TYPED_SUB>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -215,7 +226,7 @@ void TSTypeLowering::LowerTypedMul(GateRef gate)
SpeculateNumberCalculate<TypedBinOp::TYPED_MUL>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -229,7 +240,7 @@ void TSTypeLowering::LowerTypedMod(GateRef gate)
SpeculateNumberCalculate<TypedBinOp::TYPED_MOD>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -243,7 +254,7 @@ void TSTypeLowering::LowerTypedLess(GateRef gate)
SpeculateNumberCompare<TypedBinOp::TYPED_LESS>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -257,7 +268,7 @@ void TSTypeLowering::LowerTypedLessEq(GateRef gate)
SpeculateNumberCompare<TypedBinOp::TYPED_LESSEQ>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -271,7 +282,7 @@ void TSTypeLowering::LowerTypedGreater(GateRef gate)
SpeculateNumberCompare<TypedBinOp::TYPED_GREATER>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -285,7 +296,7 @@ void TSTypeLowering::LowerTypedGreaterEq(GateRef gate)
SpeculateNumberCompare<TypedBinOp::TYPED_GREATEREQ>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -299,7 +310,7 @@ void TSTypeLowering::LowerTypedDiv(GateRef gate)
SpeculateNumberCalculate<TypedBinOp::TYPED_DIV>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -313,7 +324,7 @@ void TSTypeLowering::LowerTypedEq(GateRef gate)
SpeculateNumberCompare<TypedBinOp::TYPED_EQ>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -327,7 +338,7 @@ void TSTypeLowering::LowerTypedNotEq(GateRef gate)
SpeculateNumberCompare<TypedBinOp::TYPED_NOTEQ>(gate);
return;
} else {
DeleteGuardAndFrameState(gate);
acc_.DeleteGuardAndFrameState(gate);
}
}
@ -338,24 +349,28 @@ void TSTypeLowering::SpeculateNumberCalculate(GateRef gate)
GateRef right = acc_.GetValueIn(gate, 1);
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
GateType gateType = acc_.GetGateType(gate);
GateRef check = Circuit::NullGate();
if (acc_.IsConstant(left) && acc_.IsConstant(right)) {
check = builder_.Boolean(true);
} else if (acc_.IsConstant(left)) {
if (IsTrustedType(left) && IsTrustedType(right)) {
acc_.DeleteGuardAndFrameState(gate);
} else if (IsTrustedType(left)) {
check = builder_.TypeCheck(rightType, right);
} else if (acc_.IsConstant(right)) {
} else if (IsTrustedType(right)) {
check = builder_.TypeCheck(leftType, left);
} else {
check = builder_.BoolAnd(builder_.TypeCheck(leftType, left), builder_.TypeCheck(rightType, right));
}
check = builder_.False();
// guard maybe not a GUARD
GateRef guard = acc_.GetDep(gate);
ASSERT(acc_.GetOpCode(guard) == OpCode::GUARD);
acc_.ReplaceIn(guard, 1, check);
if (check != Circuit::NullGate()) {
acc_.ReplaceIn(guard, 1, check);
}
// Replace the old NumberBinaryOp<Op> with TypedBinaryOp<Op>
GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType);
GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType);
acc_.SetDep(result, guard);
std::vector<GateRef> removedGate{gate};
ReplaceHIRGate(gate, result, builder_.GetState(), builder_.GetDepend(), removedGate);

View File

@ -46,7 +46,6 @@ private:
void Lower(GateRef gate);
void DeleteGates(std::vector<GateRef> &unusedGate);
void DeleteGuardAndFrameState(GateRef gate);
void ReplaceHIRGate(GateRef hir, GateRef outir, GateRef state, GateRef depend,
std::vector<GateRef> &unuseGate);
void LowerTypedAdd(GateRef gate);
@ -63,6 +62,9 @@ private:
void LowerTypeToNumeric(GateRef gate);
void LowerPrimitiveTypeToNumber(GateRef gate);
// TypeTrusted means the type of gate is already typecheck-passed, or the gate is constant and no need to check.
bool IsTrustedType(GateRef gate) const;
template<TypedBinOp Op>
void SpeculateNumberCalculate(GateRef gate);
template<TypedBinOp Op>