blob: 2fd002726aea10e827fbb0a558da1682dd9011da [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
class Value;
class IntConstantBounds;
typedef JsUtil::BaseHashSet<ValueRelativeOffset, JitArenaAllocator, PowerOf2SizePolicy, ValueNumber> RelativeIntBoundSet;
#pragma region IntBounds
class IntBounds sealed
{
private:
int constantLowerBound, constantUpperBound;
bool wasConstantUpperBoundEstablishedExplicitly;
RelativeIntBoundSet relativeLowerBounds, relativeUpperBounds;
protected:
IntBounds(const IntConstantBounds &constantBounds, const bool wasConstantUpperBoundEstablishedExplicitly, JitArenaAllocator *const allocator);
public:
static IntBounds *New(const IntConstantBounds &constantBounds, const bool wasConstantUpperBoundEstablishedExplicitly, JitArenaAllocator *const allocator);
IntBounds *Clone() const;
void Delete() const;
public:
void Verify() const;
private:
bool HasBounds() const;
public:
bool RequiresIntBoundedValueInfo(const ValueType valueType) const;
bool RequiresIntBoundedValueInfo() const;
public:
int ConstantLowerBound() const;
int ConstantUpperBound() const;
IntConstantBounds ConstantBounds() const;
bool WasConstantUpperBoundEstablishedExplicitly() const;
public:
const RelativeIntBoundSet &RelativeLowerBounds() const;
const RelativeIntBoundSet &RelativeUpperBounds() const;
public:
void SetLowerBound(const int constantBound);
void SetLowerBound(const int constantBoundBase, const int offset);
void SetUpperBound(const int constantBound, const bool wasEstablishedExplicitly);
void SetUpperBound(const int constantBoundBase, const int offset, const bool wasEstablishedExplicitly);
private:
template<bool Lower> void SetBound(const int constantBoundBase, const int offset, const bool wasEstablishedExplicitly);
public:
void SetLowerBound(const ValueNumber myValueNumber, const Value *const baseValue, const bool wasEstablishedExplicitly);
void SetLowerBound(const ValueNumber myValueNumber, const Value *const baseValue, const int offset, const bool wasEstablishedExplicitly);
void SetUpperBound(const ValueNumber myValueNumber, const Value *const baseValue, const bool wasEstablishedExplicitly);
void SetUpperBound(const ValueNumber myValueNumber, const Value *const baseValue, const int offset, const bool wasEstablishedExplicitly);
private:
template<bool Lower> void SetBound(const ValueNumber myValueNumber, const Value *const baseValue, const int offset, const bool wasEstablishedExplicitly);
public:
bool SetIsNot(const int constantValue, const bool isExplicit);
bool SetIsNot(const Value *const value, const bool isExplicit);
public:
static bool IsGreaterThanOrEqualTo(const int constantValue, const int constantBoundBase, const int offset);
static bool IsLessThanOrEqualTo(const int constantValue, const int constantBoundBase, const int offset);
public:
bool IsGreaterThanOrEqualTo(const int constantBoundBase, const int offset = 0) const;
bool IsLessThanOrEqualTo(const int constantBoundBase, const int offset = 0) const;
public:
bool IsGreaterThanOrEqualTo(const Value *const value, const int offset = 0) const;
bool IsLessThanOrEqualTo(const Value *const value, const int offset = 0) const;
public:
static const IntBounds *Add(const Value *const baseValue, const int n, const bool baseValueInfoIsPrecise, const IntConstantBounds &newConstantBounds, JitArenaAllocator *const allocator);
public:
bool AddCannotOverflowBasedOnRelativeBounds(const int n) const;
bool SubCannotOverflowBasedOnRelativeBounds(const int n) const;
public:
static const IntBounds *Merge(const Value *const bounds0Value, const IntBounds *const bounds0, const Value *const bounds1Value, const IntConstantBounds &constantBounds1);
static const IntBounds *Merge(const Value *const bounds0Value, const IntBounds *const bounds0, const Value *const bounds1Value, const IntBounds *const bounds1);
private:
template<bool Lower> static void MergeBoundSets(const Value *const bounds0Value, const IntBounds *const bounds0, const Value *const bounds1Value, const IntBounds *const bounds1, IntBounds *const mergedBounds);
PREVENT_ASSIGN(IntBounds);
};
#pragma endregion
#pragma region IntBoundCheckCompatibilityId and IntBoundCheck
// A bounds check takes the form (a <= b + offset). For instance, (i >= 0) would be represented as (0 <= i + 0), and (i < n)
// would be represented as (i <= n - 1). When a bounds check is required, from the two value numbers, it can be determined
// whether an existing, compatible bounds check can be updated by decreasing the offset aggressively instead of adding a new
// bounds check. The offset may only be decreased such that it does not invalidate the invariant previously established by the
// check.
//
// For instance, given that we have the bound checks (0 <= i + 0) and (i <= n - 1), suppose the bounds checks (i + 1 >= 0) and
// (i + 1 < n) are required. (i + 1 >= 0) would be represented as (0 <= i + 1). Given that (0 <= i + 0), it is already
// guaranteed that (0 <= i + 1), so no change is necessary for that part. (i + 1 < n) would be represented as (i <= n + 0). The
// compatible bounds check (i <= n - 1) would be found and updated aggressively to (i <= n + 0).
class IntBoundCheckCompatibilityId
{
private:
const ValueNumber leftValueNumber, rightValueNumber;
public:
IntBoundCheckCompatibilityId(const ValueNumber leftValueNumber, const ValueNumber rightValueNumber);
public:
bool operator ==(const IntBoundCheckCompatibilityId &other) const;
operator hash_t() const;
};
class IntBoundCheck
{
private:
ValueNumber leftValueNumber, rightValueNumber;
IR::Instr *instr;
BasicBlock *block;
public:
IntBoundCheck();
IntBoundCheck(const ValueNumber leftValueNumber, const ValueNumber rightValueNumber, IR::Instr *const instr, BasicBlock *const block);
#if DBG
public:
bool IsValid() const;
#endif
public:
ValueNumber LeftValueNumber() const;
ValueNumber RightValueNumber() const;
IR::Instr *Instr() const;
BasicBlock *Block() const;
IntBoundCheckCompatibilityId CompatibilityId() const;
public:
bool SetBoundOffset(const int offset, const bool isLoopCountBasedBound = false) const;
};
template<>
inline IntBoundCheckCompatibilityId JsUtil::ValueToKey<IntBoundCheckCompatibilityId, IntBoundCheck>::ToKey(
const IntBoundCheck &intBoundCheck)
{
return intBoundCheck.CompatibilityId();
}
typedef JsUtil::BaseHashSet<IntBoundCheck, JitArenaAllocator, PowerOf2SizePolicy, IntBoundCheckCompatibilityId> IntBoundCheckSet;
#pragma endregion