Array Bounds Check Elimination - Part 2

(Loop-Invariant Checks + Grouping Checks)
Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7V12I
Signed-off-by: liuzhijie <jay.lau2020.work@outlook.com>

Change-Id: I584c54a9ed5c472f43f8a83d3fdab6c588db5898
This commit is contained in:
liuzhijie 2023-08-16 17:34:22 +08:00
parent d37c289fd8
commit 39e0d61227
19 changed files with 1046 additions and 90 deletions

View File

@ -12,16 +12,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/array_bounds_check_elimination.h"
namespace panda::ecmascript::kungfu {
void ArrayBoundsCheckElimination::Run()
{
bounds_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
indexCheckInfo_.resize(circuit_->GetMaxGateId() + 1, nullptr);
graphLinearizer_.SetScheduleJSOpcode();
graphLinearizer_.LinearizeGraph();
CalcBounds(graphLinearizer_.GetEntryRegion());
CalcBounds(graphLinearizer_.GetEntryRegion(), nullptr);
if (IsLogEnabled()) {
LOG_COMPILER(INFO) << "";
@ -152,6 +154,26 @@ ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::AndOp(Bound *bo
return bound;
}
ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::OrOp(Bound *bound, Bound *b)
{
// Update lower bound
if (bound->lowerGate_ != b->lowerGate_) {
bound->lowerGate_ = Circuit::NullGate();
bound->lower_ = INT_MIN;
} else {
bound->lower_ = std::min(bound->lower_, b->lower_);
}
// Update upper bound
if (bound->upperGate_ != b->upperGate_) {
bound->upperGate_ = Circuit::NullGate();
bound->upper_ = INT_MAX;
} else {
bound->upper_ = std::max(bound->upper_, b->upper_);
}
return bound;
}
ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::DoConstant(GateRef gate)
{
int constValue = acc_.GetConstantValue(gate);
@ -164,7 +186,32 @@ ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::DoArithmeticOp(
auto x = acc_.GetValueIn(gate, 0);
auto y = acc_.GetValueIn(gate, 1);
if (!acc_.IsConstant(x) || !acc_.IsConstant(y)) { // One of the operands must be non-constant!
if (((acc_.IsConstant(x) || acc_.IsConstant(y)) && op == TypedBinOp::TYPED_ADD) ||
if (op == TypedBinOp::TYPED_AND && (acc_.IsConstant(x) || acc_.IsConstant(y))) {
int constValue = 0;
if (acc_.IsConstant(x)) {
constValue = acc_.GetConstantValue(x);
} else {
constValue = acc_.GetConstantValue(y);
}
if (constValue >= 0) {
return new Bound(0, Circuit::NullGate(), constValue, Circuit::NullGate());
}
} else if (op == TypedBinOp::TYPED_MOD) {
Bound *xBound = GetBound(x);
if (xBound->Lower() >= 0 && xBound->LowerGate() == Circuit::NullGate() && IsArrayLength(y)) {
return new Bound(0, Circuit::NullGate(), -1, y);
} else if (xBound->HasLower() && xBound->Lower() >= 0 && acc_.IsConstant(y)
&& acc_.GetConstantValue(y) != 0) {
int constValue = acc_.GetConstantValue(y);
if (constValue != INT_MIN) {
return new Bound(0, Circuit::NullGate(), abs(constValue) - 1, Circuit::NullGate());
} else {
return new Bound();
}
} else {
return new Bound();
}
} else if (((acc_.IsConstant(x) || acc_.IsConstant(y)) && op == TypedBinOp::TYPED_ADD) ||
(acc_.IsConstant(y) && op == TypedBinOp::TYPED_SUB)) {
// x is constant, y is variable.
if (acc_.IsConstant(y)) {
@ -193,18 +240,94 @@ ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::DoArithmeticOp(
} else {
return new Bound(newLower, bound->LowerGate(), newUpper, bound->UpperGate());
}
} else {
} else if (op == TypedBinOp::TYPED_SUB) {
Bound *bound = GetBound(x);
if (op == TypedBinOp::TYPED_SUB && bound->LowerGate() == y) {
if (bound->LowerGate() == y) {
return new Bound(TypedBinOp::TYPED_GREATEREQ, Circuit::NullGate(), bound->Lower());
} else {
return new Bound();
}
} else {
return new Bound();
}
}
return nullptr;
}
bool ArrayBoundsCheckElimination::InLoop(GateRef loopHeader, GateRef gate)
{
while (gate != acc_.GetStateRoot()) {
if (gate == loopHeader) {
return true;
} else {
gate = acc_.GetState(gate, 0);
}
}
return false;
}
/*
Do phi
*/
ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::DoPhi(GateRef gate)
{
Bound *bound = nullptr;
size_t valueSize = acc_.GetInValueCount(gate);
GateRef stateIn = acc_.GetState(gate);
bool isLoopHead = acc_.IsLoopHead(stateIn);
bool hasUpper = true;
bool hasLower = true;
for (size_t i = 0; i < valueSize; i++) {
GateRef value = acc_.GetValueIn(gate, i);
// Check if instruction is connected with phi itself
if (isLoopHead && acc_.GetOpCode(value) == OpCode::TYPED_UNARY_OP
&& InLoop(stateIn, value)) {
auto unOp = acc_.GetTypedUnAccessor(value).GetTypedUnOp();
switch (unOp) {
case TypedUnOp::TYPED_INC:
hasUpper = false;
break;
case TypedUnOp::TYPED_DEC:
hasLower = false;
break;
default:
break;
}
continue;
}
Bound *vBound = GetBound(value);
Bound *curBound;
GateRef curGate;
int curConstant;
GetInstrAndConstValueFromOp(value, curGate, curConstant);
if (!vBound->HasUpper() || !vBound->HasLower()) {
curBound = new Bound(curConstant, curGate, curConstant, curGate);
} else {
curBound = vBound;
}
if (curBound) {
if (!bound) {
bound = curBound->Copy();
} else {
bound = OrOp(bound, curBound);
}
} else {
bound = new Bound();
break;
}
}
if (!hasUpper) {
bound->RemoveUpper();
}
if (!hasLower) {
bound->RemoveLower();
}
return bound;
}
ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::VisitGate(GateRef gate)
{
OpCode op = acc_.GetOpCode(gate);
@ -213,12 +336,66 @@ ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::VisitGate(GateR
return DoConstant(gate);
case OpCode::TYPED_BINARY_OP:
return DoArithmeticOp(gate);
case OpCode::VALUE_SELECTOR:
return DoPhi(gate);
default:
return nullptr;
}
return nullptr;
}
// y = a + b - c .....
void ArrayBoundsCheckElimination::GetInstrAndConstValueFromOp(GateRef gate, GateRef& instrValue, int& constValue)
{
int base = 0;
constValue = 0;
instrValue = gate;
if (acc_.IsConstant(gate)) {
constValue = acc_.GetConstantValue(gate);
instrValue = Circuit::NullGate();
} else {
while (acc_.GetOpCode(gate) == OpCode::TYPED_BINARY_OP) {
auto op = acc_.GetTypedBinaryOp(gate);
auto x = acc_.GetValueIn(gate, 0);
auto y = acc_.GetValueIn(gate, 1);
GateRef other = x;
if ((op == TypedBinOp::TYPED_ADD && (acc_.IsConstant(x) || acc_.IsConstant(y)))
|| (op == TypedBinOp::TYPED_SUB && acc_.IsConstant(y))) {
int value = 0;
if (acc_.IsConstant(x)) {
value = acc_.GetConstantValue(x);
other = y;
} else {
value = acc_.GetConstantValue(y);
other = x;
}
while (acc_.GetOpCode(other) == OpCode::INDEX_CHECK) { // Get IndexCheck Index
other = acc_.GetValueIn(other, 1);
}
if (op == TypedBinOp::TYPED_SUB) {
value = -value;
}
if (acc_.IsConstant(other)) {
base += value + acc_.GetConstantValue(other);
constValue = base;
instrValue = Circuit::NullGate();
break ;
} else {
base += value;
constValue = base;
instrValue = other;
gate = other;
}
} else {
break;
}
}
}
}
ArrayBoundsCheckElimination::Bound *ArrayBoundsCheckElimination::GetBound(GateRef gate)
{
if (gate == Circuit::NullGate()) {
@ -295,42 +472,43 @@ void ArrayBoundsCheckElimination::AddIfCondition(IntegerStack &pushed, GateRef x
if (acc_.IsConstant(x)) { // x must be non-constant!
return;
}
int constValue = 0;
GateRef instrValue = y;
if (acc_.IsConstant(y)) {
constValue = acc_.GetConstantValue(y);
instrValue = Circuit::NullGate();
} else if (acc_.GetOpCode(y) == OpCode::TYPED_BINARY_OP) {
auto binaryOp = acc_.GetTypedBinaryOp(y);
auto a = acc_.GetValueIn(y, 0);
auto b = acc_.GetValueIn(y, 1);
if (binaryOp == TypedBinOp::TYPED_ADD) {
if (acc_.IsConstant(a)) {
constValue = acc_.GetConstantValue(a);
instrValue = b;
} else if (acc_.IsConstant(b)) {
constValue = acc_.GetConstantValue(b);
instrValue = a;
}
} else if (binaryOp == TypedBinOp::TYPED_SUB && acc_.IsConstant(b)) { // x >= a op b
constValue = -acc_.GetConstantValue(b);
instrValue = a;
}
}
int constValue;
GateRef instrValue;
GetInstrAndConstValueFromOp(y, instrValue, constValue);
UpdateBound(pushed, x, op, instrValue, constValue);
}
bool ArrayBoundsCheckElimination::IsArrayLength(GateRef gate)
{
if (gate == Circuit::NullGate()) {
return false;
}
OpCode op = acc_.GetOpCode(gate);
switch (op) {
case OpCode::LOAD_ARRAY_LENGTH:
case OpCode::LOAD_TYPED_ARRAY_LENGTH:
return true;
default:
return false;
}
UNREACHABLE();
return false;
}
bool ArrayBoundsCheckElimination::InArrayBound(Bound *bound, GateRef length, GateRef array)
{
if (!bound || array == Circuit::NullGate()) {
return false;
}
if (bound->Lower() >= 0 && bound->LowerGate() == Circuit::NullGate() &&
bound->Upper() < 0 && bound->UpperGate() != Circuit::NullGate()) {
if (bound->UpperGate() == array || (length != Circuit::NullGate() && bound->UpperGate() == length)) {
if (length != Circuit::NullGate() && bound->UpperGate() == length) {
return true;
}
}
// TODO: Solve Multidimensional array. To fix a[i][j] case, maybe LOAD_ELEMENT are not the same one.
return false;
}
@ -344,25 +522,120 @@ void ArrayBoundsCheckElimination::RemoveIndexCheck(GateRef gate)
GateRef state = acc_.GetState(gate);
GateRef value = acc_.GetValueIn(gate, 1); // Index
auto uses = acc_.Uses(gate);
for (auto it = uses.begin(); it != uses.end();) {
if (acc_.IsStateIn(it)) {
ASSERT(state != Circuit::NullGate());
it = acc_.ReplaceIn(it, state);
} else if (acc_.IsDependIn(it)) {
ASSERT(depend != Circuit::NullGate());
it = acc_.ReplaceIn(it, depend);
} else if (acc_.IsValueIn(it)) {
ASSERT(value != Circuit::NullGate());
it = acc_.ReplaceIn(it, value);
} else {
++it;
}
}
acc_.DeleteGate(gate);
acc_.ReplaceGate(gate, state, depend, value);
}
void ArrayBoundsCheckElimination::ProcessIndexCheck(GateRef gate)
bool ArrayBoundsCheckElimination::CheckLoop(GateRef array, GateRef lowerGate, int lower, GateRef upperGate, int upper)
{
if (IsArrayLength(upperGate) && acc_.GetValueIn(upperGate, 0) == array) {
if (upper >= 0) {
return false;
}
}
if (IsArrayLength(lowerGate) && acc_.GetValueIn(lowerGate, 0) == array) {
if (lower >= 0) {
return false;
}
}
return true;
}
bool ArrayBoundsCheckElimination::LoopInvariant(GateRegion *loopHeader, GateRef gate)
{
if (gate == Circuit::NullGate()) {
return true;
}
auto gateRegion = graphLinearizer_.GateToRegion(gate);
if (!gateRegion) {
return true;
}
GateRegion* g = loopHeader->GetDominator();
while (g != nullptr) {
if (g == gateRegion) {
return true;
}
if (g == g->GetDominator()) { // entry
break ;
}
g = g->GetDominator();
}
return false;
}
GateRef ArrayBoundsCheckElimination::Predicate(GateRef left, TypedBinOp cond, GateRef right)
{
return builder_.InsertRangeCheckPredicate(left, cond, right);
}
GateRef ArrayBoundsCheckElimination::PredicateCmpWithConst(GateRef left, TypedBinOp cond, int32_t right)
{
GateRef constGate = builder_.Int32(right);
return Predicate(left, cond, constGate);
}
GateRef ArrayBoundsCheckElimination::PredicateAdd(GateRef left, int32_t leftConst, TypedBinOp cond, GateRef right)
{
GateRef constGate = builder_.Int32(leftConst);
GateRef binaryOpGate = builder_.InsertTypedBinaryop(left, constGate, GateType::NumberType(),
GateType::NumberType(), GateType::AnyType(),
PGOSampleType::NoneType(), TypedBinOp::TYPED_ADD);
return Predicate(binaryOpGate, cond, right);
}
GateRef ArrayBoundsCheckElimination::PredicateAddCmpWithConst(GateRef left, int32_t leftConst,
TypedBinOp cond, int32_t right)
{
GateRef constGate = builder_.Int32(right);
return PredicateAdd(left, leftConst, cond, constGate);
}
void ArrayBoundsCheckElimination::LoopInvariantMotionForIndexCheck(GateRef array, GateRef length,
GateRef lowerGate, int lower,
GateRef upperGate, int upper,
bool isTypedArray)
{
// lower > 0
if (lowerGate != Circuit::NullGate()) {
if (lower == 0) {
// lowerGate >= 0
PredicateCmpWithConst(lowerGate, TypedBinOp::TYPED_GREATEREQ, 0);
} else if (lower > 0) {
// lowerGate + lower >= 0
PredicateAddCmpWithConst(lowerGate, lower, TypedBinOp::TYPED_GREATEREQ, 0);
} else {
// lowerGate + lower < 0
// lower < 0
// lowerGate < -lower
lower++;
lower = -lower;
PredicateCmpWithConst(lowerGate, TypedBinOp::TYPED_GREATER, lower);
}
}
// LOAD LENGTH if necessary
if (length == Circuit::NullGate()) {
length = builder_.InsertLoadArrayLength(array, isTypedArray);
}
if (upperGate == Circuit::NullGate()) {
ASSERT(upper >= 0);
PredicateCmpWithConst(length, TypedBinOp::TYPED_GREATER, upper);
} else {
if (upper == 0) {
Predicate(upperGate, TypedBinOp::TYPED_LESS, length);
} else if (upper > 0) {
// upperGate + upper < length
PredicateAdd(upperGate, upper, TypedBinOp::TYPED_LESS, length);
} else {
// upperGate + upper < length
// upper < 0
// upperGate < length + (-upper)
PredicateAdd(length, -upper, TypedBinOp::TYPED_GREATER, upperGate);
}
}
}
void ArrayBoundsCheckElimination::ProcessIndexCheck(GateRegion *loopHeader, GateRef gate)
{
auto length = acc_.GetValueIn(gate, 0);
auto array = acc_.GetValueIn(length, 0);
@ -371,7 +644,45 @@ void ArrayBoundsCheckElimination::ProcessIndexCheck(GateRef gate)
if (!indexBound->HasLower() || !indexBound->HasUpper()) {
return;
}
if (InArrayBound(indexBound, array, length)) {
if (InArrayBound(indexBound, length, array)) {
RemoveIndexCheck(gate);
} else if (loopHeader) {
if (!LoopInvariant(loopHeader, array)
|| !LoopInvariant(loopHeader, indexBound->LowerGate())
|| !LoopInvariant(loopHeader, indexBound->UpperGate())
|| (indexBound->LowerGate() == Circuit::NullGate() && indexBound->Lower() < 0)
|| (indexBound->UpperGate() == Circuit::NullGate() && indexBound->Upper() < 0)) {
return;
}
ASSERT(length != Circuit::NullGate());
bool isTypedArray = false;
if (acc_.GetOpCode(length) == OpCode::LOAD_TYPED_ARRAY_LENGTH) {
isTypedArray = true;
}
// Length instrution
if (!LoopInvariant(loopHeader, length)) {
// Generate length instruction yourself
length = Circuit::NullGate();
}
// Insert Before loopHeader State, and if find IF_TRUE and IF_FALSE, insert after the DEPEND_RELAY
// if find MERGE, insert after DEPEND_SELECTOR
GateRef insertAfter = acc_.GetState(loopHeader->GetState(), 0); // after end
GateRef stateIn = insertAfter;
GateRef dependIn = insertAfter;
acc_.GetStateInAndDependIn(insertAfter, stateIn, dependIn);
if (!CheckLoop(array, indexBound->LowerGate(), indexBound->Lower(),
indexBound->UpperGate(), indexBound->Upper())) {
return;
}
Environment env(stateIn, dependIn, {}, circuit_, &builder_);
LoopInvariantMotionForIndexCheck(array, length, indexBound->LowerGate(), indexBound->Lower(),
indexBound->UpperGate(), indexBound->Upper(), isTypedArray);
RemoveIndexCheck(gate);
}
}
@ -379,10 +690,13 @@ void ArrayBoundsCheckElimination::ProcessIndexCheck(GateRef gate)
void ArrayBoundsCheckElimination::ProcessIf(IntegerStack &pushed, GateRegion *parent, OpCode cond)
{
auto& gateLists = parent->GetGates();
for (size_t i = gateLists.size() - 1; i >= 0; i--) { // Found the last BinaryOp
for (int i = gateLists.size() - 1; i >= 0; i--) { // Found the last BinaryOp
GateRef gate = gateLists[i];
if (gate == Circuit::NullGate()) continue;
OpCode opGate = acc_.GetOpCode(gate);
if (opGate != OpCode::TYPED_BINARY_OP) continue;
if (opGate != OpCode::TYPED_BINARY_OP) {
continue ;
}
TypedBinOp op = acc_.GetTypedBinaryOp(gate);
GateRef x = acc_.GetValueIn(gate, 0);
@ -408,7 +722,7 @@ void ArrayBoundsCheckElimination::ProcessIf(IntegerStack &pushed, GateRegion *pa
}
}
bool ArrayBoundsCheckElimination::Contain(ChunkVector<GateRef>& gateLists, GateRef gate)
bool ArrayBoundsCheckElimination::Contain(GateLists &gateLists, GateRef gate)
{
for (size_t i = 0; i < gateLists.size(); i++) {
if (gateLists[i] == gate) {
@ -418,7 +732,154 @@ bool ArrayBoundsCheckElimination::Contain(ChunkVector<GateRef>& gateLists, GateR
return false;
}
void ArrayBoundsCheckElimination::CalcBounds(GateRegion *block)
void ArrayBoundsCheckElimination::AddAccessIndexedInfo(GateLists &indices, GateRef gate, int idx, GateRef indexCheck)
{
IndexCheckInfo *indexCheckInfo = indexCheckInfo_[acc_.GetId(gate)];
if (indexCheckInfo == nullptr) {
indexCheckInfo = new IndexCheckInfo(chunk_);
indexCheckInfo_[acc_.GetId(gate)] = indexCheckInfo;
indices.push_back(gate);
indexCheckInfo->min_ = idx;
indexCheckInfo->max_ = idx;
} else if (idx >= indexCheckInfo->min_ && idx <= indexCheckInfo->max_) {
RemoveIndexCheck(indexCheck);
return;
}
indexCheckInfo->min_ = std::min(indexCheckInfo->min_, idx);
indexCheckInfo->max_ = std::max(indexCheckInfo->max_, idx);
indexCheckInfo->list_.push_back(indexCheck);
}
void ArrayBoundsCheckElimination::InBlockMotion(GateLists &indexChecked, GateLists &arrays)
{
GateLists indices(chunk_);
for (size_t i = 0; i < arrays.size(); i++) {
int maxConstant = -1;
GateLists listConstant(chunk_);
GateRef arrayGate = arrays[i];
for (size_t j = 0; j < indexChecked.size(); j++) {
GateRef indexCheck = indexChecked[j];
// INDEX_CHECK may be dead
if (acc_.GetOpCode(indexCheck) != OpCode::INDEX_CHECK) {
continue;
}
GateRef length = acc_.GetValueIn(indexCheck, 0);
GateRef index = acc_.GetValueIn(indexCheck, 1);
GateRef array = acc_.GetValueIn(length, 0);
if (array != arrayGate) {
continue;
}
if (acc_.IsConstant(index)) {
int constValue = acc_.GetConstantValue(index);
if (constValue >= 0 && constValue <= maxConstant) {
RemoveIndexCheck(indexCheck);
} else if (constValue >= 0 && constValue > maxConstant) {
maxConstant = constValue;
listConstant.push_back(indexCheck);
}
} else {
int lastInteger;
GateRef lastGate;
GetInstrAndConstValueFromOp(index, lastGate, lastInteger);
if (lastInteger >= 0 && lastGate == Circuit::NullGate()) { // IsConstant
if (lastInteger <= maxConstant) {
RemoveIndexCheck(indexCheck);
} else {
maxConstant = lastInteger;
listConstant.push_back(indexCheck);
}
} else if (lastGate != Circuit::NullGate()) {
AddAccessIndexedInfo(indices, lastGate, lastInteger, indexCheck);
} // when lastInteger < 0, dont remove IndexCheck
}
}
// Iterate over all different indices
for (size_t j = 0; j < indices.size(); j++) {
GateRef index = indices[j];
IndexCheckInfo *info = indexCheckInfo_[acc_.GetId(index)];
ASSERT(info != nullptr);
// maybe index < 0, max > 0
// max + index in [0, a.length)
// min + index overflow !!!, min + index > 0
// so, min + index >= INT_MIN, min >= INT_MIN - index
// max in [-index, a.length - index)
// min >= INT_MIN + max
bool rangeCond = (info->max_ < 0 || info->max_ + INT_MIN <= info->min_);
if (info->list_.size() > 2 && rangeCond) {
GateRef insertAfter = info->list_.front();
GateRef length = acc_.GetValueIn(insertAfter, 0);
ASSERT(length != Circuit::NullGate());
Environment env(insertAfter, circuit_, &builder_);
// Calculate lower bound
GateRef lowerCompare = index;
if (info->min_ > 0) {
GateRef minGate = builder_.Int32(info->min_);
lowerCompare = builder_.InsertTypedBinaryop(lowerCompare, minGate,
GateType::NumberType(), GateType::NumberType(),
GateType::AnyType(), PGOSampleType::NoneType(),
TypedBinOp::TYPED_ADD);
} else if (info->min_ < 0) {
GateRef minGate = builder_.Int32(-info->min_);
lowerCompare = builder_.InsertTypedBinaryop(lowerCompare, minGate,
GateType::NumberType(), GateType::NumberType(),
GateType::AnyType(), PGOSampleType::NoneType(),
TypedBinOp::TYPED_SUB);
}
PredicateCmpWithConst(lowerCompare, TypedBinOp::TYPED_GREATEREQ, 0);
// Calculate upper bound
GateRef upperCompare = index;
if (info->max_ != 0) {
if (info->max_ > 0) {
GateRef maxGate = builder_.Int32(info->max_);
upperCompare = builder_.InsertTypedBinaryop(upperCompare, maxGate,
GateType::NumberType(), GateType::NumberType(),
GateType::AnyType(), PGOSampleType::NoneType(),
TypedBinOp::TYPED_ADD);
} else if (info->max_ < 0) {
GateRef maxGate = builder_.Int32(-info->max_);
upperCompare = builder_.InsertTypedBinaryop(upperCompare, maxGate,
GateType::NumberType(), GateType::NumberType(),
GateType::AnyType(), PGOSampleType::NoneType(),
TypedBinOp::TYPED_SUB);
}
}
Predicate(upperCompare, TypedBinOp::TYPED_LESS, length);
for (auto& indexCheck: (info->list_)) {
RemoveIndexCheck(indexCheck);
}
}
}
// index only constant
if (listConstant.size() > 1) {
GateRef firIndexCheckGate = listConstant.front();
Environment env(firIndexCheckGate, circuit_, &builder_);
GateRef length = acc_.GetValueIn(firIndexCheckGate, 0);
ASSERT(length != Circuit::NullGate());
ASSERT(maxConstant >= 0);
PredicateCmpWithConst(length, TypedBinOp::TYPED_GREATER, maxConstant); // length > index
for (size_t j = 0; j < listConstant.size(); j++) {
GateRef indexCheck = listConstant[j];
RemoveIndexCheck(indexCheck);
}
}
for (size_t j = 0; j < indices.size(); j++) {
indexCheckInfo_[acc_.GetId(indices[j])] = nullptr;
}
indices.clear();
}
}
void ArrayBoundsCheckElimination::CalcBounds(GateRegion *block, GateRegion *loopHeader)
{
// Pushed stack for condition
IntegerStack pushed(chunk_);
@ -428,13 +889,13 @@ void ArrayBoundsCheckElimination::CalcBounds(GateRegion *block)
if (parent != nullptr) {
auto gate = block->GetGates().front();
auto op = acc_.GetOpCode(gate);
if (op == OpCode::IF_TRUE || op == OpCode::IF_FALSE) { // Recognize If
if (op == OpCode::IF_TRUE || op == OpCode::IF_FALSE) { // Recognize If (including the condition in forloop)
ProcessIf(pushed, parent, op);
}
}
GateLists IndexChecked(chunk_);
GateLists Arrays(chunk_);
GateLists indexChecked(chunk_);
GateLists arrays(chunk_);
auto& gateList_ = block->GetGates();
for (size_t i = 0; i < gateList_.size(); i++) { // Visit GateUnion
@ -445,11 +906,11 @@ void ArrayBoundsCheckElimination::CalcBounds(GateRegion *block)
auto index = acc_.GetValueIn(gate, 1);
auto array = acc_.GetValueIn(length, 0);
ProcessIndexCheck(gate);
IndexChecked.push_back(gate);
ProcessIndexCheck(loopHeader, gate);
indexChecked.push_back(gate);
if (!Contain(Arrays, array)) {
Arrays.push_back(array);
if (!Contain(arrays, array)) {
arrays.push_back(array);
}
// Give IndexCheck a bound [0, Length - 1]
@ -462,11 +923,18 @@ void ArrayBoundsCheckElimination::CalcBounds(GateRegion *block)
}
}
}
InBlockMotion(indexChecked, arrays);
auto& dominatedRegions_ = block->GetDominatedRegions();
for (size_t i = 0; i < dominatedRegions_.size(); i++) {
GateRegion *nex = dominatedRegions_[i];
CalcBounds(nex);
if (block->IsLoopHead() && (block->GetInnerLoopIndex() == nex->GetInnerLoopIndex()
|| nex->GetLoopDepth() > block->GetLoopDepth())) {
CalcBounds(nex, block);
} else {
CalcBounds(nex, loopHeader);
}
}
for (size_t i = 0; i < pushed.size(); i++) {

View File

@ -12,6 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_COMPILER_ARRAY_BOUNDS_CHECK_ELIMINATION_H
#define ECMASCRIPT_COMPILER_ARRAY_BOUNDS_CHECK_ELIMINATION_H
@ -26,8 +27,8 @@ namespace panda::ecmascript::kungfu {
class ArrayBoundsCheckElimination {
public:
ArrayBoundsCheckElimination(Circuit *circuit, bool enableLog, const std::string& name, Chunk* chunk)
: acc_(circuit), bounds_(chunk), circuit_(circuit), chunk_(chunk), enableLog_(enableLog),
graphLinearizer_(circuit, enableLog, name, chunk, true), methodName_(name) {}
: acc_(circuit), bounds_(chunk), circuit_(circuit), builder_(circuit), chunk_(chunk), enableLog_(enableLog),
graphLinearizer_(circuit, enableLog, name, chunk, true), methodName_(name), indexCheckInfo_(chunk) {}
~ArrayBoundsCheckElimination() = default;
void Run();
@ -64,6 +65,16 @@ private:
{
return lowerGate_ != Circuit::NullGate() || lower_ > INT_MIN;
}
void RemoveUpper()
{
upperGate_ = Circuit::NullGate();
upper_ = INT_MAX;
}
void RemoveLower()
{
lowerGate_ = Circuit::NullGate();
lower_ = INT_MIN;
}
bool IsSmaller(Bound *b)
{
if (b->LowerGate() != upperGate_) {
@ -71,6 +82,10 @@ private:
}
return upper_ < b->Lower();
}
Bound* Copy()
{
return new Bound(lower_, lowerGate_, upper_, upperGate_);
}
private:
int upper_;
@ -93,33 +108,62 @@ private:
typedef ChunkVector<Bound*> BoundStack;
typedef ChunkVector<BoundStack*> BoundMap;
typedef ChunkVector<GateRef> IndexCheckList;
typedef ChunkVector<GateRef> GateLists;
typedef ChunkVector<int> IntegerStack;
typedef ChunkVector<GateRef> GateLists;
void AddAccessIndexedInfo(GateLists &indices, GateRef gate, int idx, GateRef indexCheck);
void AddIfCondition(IntegerStack &pushed, GateRef x, GateRef y, TypedBinOp op);
Bound *AndOp(Bound *bound, Bound *b);
bool Contain(ChunkVector<GateRef>& gateLists, GateRef gate);
void CalcBounds(GateRegion *block);
Bound *OrOp(Bound *bound, Bound *b);
bool Contain(GateLists& gateLists, GateRef gate);
void CalcBounds(GateRegion *block, GateRegion *loopHeader);
bool CheckLoop(GateRef array, GateRef lowerGate, int lower, GateRef upperGate, int upper);
void InBlockMotion(GateLists &indexChecked, GateLists &arrays);
bool InLoop(GateRef loopHeader, GateRef gate);
bool IsArrayLength(GateRef gate);
bool LoopInvariant(GateRegion *loopHeader, GateRef gate);
void UpdateBound(IntegerStack &pushed, GateRef gate, Bound *bound);
void UpdateBound(IntegerStack &pushed, GateRef x, TypedBinOp op, GateRef y, int constValue);
void ProcessIndexCheck(GateRef gate);
void ProcessIndexCheck(GateRegion *loopHeader, GateRef gate);
void RemoveIndexCheck(GateRef gate);
void CopyStateInAndDependIn(GateRef &stateIn, GateRef &dependIn, GateRef insertAfter);
void LoopInvariantMotionForIndexCheck(GateRef array, GateRef length, GateRef lowerGate, int lower,
GateRef upperGate, int upper, bool isTypedArray);
void GetInstrAndConstValueFromOp(GateRef gate, GateRef &instrValue, int& constValue);
Bound *GetBound(GateRef gate);
Bound *DoConstant(GateRef gate);
Bound *DoArithmeticOp(GateRef gate);
Bound *DoPhi(GateRef gate);
void SetBound(GateRef gate, Bound *bound);
void ProcessIf(IntegerStack &pushed, GateRegion *parent, OpCode cond);
bool InArrayBound(Bound *bound, GateRef Length, GateRef Array);
bool InArrayBound(Bound *bound, GateRef length, GateRef array);
Bound *VisitGate(GateRef gate);
void ReplaceIn(GateRef stateIn, GateRef dependIn, GateRef newGate);
GateRef Predicate(GateRef left, TypedBinOp cond, GateRef right);
GateRef PredicateCmpWithConst(GateRef left, TypedBinOp cond, int right);
GateRef PredicateAdd(GateRef left, int leftConst, TypedBinOp cond, GateRef right);
GateRef PredicateAddCmpWithConst(GateRef left, int leftConst, TypedBinOp cond, int right);
GateAccessor acc_;
BoundMap bounds_;
Circuit *circuit_ {nullptr};
CircuitBuilder builder_;
Chunk *chunk_ {nullptr};
bool enableLog_ {false};
GraphLinearizer graphLinearizer_;
std::string methodName_;
class IndexCheckInfo {
public:
IndexCheckInfo(Chunk* chunk): list_(chunk) {}
GateLists list_;
int min_;
int max_;
};
typedef ChunkVector<IndexCheckInfo*> IndexCheckInfoList;
IndexCheckInfoList indexCheckInfo_;
};
}
#endif

View File

@ -2147,4 +2147,108 @@ void CircuitBuilder::ClearConstantCache(GateRef gate)
auto gateType = acc_.GetGateType(gate);
GetCircuit()->ClearConstantCache(machineType, value, gateType);
}
GateRef CircuitBuilder::InsertTypedBinaryop(GateRef left, GateRef right, GateType leftType, GateType rightType,
GateType gateType, PGOSampleType sampleType, TypedBinOp op)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
uint64_t operandTypes = GatePairTypeAccessor::ToValue(leftType, rightType);
auto ret = GetCircuit()->NewGate(circuit_->TypedBinaryOp(operandTypes, op, sampleType),
MachineType::I64,
{currentControl, currentDepend, left, right},
gateType);
acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, GateRef right)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
TypedBinaryAccessor accessor(GateType::IntType(), cond);
auto ret = GetCircuit()->NewGate(circuit_->RangeCheckPredicate(accessor.ToValue()),
MachineType::I32,
{currentControl, currentDepend, left, right, frameState},
GateType::IntType());
acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::InsertStableArrayCheck(GateRef array)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef frameState = acc_.FindNearestFrameState(currentDepend);
ElementsKind kind = acc_.TryGetElementsKind(array);
ArrayMetaDataAccessor::Mode mode = ArrayMetaDataAccessor::Mode::LOAD_LENGTH;
ArrayMetaDataAccessor accessor(kind, mode);
auto ret = GetCircuit()->NewGate(circuit_->StableArrayCheck(accessor.ToValue()),
MachineType::I1,
{currentControl, currentDepend, array, frameState},
GateType::NJSValue());
acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::InsertTypedArrayCheck(GateType type, GateRef array)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef frameState = acc_.FindNearestFrameState(currentDepend);
auto ret = GetCircuit()->NewGate(circuit_->TypedArrayCheck(static_cast<size_t>(type.Value())),
MachineType::I1,
{currentControl, currentDepend, array, frameState},
GateType::NJSValue());
acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::InsertLoadArrayLength(GateRef array, bool isTypedArray)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateType arrayType = acc_.GetGateType(array);
if (isTypedArray) {
InsertTypedArrayCheck(arrayType, array);
currentControl = currentLabel->GetControl();
currentDepend = currentLabel->GetDepend();
auto ret = GetCircuit()->NewGate(circuit_->LoadTypedArrayLength(static_cast<size_t>(arrayType.Value())),
MachineType::I64,
{ currentControl, currentDepend, array },
GateType::IntType());
acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
} else {
InsertStableArrayCheck(array);
currentControl = currentLabel->GetControl();
currentDepend = currentLabel->GetDepend();
auto ret = GetCircuit()->NewGate(circuit_->LoadArrayLength(),
MachineType::I64,
{ currentControl, currentDepend, array },
GateType::IntType());
acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
UNREACHABLE();
return Circuit::NullGate();
}
} // namespace panda::ecmascript::kungfu

View File

@ -318,6 +318,12 @@ public:
GateRef CheckTaggedNumberAndConvertToFloat64(GateRef gate);
GateRef CheckTaggedNumberAndConvertToBool(GateRef gate);
GateRef CheckTaggedBooleanAndConvertToBool(GateRef gate);
GateRef InsertStableArrayCheck(GateRef array);
GateRef InsertLoadArrayLength(GateRef array, bool isTypedArray);
GateRef InsertTypedArrayCheck(GateType type, GateRef array);
GateRef InsertTypedBinaryop(GateRef left, GateRef right, GateType leftType, GateType rightType,
GateType gateType, PGOSampleType sampleType, TypedBinOp op);
GateRef InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, GateRef right);
GateRef TypedConditionJump(MachineType type, TypedJumpOp jumpOp, BranchKind branchKind, GateType typeVal,
const std::vector<GateRef>& inList);
GateRef TypedNewAllocateThis(GateRef ctor, GateRef hclassIndex, GateRef frameState);

View File

@ -156,6 +156,12 @@ TypedUnaryAccessor GateAccessor::GetTypedUnAccessor(GateRef gate) const
return TypedUnaryAccessor(gatePtr->GetOneParameterMetaData()->GetValue());
}
TypedBinaryAccessor GateAccessor::GetTypedBinaryAccessor(GateRef gate) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
return TypedBinaryAccessor(gatePtr->GetOneParameterMetaData()->GetValue());
}
TypedJumpAccessor GateAccessor::GetTypedJumpAccessor(GateRef gate) const
{
ASSERT(GetOpCode(gate) == OpCode::TYPED_CONDITION_JUMP);
@ -1199,6 +1205,96 @@ void GateAccessor::ReplaceGate(GateRef gate, GateRef state, GateRef depend, Gate
DeleteGate(gate);
}
// When Insert newGate, all the stateIn from state and dependIn from depend can be replaced to newGate
void GateAccessor::ReplaceInAfterInsert(GateRef state, GateRef depend, GateRef newGate)
{
auto uses = Uses(state);
for (auto useIt = uses.begin(); useIt != uses.end();) {
if (IsStateIn(useIt) && (*useIt != newGate)) {
ASSERT(newGate != Circuit::NullGate());
// Exception, for example, IF_TRUE / IF_FALSE -> DEPEND_RELAY,
// or LOOP_BEGIN / MERGE -> DEPEND_SELECTOR cannot be replaced
if (!IsState(*useIt)) {
useIt++;
continue;
}
useIt = ReplaceIn(useIt, newGate);
} else {
useIt++;
}
}
uses = Uses(depend);
for (auto useIt = uses.begin(); useIt != uses.end();) {
if (IsDependIn(useIt) && (*useIt != newGate)) {
ASSERT(newGate != Circuit::NullGate());
if (!IsState(*useIt)) {
useIt++;
continue;
}
useIt = ReplaceIn(useIt, newGate);
} else {
useIt++;
}
}
}
// When loopExit, find stateSplit after DEPEND_SELECTOR
void GateAccessor::GetFrameStateDependIn(GateRef gate, GateRef &dependIn)
{
auto uses = Uses(gate);
size_t stateSplitCount = 0;
GateRef stateSplit = Circuit::NullGate();
for (auto it = uses.begin(); it != uses.end();) {
if (GetOpCode(*it) == OpCode::STATE_SPLIT) {
ASSERT(stateSplitCount < 1); // only one state Split;
stateSplitCount++;
stateSplit = *it;
break;
} else {
++it;
}
}
ASSERT(stateSplitCount <= 1);
if (stateSplitCount == 1 && stateSplit != Circuit::NullGate()) {
dependIn = stateSplit;
}
}
// When ifOp or loopExit, insertAfter
// stateIn: IF_TRUE / IF_FALSE / MERGE
// dependIn: DEPEND_RELAY / DEPEND_SELECTOR, if stateSplit follow closely, after the stateSplit.
void GateAccessor::GetStateInAndDependIn(GateRef insertAfter, GateRef &stateIn, GateRef &dependIn)
{
if (GetOpCode(insertAfter) == OpCode::IF_TRUE || GetOpCode(insertAfter) == OpCode::IF_FALSE) {
auto uses = Uses(insertAfter);
for (auto it = uses.begin(); it != uses.end();) {
if (GetOpCode(*it) == OpCode::DEPEND_RELAY) {
stateIn = insertAfter;
dependIn = (*it);
break;
} else {
++it;
}
}
} else if (GetOpCode(insertAfter) == OpCode::MERGE) {
auto uses = Uses(insertAfter);
for (auto it = uses.begin(); it != uses.end();) {
if (GetOpCode(*it) == OpCode::DEPEND_SELECTOR) {
stateIn = insertAfter;
dependIn = (*it);
GetFrameStateDependIn(*it, dependIn);
break;
} else {
++it;
}
}
}
ASSERT(GetDependCount(dependIn) > 0);
}
GateRef GateAccessor::GetFrameState(GateRef gate) const
{
ASSERT(HasFrameState(gate));

View File

@ -399,6 +399,7 @@ public:
GlobalTSTypeRef GetFuncGT(GateRef gate) const;
GateType GetParamGateType(GateRef gate) const;
TypedUnaryAccessor GetTypedUnAccessor(GateRef gate) const;
TypedBinaryAccessor GetTypedBinaryAccessor(GateRef gate) const;
TypedJumpAccessor GetTypedJumpAccessor(GateRef gate) const;
ArrayMetaDataAccessor GetArrayMetaDataAccessor(GateRef gate) const;
ObjectTypeAccessor GetObjectTypeAccessor(GateRef gate) const;
@ -442,6 +443,9 @@ public:
size_t GetInValueCount(GateRef gate) const;
size_t GetInValueStarts(GateRef gate) const;
void UpdateAllUses(GateRef gate, GateRef replaceValueIn);
void ReplaceInAfterInsert(GateRef state, GateRef depend, GateRef newGate);
void GetFrameStateDependIn(GateRef gate, GateRef &dependIn);
void GetStateInAndDependIn(GateRef insertAfter, GateRef &stateIn, GateRef &dependIn);
void ReplaceIn(GateRef gate, size_t index, GateRef in);
void ReplaceStateIn(GateRef gate, GateRef in, size_t index = 0);
void ReplaceDependIn(GateRef gate, GateRef in, size_t index = 0);

View File

@ -396,7 +396,8 @@ std::string MachineTypeToStr(MachineType machineType);
V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(ObjectTypeCheck, OBJECT_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2)
V(ObjectTypeCompare, OBJECT_TYPE_COMPARE, GateFlags::CHECKABLE, 1, 1, 2) \
V(RangeCheckPredicate, RANGE_CHECK_PREDICATE, GateFlags::CHECKABLE, 1, 1, 2)
#define GATE_META_DATA_LIST_WITH_ONE_PARAMETER(V) \
V(Arg, ARG, GateFlags::HAS_ROOT, 0, 0, 0) \
@ -1017,6 +1018,38 @@ private:
uint64_t bitField_;
};
class TypedBinaryAccessor {
public:
// type bits shift
static constexpr int OPRAND_TYPE_BITS = 32;
explicit TypedBinaryAccessor(uint64_t value) : bitField_(value) {}
explicit TypedBinaryAccessor(GateType gate, TypedBinOp binOp)
{
bitField_ = TypedValueBits::Encode(gate.Value()) | TypedBinOpBits::Encode(binOp);
}
GateType GetTypeValue() const
{
return GateType(TypedValueBits::Get(bitField_));
}
TypedBinOp GetTypedBinOp() const
{
return TypedBinOpBits::Get(bitField_);
}
uint64_t ToValue() const
{
return bitField_;
}
private:
using TypedValueBits = panda::BitField<uint32_t, 0, OPRAND_TYPE_BITS>;
using TypedBinOpBits = TypedValueBits::NextField<TypedBinOp, OPRAND_TYPE_BITS>;
uint64_t bitField_;
};
class TypedJumpAccessor {
public:
// type bits shift

View File

@ -340,6 +340,7 @@ public:
ComputeLoopInfo();
ComputeLoopExit();
ComputeLoopHeader();
ComputeLoopDepth();
if (linearizer_->IsLogEnabled()) {
for (size_t i = 0; i < numLoops_; i++) {
auto& loopInfo = loops_[i];
@ -521,6 +522,25 @@ public:
}
}
void ComputeLoopDepth()
{
auto size = linearizer_->regionList_.size();
for (size_t cur = 0; cur < size; cur++) {
GateRegion* region = linearizer_->regionList_[cur];
int loopDepth = 0;
int innerLoopIndex = -1;
for (int i = numLoops_ - 1; i >= 0; i--) {
auto& loopInfo = loops_[i];
if (loopInfo.loopBodys->TestBit(cur)) {
loopDepth++;
innerLoopIndex = i;
}
}
region->SetLoopDepth(loopDepth);
region->SetInnerLoopIndex(innerLoopIndex);
}
}
bool CheckRegionDomLoopExist(GateRegion* region, LoopInfo& loopInfo)
{
if (loopInfo.loopExits == nullptr) {
@ -808,12 +828,12 @@ void GraphLinearizer::LinearizeGraph()
builder.Run();
ImmediateDominatorsGenerator generator(this, chunk_, regionList_.size());
generator.Run();
if (!IsSchedueLIR() && loopNumber_ > 0) {
scheduleUpperBound_ = true;
LoopInfoBuilder loopInfoBuilder(this, chunk_);
loopInfoBuilder.Run();
}
if (!onlyBB_) {
if (!IsSchedueLIR() && loopNumber_ > 0) {
scheduleUpperBound_ = true;
LoopInfoBuilder loopInfoBuilder(this, chunk_);
loopInfoBuilder.Run();
}
GateScheduler scheduler(this);
scheduler.Prepare();
scheduler.ScheduleUpperBound();

View File

@ -195,6 +195,26 @@ public:
return depth_;
}
void SetLoopDepth(size_t loopDepth)
{
loopDepth_ = loopDepth;
}
size_t GetLoopDepth()
{
return loopDepth_;
}
void SetInnerLoopIndex(size_t innerLoopIndex)
{
innerLoopIndex_ = innerLoopIndex;
}
int GetInnerLoopIndex()
{
return innerLoopIndex_;
}
private:
enum StateKind {
BRANCH,
@ -205,6 +225,8 @@ private:
};
static constexpr int32_t INVALID_DEPTH = -1;
size_t id_ {0};
size_t loopDepth_ {0}; // the loop nesting level of this block
int innerLoopIndex_ {-1}; // number of the innermost loop of this block
int32_t depth_ {INVALID_DEPTH};
GateRegion* iDominator_ {nullptr};
GateRegion* loopHead_ {nullptr};

View File

@ -84,6 +84,10 @@ void NumberSpeculativeLowering::VisitGate(GateRef gate)
VisitIndexCheck(gate);
break;
}
case OpCode::RANGE_CHECK_PREDICATE: {
VisitRangeCheckPredicate(gate);
break;
}
case OpCode::LOAD_ARRAY_LENGTH:
case OpCode::LOAD_TYPED_ARRAY_LENGTH: {
VisitLoadArrayLength(gate);
@ -523,6 +527,12 @@ void NumberSpeculativeLowering::VisitPhi(GateRef gate)
}
}
void NumberSpeculativeLowering::VisitRangeCheckPredicate(GateRef gate)
{
acc_.SetGateType(gate, GateType::NJSValue());
acc_.SetMachineType(gate, MachineType::I32);
}
void NumberSpeculativeLowering::VisitIndexCheck(GateRef gate)
{
acc_.SetGateType(gate, GateType::NJSValue());

View File

@ -45,6 +45,7 @@ private:
void VisitUndefinedStrictEq(GateRef gate);
void VisitCallBuiltins(GateRef gate);
void VisitRangeGuard(GateRef gate);
void VisitRangeCheckPredicate(GateRef gate);
void VisitIndexCheck(GateRef gate);
void VisitLoadArrayLength(GateRef gate);
void VisitLoadStringLength(GateRef gate);

View File

@ -87,6 +87,8 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate)
return VisitTypedUnaryOp(gate);
case OpCode::TYPED_CONDITION_JUMP:
return VisitTypedConditionJump(gate);
case OpCode::RANGE_CHECK_PREDICATE:
return VisitRangeCheckPredicate(gate);
case OpCode::INDEX_CHECK:
return VisitIndexCheck(gate);
case OpCode::LOAD_ARRAY_LENGTH:
@ -895,6 +897,28 @@ GateRef NumberSpeculativeRetype::ConvertToTagged(GateRef gate)
}
}
GateRef NumberSpeculativeRetype::VisitRangeCheckPredicate(GateRef gate)
{
if (IsRetype()) {
return SetOutputType(gate, GateType::IntType());
}
if (IsConvert()) {
Environment env(gate, circuit_, &builder_);
GateRef value0 = acc_.GetValueIn(gate, 0);
GateRef value1 = acc_.GetValueIn(gate, 1);
GateType value0Type = acc_.GetGateType(value0);
GateType value1Type = acc_.GetGateType(value1);
acc_.ReplaceValueIn(gate, CheckAndConvertToInt32(value0, value0Type), 0);
acc_.ReplaceValueIn(gate, CheckAndConvertToInt32(value1, value1Type), 1);
acc_.ReplaceStateIn(gate, builder_.GetState());
acc_.ReplaceDependIn(gate, builder_.GetDepend());
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitIndexCheck(GateRef gate)
{
if (IsRetype()) {

View File

@ -78,6 +78,7 @@ private:
GateRef VisitNumberShiftAndLogical(GateRef gate);
GateRef VisitNumberMod(GateRef gate);
GateRef VisitBooleanJump(GateRef gate);
GateRef VisitRangeCheckPredicate(GateRef gate);
GateRef VisitIndexCheck(GateRef gate);
GateRef VisitLoadArrayLength(GateRef gate);
GateRef VisitLoadStringLength(GateRef gate);

View File

@ -57,6 +57,9 @@ GateRef TypeMCRLowering::VisitGate(GateRef gate)
case OpCode::OBJECT_TYPE_COMPARE:
LowerObjectTypeCompare(gate);
break;
case OpCode::RANGE_CHECK_PREDICATE:
LowerRangeCheckPredicate(gate);
break;
case OpCode::INDEX_CHECK:
LowerIndexCheck(gate);
break;
@ -492,6 +495,38 @@ GateRef TypeMCRLowering::BuildCompareHClass(GateRef gate, GateRef frameState)
return builder_.Equal(aotHCGate, receiverHClass);
}
void TypeMCRLowering::LowerRangeCheckPredicate(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
auto deoptType = DeoptType::NOTARRAY;
GateRef frameState = GetFrameState(gate);
GateRef x = acc_.GetValueIn(gate, 0);
GateRef y = acc_.GetValueIn(gate, 1);
TypedBinaryAccessor accessor = acc_.GetTypedBinaryAccessor(gate);
TypedBinOp cond = accessor.GetTypedBinOp();
GateRef check = Circuit::NullGate();
// check the condition
switch (cond) {
case TypedBinOp::TYPED_GREATER:
check = builder_.Int32GreaterThan(x, y);
break;
case TypedBinOp::TYPED_GREATEREQ:
check = builder_.Int32GreaterThanOrEqual(x, y);
break;
case TypedBinOp::TYPED_LESS:
check = builder_.Int32LessThan(x, y);
break;
case TypedBinOp::TYPED_LESSEQ:
check = builder_.Int32LessThanOrEqual(x, y);
break;
default:
UNREACHABLE();
break;
}
builder_.DeoptCheck(check, frameState, deoptType);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeMCRLowering::LowerIndexCheck(GateRef gate)
{
Environment env(gate, circuit_, &builder_);

View File

@ -146,6 +146,7 @@ private:
void LowerLoadElement(GateRef gate);
void LowerLoadFromTaggedArray(GateRef gate);
void LowerStoreToTaggedArray(GateRef gate, GateRef glue);
void LowerRangeCheckPredicate(GateRef gate);
enum class ArrayState : uint8_t {
PACKED = 0,

View File

@ -0,0 +1,18 @@
# 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("array_bounds_check_elimination") {
deps = []
}

View File

@ -0,0 +1,70 @@
/*
* 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.
*/
function get(a: number[], p: number): number {
if (p <= a.length && p > 0) {
return a[p - 1];
}
return 0;
}
function get2(a: number[], p: number): number {
if (p <= a.length - 1 && p >= 0) {
return a[p];
}
return 0;
}
function clear1(a: number[], x: number) {
for (let i = 0; i < x; i++) {
a[i] = 0;
}
}
function clear2(b: Int32Array[], x: number) {
for (let i = 0; i < x; i++) {
b[i] = 0;
}
}
function triple(a: number[], i: number) {
a[i + 3] = 0;
a[i + 1] = 0;
a[i + 2] = 0;
}
function triple2(a: number[]) {
a[0] = 0;
a[1] = 0;
a[2] = 0;
}
let a: number[] = [1, 2, 3];
let b: Int32Array[] = [1, 2, 3];
let x = 3;
print(get(a, x));
print(get2(a, x));
clear1(a, 3);
clear2(b, 3);
clear1(a, 4);
clear2(b, 4);
let c: number[] = [1, 2, 3, 4];
triple(c, 0);
triple2(a);
print(a[2]);
print(c[2]);

View File

@ -0,0 +1,17 @@
# 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.
3
0
0
0

View File

@ -1,18 +0,0 @@
function get(a: number[], p: number) {
if(p <= a.length && p > 0) {
return a[p - 1];
}
return 0;
}
function get2(a: number[], p: number) {
if(p <= a.length - 1 && p >= 0) {
return a[p];
}
return 0;
}
let a: number[] = [1, 2, 3];
let b = 2;
get(a, b);
get2(a, b);