Description: Number Speculative Pass

Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I6NSQS
Signed-off-by: K0u1hw <wangchunyang15@huawei.com>

Change-Id: I7b372a0cd2d28fda49fb85466cac731cae31f95a
This commit is contained in:
K0u1hw 2023-03-16 19:32:31 +08:00
parent 26bdac03bf
commit 50973eef7d
27 changed files with 1468 additions and 25 deletions

View File

@ -99,6 +99,9 @@ ohos_source_set("libark_jsoptimizer_set") {
"llvm_codegen.cpp",
"llvm_ir_builder.cpp",
"new_object_stub_builder.cpp",
"number_speculative_lowering.cpp",
"number_speculative_retype.cpp",
"number_speculative_runner.cpp",
"operations_stub_builder.cpp",
"pass_manager.cpp",
"rt_call_signature.cpp",

View File

@ -116,6 +116,12 @@ GateRef CircuitBuilder::GetDoubleOfTDouble(GateRef x)
return CastInt64ToFloat64(val);
}
GateRef CircuitBuilder::GetBooleanOfTBoolean(GateRef x)
{
GateRef tagged = ChangeTaggedPointerToInt64(x);
return TruncInt64ToInt1(tagged);
}
GateRef CircuitBuilder::GetDoubleOfTNumber(GateRef x)
{
Label subentry(env_);

View File

@ -49,7 +49,6 @@ GateRef CircuitBuilder::Selector(OpCode opcode, MachineType machineType, GateRef
return circuit_->NewGate(meta, machineType, inList.size(), inList.data(), type.GetGateType());
}
GateRef CircuitBuilder::Selector(OpCode opcode, GateRef control,
const std::vector<GateRef> &values, int valueCounts, VariableType type)
{
@ -203,6 +202,126 @@ GateRef CircuitBuilder::IndexCheck(GateType type, GateRef gate, GateRef index)
return ret;
}
MachineType CircuitBuilder::GetMachineTypeOfValueType(ValueType type)
{
switch (type) {
case ValueType::BOOL:
return MachineType::I1;
case ValueType::INT32:
return MachineType::I32;
case ValueType::FLOAT64:
return MachineType::F64;
case ValueType::TAGGED_BOOLEAN:
case ValueType::TAGGED_INT:
case ValueType::TAGGED_DOUBLE:
case ValueType::TAGGED_NUMBER:
return MachineType::I64;
default:
return MachineType::NOVALUE;
}
}
GateType CircuitBuilder::GetGateTypeOfValueType(ValueType type)
{
switch (type) {
case ValueType::BOOL:
case ValueType::INT32:
case ValueType::FLOAT64:
return GateType::NJSValue();
case ValueType::TAGGED_BOOLEAN:
return GateType::BooleanType();
case ValueType::TAGGED_INT:
return GateType::IntType();
case ValueType::TAGGED_DOUBLE:
return GateType::DoubleType();
case ValueType::TAGGED_NUMBER:
return GateType::NumberType();
default:
return GateType::Empty();
}
}
GateRef CircuitBuilder::CheckAndConvert(GateRef gate, ValueType src, ValueType dst)
{
MachineType machineType = GetMachineTypeOfValueType(dst);
GateType gateType = GetGateTypeOfValueType(dst);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
ASSERT(acc_.HasFrameState(currentDepend));
auto frameState = acc_.GetFrameState(currentDepend);
uint64_t value = ValuePairTypeAccessor::ToValue(src, dst);
GateRef ret = GetCircuit()->NewGate(circuit_->CheckAndConvert(value),
machineType, {currentControl, currentDepend, gate, frameState}, gateType);
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::Convert(GateRef gate, ValueType src, ValueType dst)
{
MachineType machineType = GetMachineTypeOfValueType(dst);
GateType gateType = GetGateTypeOfValueType(dst);
uint64_t value = ValuePairTypeAccessor::ToValue(src, dst);
GateRef ret = GetCircuit()->NewGate(circuit_->Convert(value), machineType, {gate}, gateType);
return ret;
}
GateRef CircuitBuilder::ConvertInt32ToFloat64(GateRef gate)
{
return Convert(gate, ValueType::INT32, ValueType::FLOAT64);
}
GateRef CircuitBuilder::ConvertFloat64ToInt32(GateRef gate)
{
return Convert(gate, ValueType::FLOAT64, ValueType::INT32);
}
GateRef CircuitBuilder::ConvertBoolToTaggedBoolean(GateRef gate)
{
return Convert(gate, ValueType::BOOL, ValueType::TAGGED_BOOLEAN);
}
GateRef CircuitBuilder::ConvertInt32ToTaggedInt(GateRef gate)
{
return Convert(gate, ValueType::INT32, ValueType::TAGGED_INT);
}
GateRef CircuitBuilder::ConvertFloat64ToTaggedDouble(GateRef gate)
{
return Convert(gate, ValueType::FLOAT64, ValueType::TAGGED_DOUBLE);
}
GateRef CircuitBuilder::CheckTaggedIntAndConvertToInt32(GateRef gate)
{
return CheckAndConvert(gate, ValueType::TAGGED_INT, ValueType::INT32);
}
GateRef CircuitBuilder::CheckTaggedDoubleAndConvertToInt32(GateRef gate)
{
return CheckAndConvert(gate, ValueType::TAGGED_DOUBLE, ValueType::INT32);
}
GateRef CircuitBuilder::CheckTaggedNumberAndConvertToInt32(GateRef gate)
{
return CheckAndConvert(gate, ValueType::TAGGED_NUMBER, ValueType::INT32);
}
GateRef CircuitBuilder::CheckTaggedIntAndConvertToFloat64(GateRef gate)
{
return CheckAndConvert(gate, ValueType::TAGGED_INT, ValueType::FLOAT64);
}
GateRef CircuitBuilder::CheckTaggedDoubleAndConvertToFloat64(GateRef gate)
{
return CheckAndConvert(gate, ValueType::TAGGED_DOUBLE, ValueType::FLOAT64);
}
GateRef CircuitBuilder::CheckTaggedNumberAndConvertToFloat64(GateRef gate)
{
return CheckAndConvert(gate, ValueType::TAGGED_NUMBER, ValueType::FLOAT64);
}
GateRef CircuitBuilder::TryPrimitiveTypeCheck(GateType type, GateRef gate)
{
if (acc_.GetOpCode(gate) == OpCode::CONSTANT) {

View File

@ -106,6 +106,7 @@ class Variable;
V(TruncInt32ToInt1, Trunc, MachineType::I1) \
V(TruncInt32ToInt16, Trunc, MachineType::I16) \
V(TruncFloatToInt64, TruncFloatToInt64, MachineType::I64) \
V(TruncFloatToInt32, TruncFloatToInt32, MachineType::I32) \
V(ExtFloat32ToDouble, Fext, MachineType::F64) \
V(TruncDoubleToFloat32, Ftrunc, MachineType::F32) \
V(ChangeTaggedPointerToInt64, TaggedToInt64, MachineType::I64) \
@ -242,6 +243,21 @@ public:
GateRef TypedCallOperator(GateRef hirGate, MachineType type, const std::initializer_list<GateRef>& args);
inline GateRef TypedCallBuiltin(GateRef hirGate, GateRef x, BuiltinsStubCSigns::ID id);
GateRef TypeConvert(MachineType type, GateType typeFrom, GateType typeTo, const std::vector<GateRef>& inList);
MachineType GetMachineTypeOfValueType(ValueType type);
GateType GetGateTypeOfValueType(ValueType type);
GateRef Convert(GateRef gate, ValueType src, ValueType dst);
GateRef ConvertBoolToTaggedBoolean(GateRef gate);
GateRef ConvertInt32ToTaggedInt(GateRef gate);
GateRef ConvertFloat64ToTaggedDouble(GateRef gate);
GateRef ConvertFloat64ToInt32(GateRef gate);
GateRef ConvertInt32ToFloat64(GateRef gate);
GateRef CheckAndConvert(GateRef gate, ValueType src, ValueType dst);
GateRef CheckTaggedIntAndConvertToInt32(GateRef gate);
GateRef CheckTaggedDoubleAndConvertToInt32(GateRef gate);
GateRef CheckTaggedNumberAndConvertToInt32(GateRef gate);
GateRef CheckTaggedIntAndConvertToFloat64(GateRef gate);
GateRef CheckTaggedDoubleAndConvertToFloat64(GateRef gate);
GateRef CheckTaggedNumberAndConvertToFloat64(GateRef gate);
GateRef TypedUnaryOperator(MachineType type, TypedUnOp unaryOp, GateType typeVal,
const std::vector<GateRef>& inList, GateType gateType);
GateRef TypedNewAllocateThis(GateRef ctor, GateRef hclassIndex, GateRef frameState);
@ -347,6 +363,7 @@ public:
inline GateRef GetInt32OfTInt(GateRef x);
inline GateRef TaggedCastToIntPtr(GateRef x);
inline GateRef GetDoubleOfTDouble(GateRef x);
inline GateRef GetBooleanOfTBoolean(GateRef x);
inline GateRef GetDoubleOfTNumber(GateRef x);
inline GateRef Int32ToTaggedPtr(GateRef x);
inline GateRef Int64ToTaggedPtr(GateRef x);

View File

@ -362,14 +362,11 @@ void EarlyElimination::Run()
VisitDependEntry(entry);
VisitGraph();
for (auto gate : stateSplits_) {
ReplaceGate(gate, circuit_->DeadGate());
}
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
<< "===================="
<< " After check eliminating "
<< " After early eliminating "
<< "[" << GetMethodName() << "]"
<< "===================="
<< "\033[0m";
@ -703,10 +700,8 @@ GateRef EarlyElimination::TryEliminateStateSplitAndFrameState(GateRef gate)
auto curFrameState = acc_.GetFrameState(gate);
if (frameState != Circuit::NullGate()) {
acc_.UpdateAllUses(curFrameState, frameState);
acc_.DeleteGate(curFrameState);
return circuit_->DeadGate();
return Circuit::NullGate();
}
stateSplits_.insert(gate);
dependInfo = dependInfo->UpdateFrameState(curFrameState);
return UpdateDependInfo(gate, dependInfo);
}

View File

@ -341,7 +341,7 @@ class EarlyElimination : public GraphVisitor {
public:
EarlyElimination(Circuit *circuit, bool enableLog, const std::string& name, Chunk* chunk)
: GraphVisitor(circuit, chunk), enableLog_(enableLog),
methodName_(name), dependInfos_(chunk), stateSplits_(chunk) {}
methodName_(name), dependInfos_(chunk) {}
~EarlyElimination() = default;
@ -391,7 +391,6 @@ private:
bool enableLog_ {false};
std::string methodName_;
ChunkVector<DependChainInfo*> dependInfos_;
ChunkSet<GateRef> stateSplits_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_EARLY_ELIMINATION_H

View File

@ -17,6 +17,7 @@
#include "ecmascript/compiler/circuit_builder.h"
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/compiler/graph_editor.h"
#include "ecmascript/js_tagged_value.h"
namespace panda::ecmascript::kungfu {
using UseIterator = GateAccessor::UseIterator;
@ -135,6 +136,24 @@ GateType GateAccessor::GetParamGateType(GateRef gate) const
return accessor.GetGateType();
}
ValueType GateAccessor::GetSrcType(GateRef gate) const
{
ASSERT(GetOpCode(gate) == OpCode::CONVERT ||
GetOpCode(gate) == OpCode::CHECK_AND_CONVERT);
Gate *gatePtr = circuit_->LoadGatePtr(gate);
ValuePairTypeAccessor accessor(gatePtr->GetOneParameterMetaData()->GetValue());
return accessor.GetSrcType();
}
ValueType GateAccessor::GetDstType(GateRef gate) const
{
ASSERT(GetOpCode(gate) == OpCode::CONVERT ||
GetOpCode(gate) == OpCode::CHECK_AND_CONVERT);
Gate *gatePtr = circuit_->LoadGatePtr(gate);
ValuePairTypeAccessor accessor(gatePtr->GetOneParameterMetaData()->GetValue());
return accessor.GetDstType();
}
GateType GateAccessor::GetLeftType(GateRef gate) const
{
ASSERT(GetOpCode(gate) == OpCode::TYPED_UNARY_OP ||
@ -383,6 +402,11 @@ bool GateAccessor::IsConstantValue(GateRef gate, uint64_t value) const
return false;
}
bool GateAccessor::IsConstantUndefined(GateRef gate) const
{
return IsConstantValue(gate, JSTaggedValue::VALUE_UNDEFINED);
}
bool GateAccessor::IsTypedOperator(GateRef gate) const
{
return GetMetaData(gate)->IsTypedOperator();
@ -457,8 +481,12 @@ void GateAccessor::SetGateType(GateRef gate, GateType gt)
UseIterator GateAccessor::ReplaceHirIfSuccess(const UseIterator &useIt, GateRef state)
{
ASSERT(GetOpCode(*useIt) == OpCode::IF_SUCCESS);
auto firstUse = Uses(*useIt).begin();
ReplaceIn(*firstUse, firstUse.GetIndex(), state);
auto uses = Uses(*useIt);
for (auto it = uses.begin(); it != uses.end();) {
if (IsStateIn(it)) {
it = ReplaceIn(it, state);
}
}
auto next = DeleteGate(useIt);
return next;
}
@ -501,6 +529,8 @@ 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) {
it = ReplaceIn(it, success.State());
} else {
ExceptionReturn(exception.State(), exception.Depend());
it = ReplaceIn(it, success.State());
@ -632,6 +662,9 @@ size_t GateAccessor::GetInValueCount(GateRef gate) const
void GateAccessor::UpdateAllUses(GateRef oldIn, GateRef newIn)
{
if (oldIn == newIn) {
return;
}
auto uses = Uses(oldIn);
for (auto useIt = uses.begin(); useIt != uses.end();) {
useIt = ReplaceIn(useIt, newIn);
@ -690,6 +723,35 @@ GateRef GateAccessor::GetConstantGate(MachineType bitValue, BitField bitfield, G
return circuit_->GetConstantGate(bitValue, bitfield, type);
}
bool GateAccessor::IsConstantNumber(GateRef gate) const
{
DISALLOW_GARBAGE_COLLECTION;
if (GetGateType(gate).IsNJSValueType() ||
(GetOpCode(gate) != OpCode::CONSTANT)) {
return false;
}
JSTaggedValue value(GetConstantValue(gate));
return value.IsNumber();
}
double GateAccessor::GetFloat64FromConstant(GateRef gate) const
{
DISALLOW_GARBAGE_COLLECTION;
ASSERT(GetOpCode(gate) == OpCode::CONSTANT);
ASSERT(!GetGateType(gate).IsNJSValueType());
JSTaggedValue value(GetConstantValue(gate));
return value.GetDouble();
}
int GateAccessor::GetInt32FromConstant(GateRef gate) const
{
DISALLOW_GARBAGE_COLLECTION;
ASSERT(GetOpCode(gate) == OpCode::CONSTANT);
ASSERT(!GetGateType(gate).IsNJSValueType());
JSTaggedValue value(GetConstantValue(gate));
return value.GetInt();
}
bool GateAccessor::IsStateIn(const UseIterator &useIt) const
{
size_t stateStartIndex = 0;
@ -773,10 +835,13 @@ void GateAccessor::ReplaceGate(GateRef gate, GateRef state, GateRef depend, Gate
auto uses = Uses(gate);
for (auto useIt = uses.begin(); useIt != uses.end();) {
if (IsStateIn(useIt)) {
ASSERT(state != Circuit::NullGate());
useIt = ReplaceIn(useIt, state);
} else if (IsDependIn(useIt)) {
ASSERT(depend != Circuit::NullGate());
useIt = ReplaceIn(useIt, depend);
} else if (IsValueIn(useIt)) {
ASSERT(value != Circuit::NullGate());
useIt = ReplaceIn(useIt, value);
} else {
LOG_ECMA(FATAL) << "this branch is unreachable";

View File

@ -17,6 +17,7 @@
#define ECMASCRIPT_COMPILER_GATE_ACCESSOR_H
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/gate_meta_data.h"
namespace panda::ecmascript::kungfu {
@ -395,6 +396,8 @@ public:
UseIterator ReplaceIn(const UseIterator &useIt, GateRef replaceGate);
// Add for lowering
GateType GetGateType(GateRef gate) const;
ValueType GetSrcType(GateRef gate) const;
ValueType GetDstType(GateRef gate) const;
void SetGateType(GateRef gate, GateType gt);
void DeleteIn(GateRef gate, size_t idx);
UseIterator DeleteGate(const UseIterator &useIt);
@ -414,6 +417,8 @@ public:
MachineType GetMachineType(GateRef gate) const;
void SetMachineType(GateRef gate, MachineType type);
GateRef GetConstantGate(MachineType bitValue, BitField bitfield, GateType type) const;
double GetFloat64FromConstant(GateRef gate) const;
int GetInt32FromConstant(GateRef gate) const;
bool IsInGateNull(GateRef gate, size_t idx) const;
bool IsSelector(GateRef g) const;
bool IsControlCase(GateRef gate) const;
@ -423,6 +428,8 @@ public:
bool IsConstant(GateRef gate) const;
bool IsDependSelector(GateRef gate) const;
bool IsConstantValue(GateRef gate, uint64_t value) const;
bool IsConstantUndefined(GateRef gate) const;
bool IsConstantNumber(GateRef gate) const;
bool IsTypedOperator(GateRef gate) const;
bool IsNotWrite(GateRef gate) const;
bool IsDead(GateRef gate) const;
@ -560,6 +567,7 @@ private:
friend class ArgumentAccessor;
friend class BytecodeCircuitBuilder;
friend class TSInlineLowering;
friend class GraphVisitor;
};
class ConstGateAccessor {

View File

@ -162,6 +162,7 @@ std::string MachineTypeToStr(MachineType machineType);
V(Ftrunc, FTRUNC, GateFlags::NONE_FLAG, 0, 0, 1) \
V(Rev, REV, GateFlags::NONE_FLAG, 0, 0, 1) \
V(TruncFloatToInt64, TRUNC_FLOAT_TO_INT64, GateFlags::NONE_FLAG, 0, 0, 1) \
V(TruncFloatToInt32, TRUNC_FLOAT_TO_INT32, GateFlags::NONE_FLAG, 0, 0, 1) \
V(TaggedToInt64, TAGGED_TO_INT64, GateFlags::NONE_FLAG, 0, 0, 1) \
V(Int64ToTagged, INT64_TO_TAGGED, GateFlags::NONE_FLAG, 0, 0, 1) \
V(SignedIntToFloat, SIGNED_INT_TO_FLOAT, GateFlags::NONE_FLAG, 0, 0, 1) \
@ -246,7 +247,9 @@ std::string MachineTypeToStr(MachineType machineType);
V(IndexCheck, INDEX_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(Int32OverflowCheck, INT32_OVERFLOW_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(TypedUnaryOp, TYPED_UNARY_OP, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedConvert, TYPE_CONVERT, GateFlags::NO_WRITE, 1, 1, 1)
V(TypedConvert, TYPE_CONVERT, GateFlags::NO_WRITE, 1, 1, 1) \
V(CheckAndConvert, CHECK_AND_CONVERT, GateFlags::CHECKABLE, 1, 1, 1) \
V(Convert, CONVERT, GateFlags::NONE_FLAG, 0, 0, 1) \
#define GATE_META_DATA_LIST_WITH_VALUE(V) \
V(Icmp, ICMP, GateFlags::NONE_FLAG, 0, 0, 2) \
@ -589,6 +592,37 @@ private:
GateType type_;
};
class ValuePairTypeAccessor {
public:
// type bits shift
static constexpr int OPRAND_TYPE_BITS = 8;
explicit ValuePairTypeAccessor(uint64_t value) : bitField_(value) {}
ValueType GetSrcType() const
{
return static_cast<ValueType>(LeftBits::Get(bitField_));
}
ValueType GetDstType() const
{
return static_cast<ValueType>(RightBits::Get(bitField_));
}
static uint16_t ToValue(ValueType srcType, ValueType dstType)
{
uint8_t srcVlaue = static_cast<uint8_t>(srcType);
uint8_t dstVlaue = static_cast<uint8_t>(dstType);
return LeftBits::Encode(srcVlaue) | RightBits::Encode(dstVlaue);
}
private:
using LeftBits = panda::BitField<uint8_t, 0, OPRAND_TYPE_BITS>;
using RightBits = LeftBits::NextField<uint8_t, OPRAND_TYPE_BITS>;
uint64_t bitField_;
};
class GatePairTypeAccessor {
public:
// type bits shift

View File

@ -76,6 +76,14 @@ void GraphVisitor::VisitGraph()
}
}
void GraphVisitor::ReVisitGate(GateRef gate)
{
if (acc_.GetMark(gate) == MarkCode::FINISHED) {
PushEffectGate(gate);
}
}
// Reverse post-order
void GraphVisitor::VisitTopGate(Edge& current)
{

View File

@ -31,6 +31,7 @@ public:
virtual ~GraphVisitor() = default;
void VisitGraph();
void ReVisitGate(GateRef gate);
virtual GateRef VisitGate(GateRef gate) = 0;
protected:

View File

@ -184,6 +184,7 @@ void LLVMIRBuilder::InitializeHandlers()
{OpCode::FMOD, &LLVMIRBuilder::HandleMod},
{OpCode::DEOPT, &LLVMIRBuilder::HandleDeopt},
{OpCode::TRUNC_FLOAT_TO_INT64, &LLVMIRBuilder::HandleTruncFloatToInt},
{OpCode::TRUNC_FLOAT_TO_INT32, &LLVMIRBuilder::HandleTruncFloatToInt},
};
illegalOpHandlers_ = {
OpCode::NOP, OpCode::CIRCUIT_ROOT, OpCode::DEPEND_ENTRY,

View File

@ -0,0 +1,86 @@
/*
* 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_NUMBER_GATE_INFO_H
#define ECMASCRIPT_NUMBER_GATE_INFO_H
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/js_hclass.h"
namespace panda::ecmascript::kungfu {
enum class TypeInfo {
NONE,
INT1,
INT32,
FLOAT64,
TAGGED,
};
class UseInfo {
public:
UseInfo(uint8_t tag) : tag_(tag) {}
static constexpr uint8_t UNUSED = 0;
static constexpr uint8_t BOOL = 1 << 0;
static constexpr uint8_t INT32 = 1 << 1;
static constexpr uint8_t FLOAT64 = 1 << 2;
static constexpr uint8_t NATIVE = BOOL | INT32 | FLOAT64;
static constexpr uint8_t TAGGED = 1 << 3;
bool AddUse(const UseInfo &UseInfo)
{
uint8_t oldTag = tag_;
tag_ |= UseInfo.tag_;
return oldTag != tag_;
}
bool UsedAsBool() const
{
return ((tag_ & BOOL) == BOOL);
}
bool UsedAsFloat64() const
{
return ((tag_ & FLOAT64) == FLOAT64);
}
bool UsedAsNative() const
{
return ((tag_ & NATIVE) != 0);
}
bool UsedAsTagged() const
{
return ((tag_ & TAGGED) != 0);
}
static UseInfo UnUsed()
{
return UseInfo(UNUSED);
}
static UseInfo BoolUse()
{
return UseInfo(BOOL);
}
static UseInfo Int32Use()
{
return UseInfo(INT32);
}
static UseInfo Float64Use()
{
return UseInfo(FLOAT64);
}
static UseInfo TaggedUse()
{
return UseInfo(TAGGED);
}
private:
uint8_t tag_ {0};
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_NUMBER_GATE_INFO_H

View File

@ -0,0 +1,293 @@
/*
* 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 "ecmascript/compiler/gate_meta_data.h"
#include "ecmascript/compiler/number_gate_info.h"
#include "ecmascript/compiler/type.h"
#include "ecmascript/compiler/type_lowering.h"
#include "ecmascript/compiler/builtins_lowering.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/compiler/number_speculative_lowering.h"
#include "ecmascript/deoptimizer/deoptimizer.h"
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/js_locale.h"
#include "ecmascript/js_native_pointer.h"
namespace panda::ecmascript::kungfu {
void NumberSpeculativeLowering::Run()
{
std::vector<GateRef> gateList;
acc_.GetAllGates(gateList);
for (auto gate : gateList) {
VisitGate(gate);
}
}
void NumberSpeculativeLowering::VisitGate(GateRef gate)
{
OpCode op = acc_.GetOpCode(gate);
switch (op) {
case OpCode::TYPED_BINARY_OP: {
ASSERT(acc_.GetLeftType(gate).IsNumberType() && acc_.GetRightType(gate).IsNumberType());
VisitNumberBinaryOp(gate);
break;
}
case OpCode::VALUE_SELECTOR: {
VisitPhi(gate);
break;
}
case OpCode::CONSTANT: {
VisitConstant(gate);
break;
}
default:
break;
}
}
void NumberSpeculativeLowering::VisitNumberBinaryOp(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
switch (Op) {
case TypedBinOp::TYPED_ADD: {
VisitNumberCalculate<TypedBinOp::TYPED_ADD>(gate);
break;
}
case TypedBinOp::TYPED_SUB: {
VisitNumberCalculate<TypedBinOp::TYPED_SUB>(gate);
break;
}
case TypedBinOp::TYPED_MUL: {
VisitNumberCalculate<TypedBinOp::TYPED_MUL>(gate);
break;
}
case TypedBinOp::TYPED_LESS: {
VisitNumberCompare<TypedBinOp::TYPED_LESS>(gate);
break;
}
case TypedBinOp::TYPED_LESSEQ: {
VisitNumberCompare<TypedBinOp::TYPED_LESSEQ>(gate);
break;
}
case TypedBinOp::TYPED_GREATER: {
VisitNumberCompare<TypedBinOp::TYPED_GREATER>(gate);
break;
}
case TypedBinOp::TYPED_GREATEREQ: {
VisitNumberCompare<TypedBinOp::TYPED_GREATEREQ>(gate);
break;
}
case TypedBinOp::TYPED_EQ: {
VisitNumberCompare<TypedBinOp::TYPED_EQ>(gate);
break;
}
case TypedBinOp::TYPED_NOTEQ: {
VisitNumberCompare<TypedBinOp::TYPED_NOTEQ>(gate);
break;
}
default:
break;
}
}
template<TypedBinOp Op>
void NumberSpeculativeLowering::VisitNumberCalculate(GateRef gate)
{
GateRef left = acc_.GetValueIn(gate, 0);
GateRef right = acc_.GetValueIn(gate, 1);
GateType gateType = acc_.GetGateType(gate);
GateRef result = Circuit::NullGate();
if (gateType.IsIntType()) {
result = CalculateInts<Op>(left, right); // int op int
acc_.SetMachineType(gate, MachineType::I32);
} else {
result = CalculateDoubles<Op>(left, right); // float op float
acc_.SetMachineType(gate, MachineType::F64);
}
acc_.SetGateType(gate, GateType::NJSValue());
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
template<TypedBinOp Op>
void NumberSpeculativeLowering::VisitNumberCompare(GateRef gate)
{
GateRef left = acc_.GetValueIn(gate, 0);
GateRef right = acc_.GetValueIn(gate, 1);
GateType leftType = acc_.GetLeftType(gate);
GateType rightType = acc_.GetRightType(gate);
GateRef result = Circuit::NullGate();
if (leftType.IsIntType() && rightType.IsIntType()) {
result = CompareInts<Op>(left, right); // int op int
} else {
result = CompareDoubles<Op>(left, right); // float op float
}
acc_.SetMachineType(gate, MachineType::I1);
acc_.SetGateType(gate, GateType::NJSValue());
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void NumberSpeculativeLowering::VisitConstant(GateRef gate)
{
TypeInfo output = typeInfos_[acc_.GetId(gate)];
switch (output) {
case TypeInfo::INT32: {
int value = acc_.GetInt32FromConstant(gate);
acc_.UpdateAllUses(gate, builder_.Int32(value));
break;
}
case TypeInfo::FLOAT64: {
double value = acc_.GetFloat64FromConstant(gate);
acc_.UpdateAllUses(gate, builder_.Double(value));
break;
}
default:
break;
}
}
void NumberSpeculativeLowering::VisitPhi(GateRef gate)
{
TypeInfo output = typeInfos_[acc_.GetId(gate)];
switch (output) {
case TypeInfo::INT1: {
acc_.SetGateType(gate, GateType::NJSValue());
acc_.SetMachineType(gate, MachineType::I1);
break;
}
case TypeInfo::INT32: {
acc_.SetGateType(gate, GateType::NJSValue());
acc_.SetMachineType(gate, MachineType::I32);
break;
}
case TypeInfo::FLOAT64: {
acc_.SetGateType(gate, GateType::NJSValue());
acc_.SetMachineType(gate, MachineType::F64);
break;
}
default:
break;
}
}
template<TypedBinOp Op>
GateRef NumberSpeculativeLowering::CalculateInts(GateRef left, GateRef right)
{
GateRef res = Circuit::NullGate();
left = builder_.SExtInt32ToInt64(left);
right = builder_.SExtInt32ToInt64(right);
switch (Op) {
case TypedBinOp::TYPED_ADD:
res = builder_.Int64Add(left, right);
break;
case TypedBinOp::TYPED_SUB:
res = builder_.Int64Sub(left, right);
break;
case TypedBinOp::TYPED_MUL:
res = builder_.Int64Mul(left, right);
break;
default:
break;
}
// DeoptCheckForOverFlow
GateRef max = builder_.Int64(INT32_MAX);
GateRef min = builder_.Int64(INT32_MIN);
GateRef notOverflow = builder_.Int64LessThanOrEqual(res, max);
GateRef notUnderflow = builder_.Int64GreaterThanOrEqual(res, min);
GateRef condition = builder_.BoolAnd(notOverflow, notUnderflow);
builder_.DeoptCheck(condition, acc_.GetFrameState(builder_.GetDepend()), DeoptType::NOTINT);
GateRef result = builder_.TruncInt64ToInt32(res);
return result;
}
template<TypedBinOp Op>
GateRef NumberSpeculativeLowering::CalculateDoubles(GateRef left, GateRef right)
{
GateRef res = Circuit::NullGate();
switch (Op) {
case TypedBinOp::TYPED_ADD:
res = builder_.DoubleAdd(left, right);
break;
case TypedBinOp::TYPED_SUB:
res = builder_.DoubleSub(left, right);
break;
case TypedBinOp::TYPED_MUL:
res = builder_.DoubleMul(left, right);
break;
default:
break;
}
return res;
}
template<TypedBinOp Op>
GateRef NumberSpeculativeLowering::CompareInts(GateRef left, GateRef right)
{
GateRef condition = Circuit::NullGate();
switch (Op) {
case TypedBinOp::TYPED_LESS:
condition = builder_.Int32LessThan(left, right);
break;
case TypedBinOp::TYPED_LESSEQ:
condition = builder_.Int32LessThanOrEqual(left, right);
break;
case TypedBinOp::TYPED_GREATER:
condition = builder_.Int32GreaterThan(left, right);
break;
case TypedBinOp::TYPED_GREATEREQ:
condition = builder_.Int32GreaterThanOrEqual(left, right);
break;
case TypedBinOp::TYPED_EQ:
condition = builder_.Int32Equal(left, right);
break;
case TypedBinOp::TYPED_NOTEQ:
condition = builder_.Int32NotEqual(left, right);
break;
default:
break;
}
return condition;
}
template<TypedBinOp Op>
GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right)
{
GateRef condition = Circuit::NullGate();
switch (Op) {
case TypedBinOp::TYPED_LESS:
condition = builder_.DoubleLessThan(left, right);
break;
case TypedBinOp::TYPED_LESSEQ:
condition = builder_.DoubleLessThanOrEqual(left, right);
break;
case TypedBinOp::TYPED_GREATER:
condition = builder_.DoubleGreaterThan(left, right);
break;
case TypedBinOp::TYPED_GREATEREQ:
condition = builder_.DoubleGreaterThanOrEqual(left, right);
break;
case TypedBinOp::TYPED_EQ:
condition = builder_.DoubleEqual(left, right);
break;
case TypedBinOp::TYPED_NOTEQ:
condition = builder_.DoubleNotEqual(left, right);
break;
default:
break;
}
return condition;
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,60 @@
/*
* 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_NUMBER_SPECULATIVE_LOWERING_H
#define ECMASCRIPT_COMPILER_NUMBER_SPECULATIVE_LOWERING_H
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/compiler/gate_meta_data.h"
#include "ecmascript/compiler/number_gate_info.h"
#include "ecmascript/compiler/type.h"
#include "ecmascript/mem/chunk_containers.h"
namespace panda::ecmascript::kungfu {
class NumberSpeculativeLowering {
public:
NumberSpeculativeLowering(Circuit *circuit, ChunkVector<TypeInfo>& typeInfos)
: circuit_(circuit), acc_(circuit), builder_(circuit), typeInfos_(typeInfos) {}
void Run();
private:
void VisitGate(GateRef gate);
void VisitNumberBinaryOp(GateRef gate);
void VisitConstant(GateRef gate);
void VisitPhi(GateRef gate);
template<TypedBinOp Op>
void VisitNumberCalculate(GateRef gate);
template<TypedBinOp Op>
void VisitNumberCompare(GateRef gate);
template<TypedBinOp Op>
GateRef CalculateInts(GateRef left, GateRef right);
template<TypedBinOp Op>
GateRef CalculateDoubles(GateRef left, GateRef right);
template<TypedBinOp Op>
GateRef CompareInts(GateRef left, GateRef right);
template<TypedBinOp Op>
GateRef CompareDoubles(GateRef left, GateRef right);
Circuit* circuit_;
GateAccessor acc_;
CircuitBuilder builder_;
// ChunkVector<UseInfo>& useInfos_;
ChunkVector<TypeInfo>& typeInfos_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_NUMBER_SPECULATIVE_LOWERING_H

View File

@ -0,0 +1,323 @@
/*
* 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/number_speculative_retype.h"
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/compiler/gate_meta_data.h"
#include "ecmascript/compiler/number_gate_info.h"
#include "ecmascript/compiler/type.h"
namespace panda::ecmascript::kungfu {
GateRef NumberSpeculativeRetype::SetOutputType(GateRef gate, GateType pgoType)
{
TypeInfo& type = typeInfos_[acc_.GetId(gate)];
TypeInfo old = type;
if (pgoType.IsIntType()) {
type = TypeInfo::INT32;
} else if (pgoType.IsDoubleType()) {
type = TypeInfo::FLOAT64;
} else if (pgoType.IsBooleanType()) {
type = TypeInfo::INT1;
} else {
type = TypeInfo::TAGGED;
}
return old == type ? Circuit::NullGate() : gate;
}
GateRef NumberSpeculativeRetype::VisitGate(GateRef gate)
{
OpCode op = acc_.GetOpCode(gate);
switch (op) {
case OpCode::TYPED_BINARY_OP:
ASSERT(acc_.GetLeftType(gate).IsNumberType() && acc_.GetRightType(gate).IsNumberType());
return VisitNumberBinaryOp(gate);
case OpCode::TYPED_UNARY_OP:
case OpCode::INDEX_CHECK:
case OpCode::LOAD_ELEMENT:
case OpCode::STORE_ELEMENT:
return VisitNumberRelated(gate);
case OpCode::VALUE_SELECTOR:
return VisitPhi(gate);
case OpCode::CONSTANT:
return VisitConstant(gate);
default:
return VisitOthers(gate);
}
}
GateRef NumberSpeculativeRetype::VisitConstant(GateRef gate)
{
if (IsRetype()) {
GateType gateType = acc_.GetGateType(gate);
if (acc_.IsConstantNumber(gate)) {
return SetOutputType(gate, gateType);
} else {
return SetOutputType(gate, GateType::AnyType());
}
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitPhi(GateRef gate)
{
size_t valueNum = acc_.GetNumValueIn(gate);
if (IsRetype()) {
TypeInfo tempType = TypeInfo::NONE;
for (size_t i = 0; i < valueNum; ++i) {
GateRef input = acc_.GetValueIn(gate, i);
TypeInfo inputInfo = typeInfos_[acc_.GetId(input)];
if (tempType == TypeInfo::NONE) {
tempType = inputInfo;
} else if ((tempType != inputInfo) && (inputInfo != TypeInfo::NONE)) {
tempType = TypeInfo::TAGGED;
break;
}
}
TypeInfo& typeInfo = typeInfos_[acc_.GetId(gate)];
if (typeInfo != tempType) {
typeInfo = tempType;
return gate;
}
}
if (IsConvert()) {
TypeInfo output = typeInfos_[acc_.GetId(gate)];
if (output == TypeInfo::TAGGED) {
return VisitOthers(gate);
}
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitNumberBinaryOp(GateRef gate)
{
TypedBinOp op = acc_.GetTypedBinaryOp(gate);
switch (op) {
case TypedBinOp::TYPED_ADD:
case TypedBinOp::TYPED_SUB:
case TypedBinOp::TYPED_MUL: {
return VisitNumberCalculate(gate);
}
case TypedBinOp::TYPED_LESS:
case TypedBinOp::TYPED_LESSEQ:
case TypedBinOp::TYPED_GREATER:
case TypedBinOp::TYPED_GREATEREQ:
case TypedBinOp::TYPED_EQ:
case TypedBinOp::TYPED_NOTEQ: {
return VisitNumberCompare(gate);
}
default:
return VisitNumberRelated(gate);
}
}
GateRef NumberSpeculativeRetype::VisitNumberCalculate(GateRef gate)
{
GateType gateType = acc_.GetGateType(gate);
if (IsRetype()) {
GateType resType = gateType.IsIntType() ? GateType::IntType() : GateType::DoubleType();
return SetOutputType(gate, resType);
} else if (IsConvert()) {
Environment env(gate, circuit_, &builder_);
if (gateType.IsIntType()) {
ConvertForIntOperator(gate);
} else {
ConvertForDoubleOperator(gate);
}
acc_.ReplaceStateIn(gate, builder_.GetState());
acc_.ReplaceDependIn(gate, builder_.GetDepend());
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitNumberCompare(GateRef gate)
{
if (IsRetype()) {
return SetOutputType(gate, GateType::BooleanType());
}
if (IsConvert()) {
Environment env(gate, circuit_, &builder_);
GateType leftType = acc_.GetLeftType(gate);
GateType rightType = acc_.GetRightType(gate);
if (leftType.IsIntType() && rightType.IsIntType()) {
ConvertForIntOperator(gate);
} else {
ConvertForDoubleOperator(gate);
}
acc_.ReplaceStateIn(gate, builder_.GetState());
acc_.ReplaceDependIn(gate, builder_.GetDepend());
}
return Circuit::NullGate();
}
void NumberSpeculativeRetype::ConvertForIntOperator(GateRef gate)
{
GateRef left = acc_.GetValueIn(gate, 0);
GateRef right = acc_.GetValueIn(gate, 1);
GateType leftType = acc_.GetLeftType(gate);
GateType rightType = acc_.GetRightType(gate);
acc_.ReplaceValueIn(gate, CheckAndConvertToInt32(left, leftType), 0);
acc_.ReplaceValueIn(gate, CheckAndConvertToInt32(right, rightType), 1);
}
void NumberSpeculativeRetype::ConvertForDoubleOperator(GateRef gate)
{
GateRef left = acc_.GetValueIn(gate, 0);
GateRef right = acc_.GetValueIn(gate, 1);
GateType leftType = acc_.GetLeftType(gate);
GateType rightType = acc_.GetRightType(gate);
acc_.ReplaceValueIn(gate, CheckAndConvertToFloat64(left, leftType), 0);
acc_.ReplaceValueIn(gate, CheckAndConvertToFloat64(right, rightType), 1);
}
GateRef NumberSpeculativeRetype::VisitNumberRelated(GateRef gate)
{
if (IsRetype()) {
return SetOutputType(gate, GateType::NumberType());
}
if (IsConvert()) {
Environment env(gate, circuit_, &builder_);
size_t valueNum = acc_.GetNumValueIn(gate);
for (size_t i = 0; i < valueNum; ++i) {
GateRef input = acc_.GetValueIn(gate, i);
GateType inputType = acc_.GetGateType(input);
if (inputType.IsNumberType() || inputType.IsBooleanType()) {
acc_.ReplaceValueIn(gate, CheckAndConvertToTagged(input, inputType), i);
}
}
acc_.ReplaceStateIn(gate, builder_.GetState());
acc_.ReplaceDependIn(gate, builder_.GetDepend());
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitOthers(GateRef gate)
{
if (IsRetype()) {
return SetOutputType(gate, GateType::AnyType());
}
if (IsConvert()) {
size_t valueNum = acc_.GetNumValueIn(gate);
for (size_t i = 0; i < valueNum; ++i) {
GateRef input = acc_.GetValueIn(gate, i);
acc_.ReplaceValueIn(gate, ConvertToTagged(input), i);
}
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::CheckAndConvertToInt32(GateRef gate, GateType gateType)
{
TypeInfo output = typeInfos_[acc_.GetId(gate)];
switch (output) {
case TypeInfo::INT32:
return gate;
case TypeInfo::FLOAT64:
return builder_.ConvertFloat64ToInt32(gate);
case TypeInfo::TAGGED: {
ASSERT(gateType.IsNumberType());
if (gateType.IsIntType()) {
return builder_.CheckTaggedIntAndConvertToInt32(gate);
} else if (gateType.IsDoubleType()) {
return builder_.CheckTaggedDoubleAndConvertToInt32(gate);
} else {
return builder_.CheckTaggedNumberAndConvertToInt32(gate);
}
}
default: {
UNREACHABLE();
return Circuit::NullGate();
}
}
}
GateRef NumberSpeculativeRetype::CheckAndConvertToFloat64(GateRef gate, GateType gateType)
{
TypeInfo output = typeInfos_[acc_.GetId(gate)];
switch (output) {
case TypeInfo::INT32:
return builder_.ConvertInt32ToFloat64(gate);
case TypeInfo::FLOAT64:
return gate;
case TypeInfo::TAGGED: {
ASSERT(gateType.IsNumberType());
if (gateType.IsIntType()) {
return builder_.CheckTaggedIntAndConvertToFloat64(gate);
} else if (gateType.IsDoubleType()) {
return builder_.CheckTaggedDoubleAndConvertToFloat64(gate);
} else {
return builder_.CheckTaggedNumberAndConvertToFloat64(gate);
}
}
default: {
UNREACHABLE();
return Circuit::NullGate();
}
}
}
GateRef NumberSpeculativeRetype::CheckAndConvertToTagged(GateRef gate, GateType gateType)
{
TypeInfo output = typeInfos_[acc_.GetId(gate)];
switch (output) {
case TypeInfo::INT1:
return builder_.ConvertBoolToTaggedBoolean(gate);
case TypeInfo::INT32:
return builder_.ConvertInt32ToTaggedInt(gate);
case TypeInfo::FLOAT64:
return builder_.ConvertFloat64ToTaggedDouble(gate);
case TypeInfo::TAGGED: {
ASSERT(gateType.IsNumberType() || gateType.IsBooleanType());
builder_.TryPrimitiveTypeCheck(gateType, gate);
return gate;
}
default:
UNREACHABLE();
return Circuit::NullGate();
}
}
GateRef NumberSpeculativeRetype::ConvertToTagged(GateRef gate)
{
TypeInfo output = typeInfos_[acc_.GetId(gate)];
switch (output) {
case TypeInfo::INT1:
return builder_.ConvertBoolToTaggedBoolean(gate);
case TypeInfo::INT32:
return builder_.ConvertInt32ToTaggedInt(gate);
case TypeInfo::FLOAT64:
return builder_.ConvertFloat64ToTaggedDouble(gate);
case TypeInfo::TAGGED: {
return gate;
}
default:
UNREACHABLE();
return Circuit::NullGate();
}
}
void NumberSpeculativeRetype::Run()
{
// visit gate in RPO, propagate use infos and
// reset the machine type of number operator gate and related phi,
// if some tagged phi is used as native value, change it to native phi.
state_ = State::Retype;
VisitGraph();
state_ = State::Convert;
VisitGraph();
}
} // namespace panda::ecmascript::kungfu

View File

@ -0,0 +1,73 @@
/*
* 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_NUMBER_SPECULATIVE_RETYPE_H
#define ECMASCRIPT_COMPILER_NUMBER_SPECULATIVE_RETYPE_H
#include "ecmascript/compiler/circuit_builder.h"
#include "ecmascript/compiler/gate_accessor.h"
#include "ecmascript/compiler/gate_meta_data.h"
#include "ecmascript/compiler/graph_visitor.h"
#include "ecmascript/compiler/number_gate_info.h"
#include "ecmascript/compiler/type.h"
#include "ecmascript/mem/chunk_containers.h"
namespace panda::ecmascript::kungfu {
class NumberSpeculativeRetype : public GraphVisitor {
public:
NumberSpeculativeRetype(Circuit *circuit, Chunk* chunk, ChunkVector<TypeInfo>& typeInfos)
: GraphVisitor(circuit, chunk), acc_(circuit), builder_(circuit), typeInfos_(typeInfos) {}
void Run();
GateRef VisitGate(GateRef gate);
private:
enum class State {
Retype,
Convert,
};
bool IsRetype() const
{
return state_ == State::Retype;
}
bool IsConvert() const
{
return state_ == State::Convert;
}
GateRef SetOutputType(GateRef gate, GateType type);
GateRef VisitPhi(GateRef gate);
GateRef VisitConstant(GateRef gate);
GateRef VisitNumberBinaryOp(GateRef gate);
GateRef VisitNumberCalculate(GateRef gate);
GateRef VisitNumberCompare(GateRef gate);
void ConvertForIntOperator(GateRef gate);
void ConvertForDoubleOperator(GateRef gate);
GateRef VisitNumberRelated(GateRef gate);
GateRef VisitOthers(GateRef gate);
GateRef CheckAndConvertToInt32(GateRef gate, GateType gateType);
GateRef CheckAndConvertToFloat64(GateRef gate, GateType gateType);
GateRef CheckAndConvertToTagged(GateRef gate, GateType gateType);
GateRef ConvertToTagged(GateRef gate);
GateAccessor acc_;
CircuitBuilder builder_;
ChunkVector<TypeInfo>& typeInfos_;
State state_ {0};
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_NUMBER_SPECULATIVE_RETYPE_H

View File

@ -0,0 +1,53 @@
/*
* 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/number_speculative_runner.h"
#include "ecmascript/compiler/number_gate_info.h"
#include "ecmascript/compiler/number_speculative_lowering.h"
namespace panda::ecmascript::kungfu {
void NumberSpeculativeRunner::Run()
{
auto maxId = circuit_->GetMaxGateId();
typeInfos_.resize(maxId + 1, TypeInfo::TAGGED);
NumberSpeculativeRetype retype(circuit_, chunk_, typeInfos_);
retype.Run();
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
<< "===================="
<< " After number speculative retype "
<< "[" << GetMethodName() << "]"
<< "===================="
<< "\033[0m";
circuit_->PrintAllGatesWithBytecode();
LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
}
NumberSpeculativeLowering lowering(circuit_, typeInfos_);
lowering.Run();
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
<< "===================="
<< " After number speculative runner "
<< "[" << GetMethodName() << "]"
<< "===================="
<< "\033[0m";
circuit_->PrintAllGatesWithBytecode();
LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
}
}
} // panda::ecmascript::kungfu

View File

@ -0,0 +1,50 @@
/*
* 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_NUMBER_SPECULATIVE_RUNNER_H
#define ECMASCRIPT_COMPILER_NUMBER_SPECULATIVE_RUNNER_H
#include "ecmascript/compiler/number_speculative_lowering.h"
#include "ecmascript/compiler/number_speculative_retype.h"
namespace panda::ecmascript::kungfu {
class NumberSpeculativeRunner {
public:
NumberSpeculativeRunner(Circuit *circuit, bool enableLog, const std::string& name, Chunk* chunk)
: circuit_(circuit), acc_(circuit), enableLog_(enableLog),
methodName_(name), chunk_(chunk), typeInfos_(chunk) {}
~NumberSpeculativeRunner() = default;
void Run();
private:
bool IsLogEnabled() const
{
return enableLog_;
}
const std::string& GetMethodName() const
{
return methodName_;
}
Circuit *circuit_ {nullptr};
GateAccessor acc_;
bool enableLog_ {false};
std::string methodName_;
Chunk *chunk_ {nullptr};
ChunkVector<TypeInfo> typeInfos_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_NUMBER_SPECULATIVE_RUNNER_H

View File

@ -22,6 +22,7 @@
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/compiler_log.h"
#include "ecmascript/compiler/llvm_codegen.h"
#include "ecmascript/compiler/number_speculative_runner.h"
#include "ecmascript/compiler/scheduler.h"
#include "ecmascript/compiler/slowpath_lowering.h"
#include "ecmascript/compiler/ts_inline_lowering.h"
@ -274,6 +275,18 @@ public:
}
};
class NumberSpeculativePass {
public:
bool Run(PassData* data)
{
TimeScope timescope("NumberSpeculativePass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
Chunk chunk(data->GetNativeAreaAllocator());
bool enableLog = data->GetLog()->EnableMethodCIRLog();
NumberSpeculativeRunner(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk).Run();
return true;
}
};
class EarlyEliminationPass {
public:
bool Run(PassData* data)

View File

@ -116,6 +116,7 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat
if (EnableTypeLowering()) {
pipeline.RunPass<TSTypeLoweringPass>();
pipeline.RunPass<EarlyEliminationPass>();
pipeline.RunPass<NumberSpeculativePass>();
pipeline.RunPass<TypeLoweringPass>();
}
pipeline.RunPass<SlowPathLoweringPass>();

View File

@ -41,6 +41,7 @@ void SlowPathLowering::CallRuntimeLowering()
{
std::vector<GateRef> gateList;
circuit_->GetAllGates(gateList);
for (const auto &gate : gateList) {
auto op = acc_.GetOpCode(gate);
if (op == OpCode::JS_BYTECODE) {
@ -59,6 +60,8 @@ void SlowPathLowering::CallRuntimeLowering()
LowerTypedAotCall(gate);
} else if (op == OpCode::UPDATE_HOTNESS) {
LowerUpdateHotness(gate);
} else if (op == OpCode::STATE_SPLIT) {
DeleteStateSplit(gate);
}
}
@ -73,6 +76,12 @@ void SlowPathLowering::CallRuntimeLowering()
}
}
void SlowPathLowering::DeleteStateSplit(GateRef gate)
{
auto depend = acc_.GetDep(gate);
acc_.ReplaceGate(gate, Circuit::NullGate(), depend, Circuit::NullGate());
}
void SlowPathLowering::LowerToJSCall(GateRef hirGate, const std::vector<GateRef> &args)
{
GateRef stateInGate = builder_.GetState();

View File

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

View File

@ -32,8 +32,6 @@ void TSTypeLowering::RunTSTypeLowering()
}
}
VerifyGuard();
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
LOG_COMPILER(INFO) << "\033[34m"
@ -512,8 +510,6 @@ void TSTypeLowering::SpeculateNumbers(GateRef gate)
GateType leftType = acc_.GetGateType(left);
GateType rightType = acc_.GetGateType(right);
GateType gateType = acc_.GetGateType(gate);
builder_.TryPrimitiveTypeCheck(leftType, left);
builder_.TryPrimitiveTypeCheck(rightType, right);
ASSERT(acc_.GetOpCode(acc_.GetDep(gate)) == OpCode::STATE_SPLIT);
GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType);
@ -536,7 +532,6 @@ void TSTypeLowering::SpeculateNumber(GateRef gate)
GateType valueType = acc_.GetGateType(value);
GateType gateType = acc_.GetGateType(gate);
builder_.TryPrimitiveTypeCheck(valueType, value);
if (valueType.IsIntType() && NeedInt32OverflowCheck(Op)) {
builder_.Int32OverflowCheck<Op>(value);
}
@ -563,7 +558,6 @@ void TSTypeLowering::LowerPrimitiveTypeToNumber(GateRef gate)
{
GateRef src = acc_.GetValueIn(gate, 0);
GateType srcType = acc_.GetGateType(src);
builder_.TryPrimitiveTypeCheck(srcType, src);
ASSERT(acc_.GetOpCode(acc_.GetDep(gate)) == OpCode::STATE_SPLIT);
GateRef result = builder_.PrimitiveToNumber(src, VariableType(MachineType::I64, srcType));
@ -789,7 +783,6 @@ void TSTypeLowering::LowerTypedStObjByIndex(GateRef gate)
}
GateRef index = acc_.GetValueIn(gate, 1);
builder_.IndexCheck(receiverType, receiver, index);
builder_.TryPrimitiveTypeCheck(valueType, value);
ASSERT(acc_.GetOpCode(acc_.GetDep(gate)) == OpCode::STATE_SPLIT);
if (tsManager_->IsFloat32ArrayType(receiverType)) {
@ -826,10 +819,8 @@ void TSTypeLowering::LowerTypedLdObjByValue(GateRef gate, bool isThis)
AddProfiling(gate);
builder_.TryPrimitiveTypeCheck(GateType::IntType(), propKey);
builder_.StableArrayCheck(receiver);
builder_.IndexCheck(receiverType, receiver, propKey);
ASSERT(acc_.GetOpCode(acc_.GetDep(gate)) == OpCode::STATE_SPLIT);
GateRef result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_ELEMENT>(receiver, propKey);
@ -848,8 +839,6 @@ void TSTypeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
AddProfiling(gate);
builder_.TryPrimitiveTypeCheck(valueType, value);
ASSERT(acc_.GetOpCode(acc_.GetDep(gate)) == OpCode::STATE_SPLIT);
GateRef result;

View File

@ -202,6 +202,11 @@ public:
return (m == 0) && (l == static_cast<uint32_t>(TSPrimitiveType::BIG_INT));
}
bool IsNJSValueType() const
{
return type_ == NJS_VALUE;
}
bool IsDigitablePrimitiveType() const
{
return IsNumberType() || IsNullType() || IsUndefinedType() || IsBooleanType() || IsBigIntType();
@ -269,6 +274,16 @@ private:
uint32_t type_ {0};
};
enum class ValueType : uint8_t {
BOOL,
INT32,
FLOAT64,
TAGGED_BOOLEAN,
TAGGED_INT,
TAGGED_DOUBLE,
TAGGED_NUMBER,
};
class Type {
public:
explicit Type(GateType payload);

View File

@ -118,6 +118,12 @@ void TypeLowering::LowerType(GateRef gate)
case OpCode::GET_SUPER_CONSTRUCTOR:
LowerGetSuperConstructor(gate);
break;
case OpCode::CONVERT:
LowerConvert(gate);
break;
case OpCode::CHECK_AND_CONVERT:
LowerCheckAndConvert(gate);
break;
default:
break;
}
@ -640,7 +646,29 @@ void TypeLowering::LowerArrayLoadElement(GateRef gate)
GateRef element =
builder_.Load(VariableType::JS_POINTER(), receiver, builder_.IntPtr(JSObject::ELEMENTS_OFFSET));
GateRef index = acc_.GetValueIn(gate, 1);
index = builder_.GetInt32OfTInt(index);
GateType indexType = acc_.GetGateType(gate);
Label midMerge(&builder_);
if (indexType.IsIntType()) {
index = builder_.GetInt32OfTInt(index);
} else if (indexType.IsDoubleType()) {
index = builder_.TruncFloatToInt32(builder_.GetDoubleOfTDouble(index));
} else {
// is number and need typecheck in runtime.
DEFVAlUE(idx, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label isInt(&builder_);
Label isDouble(&builder_);
builder_.Branch(builder_.TaggedIsInt(index), &isInt, &isDouble);
builder_.Bind(&isInt);
idx = builder_.GetInt32OfTInt(index);
builder_.Jump(&midMerge);
builder_.Bind(&isDouble);
idx = builder_.TruncFloatToInt32(builder_.GetDoubleOfTDouble(index));
builder_.Jump(&midMerge);
builder_.Bind(&midMerge);
index = *idx;
}
GateRef res = builder_.GetValueFromTaggedArray(element, index);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), res);
Label isHole(&builder_);
@ -3149,4 +3177,179 @@ void TypeLowering::ReplaceHirWithPendingException(GateRef hirGate, GateRef glue,
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
}
void TypeLowering::LowerConvert(GateRef gate)
{
GateRef value = acc_.GetValueIn(gate);
ValueType srcType = acc_.GetSrcType(gate);
ValueType dstType = acc_.GetDstType(gate);
GateRef result = Circuit::NullGate();
if (srcType == ValueType::BOOL) {
ASSERT(dstType == ValueType::TAGGED_BOOLEAN);
result = ConvertBoolToTaggedBoolean(value);
} else if (srcType == ValueType::INT32) {
ASSERT(dstType == ValueType::TAGGED_INT || dstType == ValueType::FLOAT64);
if (dstType == ValueType::TAGGED_INT) {
result = ConvertInt32ToTaggedInt(value);
} else {
result = ConvertInt32ToFloat64(value);
}
} else if (srcType == ValueType::FLOAT64) {
ASSERT(dstType == ValueType::TAGGED_DOUBLE || dstType == ValueType::INT32);
if (dstType == ValueType::TAGGED_DOUBLE) {
result = ConvertFloat64ToTaggedDouble(value);
} else {
result = ConvertFloat64ToInt32(value);
}
}
acc_.ReplaceGate(gate, Circuit::NullGate(), Circuit::NullGate(), result);
}
GateRef TypeLowering::ConvertTaggedNumberToInt32(GateRef gate, Label *exit)
{
DEFVAlUE(result, (&builder_), VariableType::INT32(), builder_.Int32(0));
Label isInt(&builder_);
Label isDouble(&builder_);
builder_.Branch(builder_.TaggedIsInt(gate), &isInt, &isDouble);
builder_.Bind(&isInt);
result = ConvertTaggedIntToInt32(gate);
builder_.Jump(exit);
builder_.Bind(&isDouble);
result = ConvertFloat64ToInt32(ConvertTaggedDoubleToFloat64(gate));
builder_.Jump(exit);
builder_.Bind(exit);
return *result;
}
GateRef TypeLowering::ConvertTaggedNumberToFloat64(GateRef gate, Label *exit)
{
DEFVAlUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
Label isInt(&builder_);
Label isDouble(&builder_);
builder_.Branch(builder_.TaggedIsInt(gate), &isInt, &isDouble);
builder_.Bind(&isInt);
result = ConvertInt32ToFloat64(ConvertTaggedIntToInt32(gate));
builder_.Jump(exit);
builder_.Bind(&isDouble);
result = ConvertTaggedDoubleToFloat64(gate);
builder_.Jump(exit);
builder_.Bind(exit);
return *result;
}
void TypeLowering::LowerCheckAndConvert(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
ValueType srcType = acc_.GetSrcType(gate);
switch (srcType) {
case ValueType::TAGGED_INT:
LowerCheckTaggedIntAndConvert(gate);
break;
case ValueType::TAGGED_DOUBLE:
LowerCheckTaggedDoubleAndConvert(gate);
break;
case ValueType::TAGGED_NUMBER:
LowerCheckTaggedNumberAndConvert(gate);
break;
default:
UNREACHABLE();
}
}
void TypeLowering::LowerCheckTaggedIntAndConvert(GateRef gate)
{
GateRef frameState = GetFrameState(gate);
GateRef value = acc_.GetValueIn(gate, 0);
GateRef typeCheck = builder_.TaggedIsInt(value);
builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTINT);
GateRef result = Circuit::NullGate();
ValueType dst = acc_.GetDstType(gate);
ASSERT(dst == ValueType::INT32 || dst == ValueType::FLOAT64);
if (dst == ValueType::INT32) {
result = ConvertTaggedIntToInt32(value);
} else {
result = ConvertTaggedIntToFloat64(value);
}
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void TypeLowering::LowerCheckTaggedDoubleAndConvert(GateRef gate)
{
GateRef frameState = GetFrameState(gate);
GateRef value = acc_.GetValueIn(gate, 0);
GateRef typeCheck = builder_.TaggedIsDouble(value);
builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTDOUBLE);
GateRef result = Circuit::NullGate();
ValueType dst = acc_.GetDstType(gate);
ASSERT(dst == ValueType::INT32 || dst == ValueType::FLOAT64);
if (dst == ValueType::INT32) {
result = ConvertTaggedDoubleToInt32(value);
} else {
result = ConvertTaggedDoubleToFloat64(value);
}
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void TypeLowering::LowerCheckTaggedNumberAndConvert(GateRef gate)
{
GateRef frameState = GetFrameState(gate);
GateRef value = acc_.GetValueIn(gate, 0);
GateRef typeCheck = builder_.TaggedIsNumber(value);
builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTNUMBER);
GateRef result = Circuit::NullGate();
ValueType dst = acc_.GetDstType(gate);
ASSERT(dst == ValueType::INT32 || dst == ValueType::FLOAT64);
Label exit(&builder_);
if (dst == ValueType::INT32) {
result = ConvertTaggedNumberToInt32(value, &exit);
} else {
result = ConvertTaggedNumberToFloat64(value, &exit);
}
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
GateRef TypeLowering::ConvertBoolToTaggedBoolean(GateRef gate)
{
return builder_.BooleanToTaggedBooleanPtr(gate);
}
GateRef TypeLowering::ConvertInt32ToFloat64(GateRef gate)
{
return builder_.ChangeInt32ToFloat64(gate);
}
GateRef TypeLowering::ConvertInt32ToTaggedInt(GateRef gate)
{
return builder_.Int32ToTaggedPtr(gate);
}
GateRef TypeLowering::ConvertFloat64ToInt32(GateRef gate)
{
return builder_.ChangeFloat64ToInt32(gate);
}
GateRef TypeLowering::ConvertFloat64ToTaggedDouble(GateRef gate)
{
return builder_.DoubleToTaggedDoublePtr(gate);
}
GateRef TypeLowering::ConvertTaggedIntToInt32(GateRef gate)
{
return builder_.GetInt32OfTInt(gate);
}
GateRef TypeLowering::ConvertTaggedIntToFloat64(GateRef gate)
{
return builder_.ChangeInt32ToFloat64(builder_.GetInt32OfTInt(gate));
}
GateRef TypeLowering::ConvertTaggedDoubleToInt32(GateRef gate)
{
return builder_.ChangeFloat64ToInt32(builder_.GetDoubleOfTDouble(gate));
}
GateRef TypeLowering::ConvertTaggedDoubleToFloat64(GateRef gate)
{
return builder_.GetDoubleOfTDouble(gate);
}
} // namespace panda::ecmascript

View File

@ -253,6 +253,24 @@ private:
GateRef GetObjectFromConstPool(GateRef jsFunc, GateRef index);
GateRef ConvertNumberToBool(GateRef gate, GateType valueType);
GateRef ConvertBooleanToBool(GateRef gate);
void LowerConvert(GateRef gate);
void LowerCheckAndConvert(GateRef gate);
void LowerCheckTaggedIntAndConvert(GateRef gate);
void LowerCheckTaggedDoubleAndConvert(GateRef gate);
void LowerCheckTaggedNumberAndConvert(GateRef gate);
GateRef ConvertBoolToTaggedBoolean(GateRef gate);
GateRef ConvertInt32ToFloat64(GateRef gate);
GateRef ConvertInt32ToTaggedInt(GateRef gate);
GateRef ConvertFloat64ToInt32(GateRef gate);
GateRef ConvertFloat64ToTaggedDouble(GateRef gate);
GateRef ConvertTaggedIntToInt32(GateRef gate);
GateRef ConvertTaggedIntToFloat64(GateRef gate);
GateRef ConvertTaggedDoubleToInt32(GateRef gate);
GateRef ConvertTaggedDoubleToFloat64(GateRef gate);
GateRef ConvertTaggedNumberToInt32(GateRef gate, Label *exit);
GateRef ConvertTaggedNumberToFloat64(GateRef gate, Label *exit);
GateRef GetFrameState(GateRef gate) const
{
return acc_.GetFrameState(gate);