GlobOptIntBounds.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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 IntBoundedValueInfo : public ValueInfo
  7. {
  8. private:
  9. const IntBounds *const bounds;
  10. // Definitely-int values are inherently not negative zero. This member variable, if true, indicates that this value was
  11. // produced by an int-specialized instruction that prevented a negative zero result using a negative zero bailout
  12. // (BailOutOnNegativeZero). Negative zero tracking in the dead-store phase tracks this information to see if some of these
  13. // negative zero bailout checks can be removed.
  14. bool wasNegativeZeroPreventedByBailout;
  15. protected:
  16. IntBoundedValueInfo(const ValueType type, const IntBounds *const bounds, const bool wasNegativeZeroPreventedByBailout)
  17. :
  18. ValueInfo(
  19. type.IsInt()
  20. ? bounds->ConstantBounds().GetValueType()
  21. : bounds->ConstantBounds().IsLikelyTaggable() ? type : type.ToLikelyUntaggedInt(),
  22. ValueStructureKind::IntBounded),
  23. bounds(bounds),
  24. wasNegativeZeroPreventedByBailout(wasNegativeZeroPreventedByBailout)
  25. {
  26. Assert(type.IsLikelyInt());
  27. Assert(Type().IsLikelyInt());
  28. Assert(Type().IsInt() == type.IsInt());
  29. bounds->Verify();
  30. // Bounds for definitely int values should have relative bounds, otherwise those values should use one of the other
  31. // value infos
  32. Assert(bounds->RequiresIntBoundedValueInfo(Type()));
  33. Assert(!wasNegativeZeroPreventedByBailout || type.IsInt());
  34. Assert(!wasNegativeZeroPreventedByBailout || bounds->ConstantLowerBound() <= 0);
  35. Assert(!wasNegativeZeroPreventedByBailout || bounds->ConstantUpperBound() >= 0);
  36. }
  37. public:
  38. static IntBoundedValueInfo *New(
  39. const ValueType type,
  40. const IntBounds *const bounds,
  41. const bool wasNegativeZeroPreventedByBailout,
  42. JitArenaAllocator *const allocator)
  43. {
  44. Assert(allocator);
  45. return JitAnew(allocator, IntBoundedValueInfo, type, bounds, wasNegativeZeroPreventedByBailout);
  46. }
  47. IntBoundedValueInfo *Copy(JitArenaAllocator *const allocator) const
  48. {
  49. Assert(allocator);
  50. return JitAnew(allocator, IntBoundedValueInfo, *this);
  51. }
  52. public:
  53. const IntBounds *Bounds() const
  54. {
  55. return bounds;
  56. }
  57. bool WasNegativeZeroPreventedByBailout() const
  58. {
  59. return wasNegativeZeroPreventedByBailout;
  60. }
  61. };
  62. class LoopCount
  63. {
  64. private:
  65. bool hasBeenGenerated;
  66. // Information needed to generate the loop count instructions
  67. // loopCountMinusOne = (left - right + offset) / minMagnitudeChange
  68. StackSym *leftSym, *rightSym;
  69. int offset, minMagnitudeChange;
  70. // Information needed to use the computed loop count
  71. StackSym *loopCountMinusOneSym;
  72. StackSym *loopCountSym; // Not generated by default and depends on loopCountMinusOneSym
  73. int loopCountMinusOneConstantValue;
  74. public:
  75. LoopCount(StackSym *const leftSym, StackSym *const rightSym, const int offset, const int minMagnitudeChange)
  76. : leftSym(leftSym), rightSym(rightSym), offset(offset), minMagnitudeChange(minMagnitudeChange), hasBeenGenerated(false), loopCountSym(nullptr)
  77. {
  78. Assert(leftSym || rightSym);
  79. Assert(!leftSym || leftSym->GetType() == TyInt32 || leftSym->GetType() == TyUint32);
  80. Assert(!rightSym || rightSym->GetType() == TyInt32 || rightSym->GetType() == TyUint32);
  81. Assert(minMagnitudeChange > 0);
  82. }
  83. LoopCount(StackSym *const loopCountMinusOneSym) : loopCountMinusOneSym(loopCountMinusOneSym), hasBeenGenerated(true), loopCountSym(nullptr)
  84. {
  85. Assert(loopCountMinusOneSym);
  86. }
  87. LoopCount(StackSym *const loopCountMinusOneSym, StackSym *const loopCountSym) :
  88. loopCountMinusOneSym(loopCountMinusOneSym),
  89. loopCountSym(loopCountSym),
  90. hasBeenGenerated(true)
  91. {
  92. Assert(loopCountMinusOneSym);
  93. }
  94. LoopCount(const int loopCountMinusOneConstantValue)
  95. : loopCountMinusOneSym(nullptr), loopCountMinusOneConstantValue(loopCountMinusOneConstantValue), hasBeenGenerated(true), loopCountSym(nullptr)
  96. {
  97. Assert(loopCountMinusOneConstantValue >= 0);
  98. }
  99. public:
  100. bool HasBeenGenerated() const
  101. {
  102. return hasBeenGenerated;
  103. }
  104. bool HasGeneratedLoopCountSym() const
  105. {
  106. // Consider loop count sym generated if there is no loopCountMinusOneSym and it has been generated
  107. return hasBeenGenerated && (loopCountSym != nullptr || loopCountMinusOneSym == nullptr);
  108. }
  109. StackSym *LeftSym() const
  110. {
  111. Assert(!HasBeenGenerated());
  112. return leftSym;
  113. }
  114. StackSym *RightSym() const
  115. {
  116. Assert(!HasBeenGenerated());
  117. return rightSym;
  118. }
  119. int Offset() const
  120. {
  121. Assert(!HasBeenGenerated());
  122. return offset;
  123. }
  124. int MinMagnitudeChange() const
  125. {
  126. Assert(!HasBeenGenerated());
  127. return minMagnitudeChange;
  128. }
  129. StackSym *LoopCountMinusOneSym() const
  130. {
  131. Assert(HasBeenGenerated());
  132. return loopCountMinusOneSym;
  133. }
  134. StackSym *LoopCountSym() const
  135. {
  136. Assert(HasGeneratedLoopCountSym());
  137. return loopCountSym;
  138. }
  139. void SetLoopCountSym(StackSym *const loopCountSym)
  140. {
  141. Assert(HasBeenGenerated());
  142. Assert(loopCountSym);
  143. this->loopCountSym = loopCountSym;
  144. }
  145. void SetLoopCountMinusOneSym(StackSym *const loopCountMinusOneSym)
  146. {
  147. Assert(!HasBeenGenerated());
  148. Assert(loopCountMinusOneSym);
  149. hasBeenGenerated = true;
  150. this->loopCountMinusOneSym = loopCountMinusOneSym;
  151. }
  152. int LoopCountMinusOneConstantValue() const
  153. {
  154. Assert(!LoopCountMinusOneSym());
  155. return loopCountMinusOneConstantValue;
  156. }
  157. };
  158. class GlobOpt::AddSubConstantInfo
  159. {
  160. private:
  161. StackSym *srcSym;
  162. Value *srcValue;
  163. bool srcValueIsLikelyConstant;
  164. int32 offset;
  165. public:
  166. AddSubConstantInfo() : srcSym(nullptr)
  167. {
  168. }
  169. public:
  170. bool HasInfo() const
  171. {
  172. return !!srcSym;
  173. }
  174. StackSym *SrcSym() const
  175. {
  176. Assert(HasInfo());
  177. return srcSym;
  178. }
  179. Value *SrcValue() const
  180. {
  181. Assert(HasInfo());
  182. return srcValue;
  183. }
  184. bool SrcValueIsLikelyConstant() const
  185. {
  186. Assert(HasInfo());
  187. return srcValueIsLikelyConstant;
  188. }
  189. int32 Offset() const
  190. {
  191. Assert(HasInfo());
  192. return offset;
  193. }
  194. public:
  195. void Set(StackSym *const srcSym, Value *const srcValue, const bool srcValueIsLikelyConstant, const int32 offset);
  196. };
  197. class GlobOpt::ArrayLowerBoundCheckHoistInfo
  198. {
  199. protected:
  200. BasicBlock *compatibleBoundCheckBlock;
  201. Loop *loop;
  202. // Info populated for a compatible bound check and for hoisting out of loop
  203. StackSym *indexSym;
  204. int offset;
  205. ValueNumber indexValueNumber;
  206. // Info populated for hoisting out of loop
  207. Value *indexValue;
  208. IntConstantBounds indexConstantBounds; // also populated for constant index, when there's a compatible bound check
  209. bool isLoopCountBasedBound;
  210. // Info populated for hoisting out of loop using a loop count based bound, when the bound needs to be generated
  211. LoopCount *loopCount;
  212. int maxMagnitudeChange;
  213. public:
  214. ArrayLowerBoundCheckHoistInfo() : compatibleBoundCheckBlock(nullptr), loop(nullptr)
  215. {
  216. }
  217. public:
  218. bool HasAnyInfo() const
  219. {
  220. return CompatibleBoundCheckBlock() || Loop();
  221. }
  222. BasicBlock *CompatibleBoundCheckBlock() const
  223. {
  224. Assert(!(compatibleBoundCheckBlock && loop));
  225. return compatibleBoundCheckBlock;
  226. }
  227. Loop *Loop() const
  228. {
  229. Assert(!(compatibleBoundCheckBlock && loop));
  230. return loop;
  231. }
  232. StackSym *IndexSym() const
  233. {
  234. Assert(HasAnyInfo());
  235. return indexSym;
  236. }
  237. int Offset() const
  238. {
  239. Assert(HasAnyInfo());
  240. return offset;
  241. }
  242. ValueNumber IndexValueNumber() const
  243. {
  244. Assert(HasAnyInfo());
  245. Assert(IndexSym());
  246. return indexValueNumber;
  247. }
  248. Value *IndexValue() const
  249. {
  250. Assert(Loop());
  251. return indexValue;
  252. }
  253. const IntConstantBounds &IndexConstantBounds() const
  254. {
  255. Assert(Loop() || CompatibleBoundCheckBlock() && !IndexSym());
  256. return indexConstantBounds;
  257. }
  258. bool IsLoopCountBasedBound() const
  259. {
  260. Assert(Loop());
  261. return isLoopCountBasedBound;
  262. }
  263. LoopCount *LoopCount() const
  264. {
  265. Assert(Loop());
  266. return loopCount;
  267. }
  268. int MaxMagnitudeChange() const
  269. {
  270. Assert(LoopCount());
  271. return maxMagnitudeChange;
  272. }
  273. public:
  274. void SetCompatibleBoundCheck(BasicBlock *const compatibleBoundCheckBlock, StackSym *const indexSym, const int offset, const ValueNumber indexValueNumber);
  275. void SetLoop(::Loop *const loop, const int indexConstantValue, const bool isLoopCountBasedBound = false);
  276. void SetLoop(::Loop *const loop, StackSym *const indexSym, const int offset, Value *const indexValue, const IntConstantBounds &indexConstantBounds, const bool isLoopCountBasedBound = false);
  277. void SetLoopCount(::LoopCount *const loopCount, const int maxMagnitudeChange);
  278. };
  279. class GlobOpt::ArrayUpperBoundCheckHoistInfo : protected ArrayLowerBoundCheckHoistInfo
  280. {
  281. private:
  282. typedef ArrayLowerBoundCheckHoistInfo Base;
  283. private:
  284. // Info populated for hoisting out of loop
  285. Value *headSegmentLengthValue;
  286. IntConstantBounds headSegmentLengthConstantBounds;
  287. public:
  288. using Base::HasAnyInfo;
  289. using Base::CompatibleBoundCheckBlock;
  290. using Base::Loop;
  291. using Base::IndexSym;
  292. using Base::Offset;
  293. using Base::IndexValueNumber;
  294. using Base::IndexValue;
  295. using Base::IndexConstantBounds;
  296. using Base::IsLoopCountBasedBound;
  297. using Base::LoopCount;
  298. using Base::MaxMagnitudeChange;
  299. public:
  300. Value *HeadSegmentLengthValue() const
  301. {
  302. Assert(Loop());
  303. return headSegmentLengthValue;
  304. }
  305. const IntConstantBounds &HeadSegmentLengthConstantBounds() const
  306. {
  307. Assert(Loop());
  308. return headSegmentLengthConstantBounds;
  309. }
  310. public:
  311. using Base::SetCompatibleBoundCheck;
  312. using Base::SetLoopCount;
  313. protected:
  314. using Base::SetLoop;
  315. public:
  316. void SetCompatibleBoundCheck(BasicBlock *const compatibleBoundCheckBlock, const int indexConstantValue);
  317. void SetLoop(::Loop *const loop, const int indexConstantValue, Value *const headSegmentLengthValue, const IntConstantBounds &headSegmentLengthConstantBounds, const bool isLoopCountBasedBound = false);
  318. void SetLoop(::Loop *const loop, StackSym *const indexSym, const int offset, Value *const indexValue, const IntConstantBounds &indexConstantBounds, Value *const headSegmentLengthValue, const IntConstantBounds &headSegmentLengthConstantBounds, const bool isLoopCountBasedBound = false);
  319. };