IntBounds.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. class Value;
  7. class IntConstantBounds;
  8. typedef JsUtil::BaseHashSet<ValueRelativeOffset, JitArenaAllocator, PowerOf2SizePolicy, ValueNumber> RelativeIntBoundSet;
  9. #pragma region IntBounds
  10. class IntBounds sealed
  11. {
  12. private:
  13. int constantLowerBound, constantUpperBound;
  14. bool wasConstantUpperBoundEstablishedExplicitly;
  15. RelativeIntBoundSet relativeLowerBounds, relativeUpperBounds;
  16. protected:
  17. IntBounds(const IntConstantBounds &constantBounds, const bool wasConstantUpperBoundEstablishedExplicitly, JitArenaAllocator *const allocator);
  18. public:
  19. static IntBounds *New(const IntConstantBounds &constantBounds, const bool wasConstantUpperBoundEstablishedExplicitly, JitArenaAllocator *const allocator);
  20. IntBounds *Clone() const;
  21. void Delete() const;
  22. public:
  23. void Verify() const;
  24. private:
  25. bool HasBounds() const;
  26. public:
  27. bool RequiresIntBoundedValueInfo(const ValueType valueType) const;
  28. bool RequiresIntBoundedValueInfo() const;
  29. public:
  30. int ConstantLowerBound() const;
  31. int ConstantUpperBound() const;
  32. IntConstantBounds ConstantBounds() const;
  33. bool WasConstantUpperBoundEstablishedExplicitly() const;
  34. public:
  35. const RelativeIntBoundSet &RelativeLowerBounds() const;
  36. const RelativeIntBoundSet &RelativeUpperBounds() const;
  37. public:
  38. void SetLowerBound(const int constantBound);
  39. void SetLowerBound(const int constantBoundBase, const int offset);
  40. void SetUpperBound(const int constantBound, const bool wasEstablishedExplicitly);
  41. void SetUpperBound(const int constantBoundBase, const int offset, const bool wasEstablishedExplicitly);
  42. private:
  43. template<bool Lower> void SetBound(const int constantBoundBase, const int offset, const bool wasEstablishedExplicitly);
  44. public:
  45. void SetLowerBound(const ValueNumber myValueNumber, const Value *const baseValue, const bool wasEstablishedExplicitly);
  46. void SetLowerBound(const ValueNumber myValueNumber, const Value *const baseValue, const int offset, const bool wasEstablishedExplicitly);
  47. void SetUpperBound(const ValueNumber myValueNumber, const Value *const baseValue, const bool wasEstablishedExplicitly);
  48. void SetUpperBound(const ValueNumber myValueNumber, const Value *const baseValue, const int offset, const bool wasEstablishedExplicitly);
  49. private:
  50. template<bool Lower> void SetBound(const ValueNumber myValueNumber, const Value *const baseValue, const int offset, const bool wasEstablishedExplicitly);
  51. public:
  52. bool SetIsNot(const int constantValue, const bool isExplicit);
  53. bool SetIsNot(const Value *const value, const bool isExplicit);
  54. public:
  55. static bool IsGreaterThanOrEqualTo(const int constantValue, const int constantBoundBase, const int offset);
  56. static bool IsLessThanOrEqualTo(const int constantValue, const int constantBoundBase, const int offset);
  57. public:
  58. bool IsGreaterThanOrEqualTo(const int constantBoundBase, const int offset = 0) const;
  59. bool IsLessThanOrEqualTo(const int constantBoundBase, const int offset = 0) const;
  60. public:
  61. bool IsGreaterThanOrEqualTo(const Value *const value, const int offset = 0) const;
  62. bool IsLessThanOrEqualTo(const Value *const value, const int offset = 0) const;
  63. public:
  64. static const IntBounds *Add(const Value *const baseValue, const int n, const bool baseValueInfoIsPrecise, const IntConstantBounds &newConstantBounds, JitArenaAllocator *const allocator);
  65. public:
  66. bool AddCannotOverflowBasedOnRelativeBounds(const int n) const;
  67. bool SubCannotOverflowBasedOnRelativeBounds(const int n) const;
  68. public:
  69. static const IntBounds *Merge(const Value *const bounds0Value, const IntBounds *const bounds0, const Value *const bounds1Value, const IntConstantBounds &constantBounds1);
  70. static const IntBounds *Merge(const Value *const bounds0Value, const IntBounds *const bounds0, const Value *const bounds1Value, const IntBounds *const bounds1);
  71. private:
  72. 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);
  73. PREVENT_ASSIGN(IntBounds);
  74. };
  75. #pragma endregion
  76. #pragma region IntBoundCheckCompatibilityId and IntBoundCheck
  77. // A bounds check takes the form (a <= b + offset). For instance, (i >= 0) would be represented as (0 <= i + 0), and (i < n)
  78. // would be represented as (i <= n - 1). When a bounds check is required, from the two value numbers, it can be determined
  79. // whether an existing, compatible bounds check can be updated by decreasing the offset aggressively instead of adding a new
  80. // bounds check. The offset may only be decreased such that it does not invalidate the invariant previously established by the
  81. // check.
  82. //
  83. // For instance, given that we have the bound checks (0 <= i + 0) and (i <= n - 1), suppose the bounds checks (i + 1 >= 0) and
  84. // (i + 1 < n) are required. (i + 1 >= 0) would be represented as (0 <= i + 1). Given that (0 <= i + 0), it is already
  85. // guaranteed that (0 <= i + 1), so no change is necessary for that part. (i + 1 < n) would be represented as (i <= n + 0). The
  86. // compatible bounds check (i <= n - 1) would be found and updated aggressively to (i <= n + 0).
  87. class IntBoundCheckCompatibilityId
  88. {
  89. private:
  90. const ValueNumber leftValueNumber, rightValueNumber;
  91. public:
  92. IntBoundCheckCompatibilityId(const ValueNumber leftValueNumber, const ValueNumber rightValueNumber);
  93. public:
  94. bool operator ==(const IntBoundCheckCompatibilityId &other) const;
  95. operator hash_t() const;
  96. };
  97. class IntBoundCheck
  98. {
  99. private:
  100. ValueNumber leftValueNumber, rightValueNumber;
  101. IR::Instr *instr;
  102. BasicBlock *block;
  103. public:
  104. IntBoundCheck();
  105. IntBoundCheck(const ValueNumber leftValueNumber, const ValueNumber rightValueNumber, IR::Instr *const instr, BasicBlock *const block);
  106. #if DBG
  107. public:
  108. bool IsValid() const;
  109. #endif
  110. public:
  111. ValueNumber LeftValueNumber() const;
  112. ValueNumber RightValueNumber() const;
  113. IR::Instr *Instr() const;
  114. BasicBlock *Block() const;
  115. IntBoundCheckCompatibilityId CompatibilityId() const;
  116. public:
  117. bool SetBoundOffset(const int offset, const bool isLoopCountBasedBound = false) const;
  118. };
  119. template<>
  120. inline IntBoundCheckCompatibilityId JsUtil::ValueToKey<IntBoundCheckCompatibilityId, IntBoundCheck>::ToKey(
  121. const IntBoundCheck &intBoundCheck)
  122. {
  123. return intBoundCheck.CompatibilityId();
  124. }
  125. typedef JsUtil::BaseHashSet<IntBoundCheck, JitArenaAllocator, PowerOf2SizePolicy, IntBoundCheckCompatibilityId> IntBoundCheckSet;
  126. #pragma endregion