//------------------------------------------------------------------------------------------------------- // 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 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 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 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 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::ToKey( const IntBoundCheck &intBoundCheck) { return intBoundCheck.CompatibilityId(); } typedef JsUtil::BaseHashSet IntBoundCheckSet; #pragma endregion