IntBounds.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  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. #include "Backend.h"
  6. #pragma region IntBounds
  7. IntBounds::IntBounds(
  8. const IntConstantBounds &constantBounds,
  9. const bool wasConstantUpperBoundEstablishedExplicitly,
  10. JitArenaAllocator *const allocator)
  11. :
  12. constantLowerBound(constantBounds.LowerBound()),
  13. constantUpperBound(constantBounds.UpperBound()),
  14. wasConstantUpperBoundEstablishedExplicitly(wasConstantUpperBoundEstablishedExplicitly),
  15. relativeLowerBounds(allocator),
  16. relativeUpperBounds(allocator)
  17. {
  18. }
  19. IntBounds *IntBounds::New(
  20. const IntConstantBounds &constantBounds,
  21. const bool wasConstantUpperBoundEstablishedExplicitly,
  22. JitArenaAllocator *const allocator)
  23. {
  24. Assert(allocator);
  25. return JitAnew(allocator, IntBounds, constantBounds, wasConstantUpperBoundEstablishedExplicitly, allocator);
  26. }
  27. IntBounds *IntBounds::Clone() const
  28. {
  29. JitArenaAllocator *const allocator = relativeLowerBounds.GetAllocator();
  30. return JitAnew(allocator, IntBounds, *this);
  31. }
  32. void IntBounds::Delete() const
  33. {
  34. JitArenaAllocator *const allocator = relativeLowerBounds.GetAllocator();
  35. JitAdelete(allocator, const_cast<IntBounds *>(this));
  36. }
  37. void IntBounds::Verify() const
  38. {
  39. Assert(this);
  40. Assert(constantLowerBound <= constantUpperBound);
  41. Assert(HasBounds());
  42. }
  43. bool IntBounds::HasBounds() const
  44. {
  45. return constantLowerBound != IntConstMin || constantUpperBound != IntConstMax || RequiresIntBoundedValueInfo();
  46. }
  47. bool IntBounds::RequiresIntBoundedValueInfo(const ValueType valueType) const
  48. {
  49. Assert(valueType.IsLikelyInt());
  50. return !valueType.IsInt() || RequiresIntBoundedValueInfo();
  51. }
  52. bool IntBounds::RequiresIntBoundedValueInfo() const
  53. {
  54. return WasConstantUpperBoundEstablishedExplicitly() || relativeLowerBounds.Count() != 0 || relativeUpperBounds.Count() != 0;
  55. }
  56. int IntBounds::ConstantLowerBound() const
  57. {
  58. return constantLowerBound;
  59. }
  60. int IntBounds::ConstantUpperBound() const
  61. {
  62. return constantUpperBound;
  63. }
  64. IntConstantBounds IntBounds::ConstantBounds() const
  65. {
  66. return IntConstantBounds(ConstantLowerBound(), ConstantUpperBound());
  67. }
  68. bool IntBounds::WasConstantUpperBoundEstablishedExplicitly() const
  69. {
  70. return wasConstantUpperBoundEstablishedExplicitly;
  71. }
  72. const RelativeIntBoundSet &IntBounds::RelativeLowerBounds() const
  73. {
  74. return relativeLowerBounds;
  75. }
  76. const RelativeIntBoundSet &IntBounds::RelativeUpperBounds() const
  77. {
  78. return relativeUpperBounds;
  79. }
  80. void IntBounds::SetLowerBound(const int constantBound)
  81. {
  82. if(constantLowerBound < constantBound && constantBound <= constantUpperBound)
  83. constantLowerBound = constantBound;
  84. }
  85. void IntBounds::SetLowerBound(const int constantBoundBase, const int offset)
  86. {
  87. SetBound<true>(constantBoundBase, offset, false);
  88. }
  89. void IntBounds::SetUpperBound(const int constantBound, const bool wasEstablishedExplicitly)
  90. {
  91. if(constantLowerBound <= constantBound && constantBound < constantUpperBound)
  92. constantUpperBound = constantBound;
  93. if(wasEstablishedExplicitly)
  94. wasConstantUpperBoundEstablishedExplicitly = true;
  95. }
  96. void IntBounds::SetUpperBound(const int constantBoundBase, const int offset, const bool wasEstablishedExplicitly)
  97. {
  98. SetBound<false>(constantBoundBase, offset, wasEstablishedExplicitly);
  99. }
  100. template<bool Lower>
  101. void IntBounds::SetBound(const int constantBoundBase, const int offset, const bool wasEstablishedExplicitly)
  102. {
  103. int constantBound;
  104. if(offset == 0)
  105. constantBound = constantBoundBase;
  106. else if(Int32Math::Add(constantBoundBase, offset, &constantBound))
  107. return;
  108. if(Lower)
  109. SetLowerBound(constantBound);
  110. else
  111. SetUpperBound(constantBound, wasEstablishedExplicitly);
  112. }
  113. void IntBounds::SetLowerBound(
  114. const ValueNumber myValueNumber,
  115. const Value *const baseValue,
  116. const bool wasEstablishedExplicitly)
  117. {
  118. SetLowerBound(myValueNumber, baseValue, 0, wasEstablishedExplicitly);
  119. }
  120. void IntBounds::SetLowerBound(
  121. const ValueNumber myValueNumber,
  122. const Value *const baseValue,
  123. const int offset,
  124. const bool wasEstablishedExplicitly)
  125. {
  126. SetBound<true>(myValueNumber, baseValue, offset, wasEstablishedExplicitly);
  127. }
  128. void IntBounds::SetUpperBound(
  129. const ValueNumber myValueNumber,
  130. const Value *const baseValue,
  131. const bool wasEstablishedExplicitly)
  132. {
  133. SetUpperBound(myValueNumber, baseValue, 0, wasEstablishedExplicitly);
  134. }
  135. void IntBounds::SetUpperBound(
  136. const ValueNumber myValueNumber,
  137. const Value *const baseValue,
  138. const int offset,
  139. const bool wasEstablishedExplicitly)
  140. {
  141. SetBound<false>(myValueNumber, baseValue, offset, wasEstablishedExplicitly);
  142. }
  143. template<bool Lower>
  144. void IntBounds::SetBound(
  145. const ValueNumber myValueNumber,
  146. const Value *const baseValue,
  147. const int offset,
  148. const bool wasEstablishedExplicitly)
  149. {
  150. Assert(baseValue);
  151. Assert(baseValue->GetValueNumber() != myValueNumber);
  152. // Aggressively merge the constant lower or upper bound of the base value, adjusted by the offset
  153. ValueInfo const * const baseValueInfo = baseValue->GetValueInfo();
  154. int constantBoundBase;
  155. const bool success =
  156. Lower
  157. ? baseValueInfo->TryGetIntConstantLowerBound(&constantBoundBase, true)
  158. : baseValueInfo->TryGetIntConstantUpperBound(&constantBoundBase, true);
  159. Assert(success);
  160. const bool isBoundConstant = baseValueInfo->HasIntConstantValue();
  161. SetBound<Lower>(constantBoundBase, offset, wasEstablishedExplicitly && isBoundConstant);
  162. if(isBoundConstant)
  163. return;
  164. // If the base value has relative bounds, pull in the lower or upper bounds adjusted by the offset
  165. RelativeIntBoundSet &boundSet = Lower ? relativeLowerBounds : relativeUpperBounds;
  166. const RelativeIntBoundSet &oppositeBoundSet = Lower ? relativeUpperBounds : relativeLowerBounds;
  167. if(baseValueInfo->IsIntBounded())
  168. {
  169. const IntBounds *const baseValueBounds = baseValueInfo->AsIntBounded()->Bounds();
  170. const RelativeIntBoundSet &baseValueBoundSet =
  171. Lower ? baseValueBounds->relativeLowerBounds : baseValueBounds->relativeUpperBounds;
  172. for(auto it = baseValueBoundSet.GetIterator(); it.IsValid(); it.MoveNext())
  173. {
  174. ValueRelativeOffset bound(it.CurrentValue());
  175. if(bound.BaseValueNumber() == myValueNumber || !bound.Add(offset))
  176. continue;
  177. const ValueRelativeOffset *existingOppositeBound;
  178. if(oppositeBoundSet.TryGetReference(bound.BaseValueNumber(), &existingOppositeBound) &&
  179. (Lower ? bound.Offset() > existingOppositeBound->Offset() : bound.Offset() < existingOppositeBound->Offset()))
  180. {
  181. // This bound contradicts the existing opposite bound on the same base value number:
  182. // - Setting a lower bound (base + offset) when (base + offset2) is an upper bound and (offset > offset2)
  183. // - Setting an upper bound (base + offset) when (base + offset2) is a lower bound and (offset < offset2)
  184. continue;
  185. }
  186. ValueRelativeOffset *existingBound;
  187. if(boundSet.TryGetReference(bound.BaseValueNumber(), &existingBound))
  188. existingBound->Merge<Lower, true>(bound);
  189. else
  190. boundSet.Add(bound);
  191. }
  192. }
  193. // Set the base value as a relative bound
  194. const ValueRelativeOffset bound(baseValue, offset, wasEstablishedExplicitly);
  195. const ValueRelativeOffset *existingOppositeBound;
  196. if(oppositeBoundSet.TryGetReference(bound.BaseValueNumber(), &existingOppositeBound) &&
  197. (Lower ? offset > existingOppositeBound->Offset() : offset < existingOppositeBound->Offset()))
  198. {
  199. // This bound contradicts the existing opposite bound on the same base value number:
  200. // - Setting a lower bound (base + offset) when (base + offset2) is an upper bound and (offset > offset2)
  201. // - Setting an upper bound (base + offset) when (base + offset2) is a lower bound and (offset < offset2)
  202. return;
  203. }
  204. ValueRelativeOffset *existingBound;
  205. if(boundSet.TryGetReference(bound.BaseValueNumber(), &existingBound))
  206. existingBound->Merge<Lower, true>(bound);
  207. else
  208. boundSet.Add(bound);
  209. }
  210. bool IntBounds::SetIsNot(const int constantValue, const bool isExplicit)
  211. {
  212. if(constantLowerBound == constantUpperBound)
  213. return false;
  214. Assert(constantLowerBound < constantUpperBound);
  215. if(constantValue == constantLowerBound)
  216. {
  217. ++constantLowerBound;
  218. return true;
  219. }
  220. if(constantValue == constantUpperBound)
  221. {
  222. --constantUpperBound;
  223. if(isExplicit)
  224. wasConstantUpperBoundEstablishedExplicitly = true;
  225. return true;
  226. }
  227. return false;
  228. }
  229. bool IntBounds::SetIsNot(const Value *const value, const bool isExplicit)
  230. {
  231. Assert(value);
  232. ValueInfo const *const valueInfo = value->GetValueInfo();
  233. Assert(valueInfo->IsLikelyInt());
  234. int constantValue;
  235. bool changed;
  236. if(valueInfo->TryGetIntConstantValue(&constantValue, true))
  237. {
  238. changed = SetIsNot(constantValue, isExplicit);
  239. if(valueInfo->IsInt())
  240. return changed;
  241. }
  242. else
  243. changed = false;
  244. const ValueNumber valueNumber = value->GetValueNumber();
  245. ValueRelativeOffset *existingLowerBound = nullptr;
  246. const bool existingLowerBoundOffsetIsZero =
  247. relativeLowerBounds.TryGetReference(valueNumber, &existingLowerBound) && existingLowerBound->Offset() == 0;
  248. ValueRelativeOffset *existingUpperBound = nullptr;
  249. const bool existingUpperBoundOffsetIsZero =
  250. relativeUpperBounds.TryGetReference(valueNumber, &existingUpperBound) && existingUpperBound->Offset() == 0;
  251. if(existingLowerBoundOffsetIsZero == existingUpperBoundOffsetIsZero)
  252. return changed; // neither bound can be changed, or changing a bound would contradict the opposite bound
  253. if(existingLowerBoundOffsetIsZero)
  254. existingLowerBound->SetOffset(1);
  255. else
  256. {
  257. existingUpperBound->SetOffset(-1);
  258. if(isExplicit)
  259. existingUpperBound->SetWasEstablishedExplicitly();
  260. }
  261. return true;
  262. }
  263. bool IntBounds::IsGreaterThanOrEqualTo(const int constantValue, const int constantBoundBase, const int offset)
  264. {
  265. if(offset == 0)
  266. return constantValue >= constantBoundBase;
  267. if(offset == 1)
  268. return constantValue > constantBoundBase;
  269. // use unsigned to avoid signed int overflow
  270. const int constantBound = (unsigned)constantBoundBase + (unsigned)offset;
  271. return
  272. offset >= 0
  273. ? constantBound >= constantBoundBase && constantValue >= constantBound
  274. : constantBound >= constantBoundBase || constantValue >= constantBound;
  275. }
  276. bool IntBounds::IsLessThanOrEqualTo(const int constantValue, const int constantBoundBase, const int offset)
  277. {
  278. if(offset == 0)
  279. return constantValue <= constantBoundBase;
  280. if(offset == -1)
  281. return constantValue < constantBoundBase;
  282. // use unsigned to avoid signed int overflow
  283. const int constantBound = (unsigned)constantBoundBase + (unsigned)offset;
  284. return
  285. offset >= 0
  286. ? constantBound < constantBoundBase || constantValue <= constantBound
  287. : constantBound < constantBoundBase && constantValue <= constantBound;
  288. }
  289. bool IntBounds::IsGreaterThanOrEqualTo(const int constantBoundBase, const int offset) const
  290. {
  291. return IsGreaterThanOrEqualTo(constantLowerBound, constantBoundBase, offset);
  292. }
  293. bool IntBounds::IsLessThanOrEqualTo(const int constantBoundBase, const int offset) const
  294. {
  295. return IsLessThanOrEqualTo(constantUpperBound, constantBoundBase, offset);
  296. }
  297. bool IntBounds::IsGreaterThanOrEqualTo(const Value *const value, const int offset) const
  298. {
  299. Assert(value);
  300. ValueInfo const * const valueInfo = value->GetValueInfo();
  301. int constantBoundBase;
  302. const bool success = valueInfo->TryGetIntConstantUpperBound(&constantBoundBase, true);
  303. Assert(success);
  304. if(IsGreaterThanOrEqualTo(constantBoundBase, offset))
  305. return true;
  306. if(valueInfo->HasIntConstantValue())
  307. return false;
  308. const ValueRelativeOffset *bound;
  309. return relativeLowerBounds.TryGetReference(value->GetValueNumber(), &bound) && bound->Offset() >= offset;
  310. }
  311. bool IntBounds::IsLessThanOrEqualTo(const Value *const value, const int offset) const
  312. {
  313. Assert(value);
  314. ValueInfo const * const valueInfo = value->GetValueInfo();
  315. int constantBoundBase;
  316. const bool success = valueInfo->TryGetIntConstantLowerBound(&constantBoundBase, true);
  317. Assert(success);
  318. if(IsLessThanOrEqualTo(constantBoundBase, offset))
  319. return true;
  320. if(valueInfo->HasIntConstantValue())
  321. return false;
  322. const ValueRelativeOffset *bound;
  323. return relativeUpperBounds.TryGetReference(value->GetValueNumber(), &bound) && bound->Offset() <= offset;
  324. }
  325. const IntBounds *IntBounds::Add(
  326. const Value *const baseValue,
  327. const int n,
  328. const bool baseValueInfoIsPrecise,
  329. const IntConstantBounds &newConstantBounds,
  330. JitArenaAllocator *const allocator)
  331. {
  332. Assert(baseValue);
  333. Assert(baseValue->GetValueInfo()->IsLikelyInt());
  334. Assert(!baseValue->GetValueInfo()->HasIntConstantValue());
  335. // Determine whether the new constant upper bound was established explicitly
  336. bool wasConstantUpperBoundEstablishedExplicitly = false;
  337. ValueInfo const * const baseValueInfo = baseValue->GetValueInfo();
  338. const IntBounds *const baseBounds = baseValueInfo->IsIntBounded() ? baseValueInfo->AsIntBounded()->Bounds() : nullptr;
  339. if(baseBounds && baseBounds->WasConstantUpperBoundEstablishedExplicitly())
  340. {
  341. int baseAdjustedConstantUpperBound;
  342. if(!Int32Math::Add(baseBounds->ConstantUpperBound(), n, &baseAdjustedConstantUpperBound) &&
  343. baseAdjustedConstantUpperBound == newConstantBounds.UpperBound())
  344. {
  345. wasConstantUpperBoundEstablishedExplicitly = true;
  346. }
  347. }
  348. // Create the new bounds. Don't try to determine the constant bounds by offsetting the current constant bounds, as loop
  349. // prepasses are conservative. Use the constant bounds that are passed in.
  350. IntBounds *const newBounds = New(newConstantBounds, wasConstantUpperBoundEstablishedExplicitly, allocator);
  351. // Adjust the relative bounds by the constant. The base value info would not be precise for instance, when we're in a loop
  352. // and the value was created before the loop or in a previous loop iteration.
  353. if(n < 0 && !baseValueInfoIsPrecise)
  354. {
  355. // Don't know the number of similar decreases in value that will take place
  356. Assert(newBounds->constantLowerBound == IntConstMin);
  357. }
  358. else if(baseBounds)
  359. {
  360. Assert(!baseBounds->relativeLowerBounds.ContainsKey(baseValue->GetValueNumber()));
  361. newBounds->relativeLowerBounds.Copy(&baseBounds->relativeLowerBounds);
  362. if(n != 0)
  363. {
  364. for(auto it = newBounds->relativeLowerBounds.GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
  365. {
  366. ValueRelativeOffset &bound = it.CurrentValueReference();
  367. if(!bound.Add(n))
  368. it.RemoveCurrent();
  369. }
  370. }
  371. }
  372. if(n > 0 && !baseValueInfoIsPrecise)
  373. {
  374. // Don't know the number of similar increases in value that will take place, so clear the relative upper bounds
  375. Assert(newBounds->constantUpperBound == IntConstMax);
  376. }
  377. else if(baseBounds)
  378. {
  379. Assert(!baseBounds->relativeUpperBounds.ContainsKey(baseValue->GetValueNumber()));
  380. newBounds->relativeUpperBounds.Copy(&baseBounds->relativeUpperBounds);
  381. if(n != 0)
  382. {
  383. for(auto it = newBounds->relativeUpperBounds.GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
  384. {
  385. ValueRelativeOffset &bound = it.CurrentValueReference();
  386. if(!bound.Add(n))
  387. it.RemoveCurrent();
  388. }
  389. }
  390. }
  391. // The result is equal to (baseValue +/- n), so set that as a relative lower and upper bound
  392. if(baseValueInfo->HasIntConstantValue())
  393. return newBounds;
  394. const ValueRelativeOffset bound(baseValue, n, true);
  395. if(n >= 0 || baseValueInfoIsPrecise)
  396. newBounds->relativeLowerBounds.Add(bound);
  397. if(n <= 0 || baseValueInfoIsPrecise)
  398. newBounds->relativeUpperBounds.Add(bound);
  399. return newBounds;
  400. }
  401. bool IntBounds::AddCannotOverflowBasedOnRelativeBounds(const int n) const
  402. {
  403. Assert(n != 0);
  404. if(n >= 0)
  405. {
  406. const int maxBoundOffset = -n;
  407. for(auto it = relativeUpperBounds.GetIterator(); it.IsValid(); it.MoveNext())
  408. {
  409. // If (a < b), then (a + 1) cannot overflow
  410. const ValueRelativeOffset &bound = it.CurrentValue();
  411. if(bound.Offset() <= maxBoundOffset)
  412. return true;
  413. }
  414. return false;
  415. }
  416. return n != IntConstMin && SubCannotOverflowBasedOnRelativeBounds(-n);
  417. }
  418. bool IntBounds::SubCannotOverflowBasedOnRelativeBounds(const int n) const
  419. {
  420. Assert(n != 0);
  421. if(n >= 0)
  422. {
  423. const int minBoundOffset = n;
  424. for(auto it = relativeLowerBounds.GetIterator(); it.IsValid(); it.MoveNext())
  425. {
  426. // If (a > b), then (a - 1) cannot overflow
  427. const ValueRelativeOffset &bound = it.CurrentValue();
  428. if(bound.Offset() >= minBoundOffset)
  429. return true;
  430. }
  431. return false;
  432. }
  433. return n != IntConstMin && AddCannotOverflowBasedOnRelativeBounds(-n);
  434. }
  435. const IntBounds *IntBounds::Merge(
  436. const Value *const bounds0Value,
  437. const IntBounds *const bounds0,
  438. const Value *const bounds1Value,
  439. const IntConstantBounds &constantBounds1)
  440. {
  441. Assert(bounds0Value);
  442. bounds0->Verify();
  443. Assert(bounds1Value);
  444. const IntConstantBounds constantBounds(
  445. min(bounds0->ConstantLowerBound(), constantBounds1.LowerBound()),
  446. max(bounds0->ConstantUpperBound(), constantBounds1.UpperBound()));
  447. const ValueNumber bounds1ValueNumber = bounds1Value->GetValueNumber();
  448. const ValueRelativeOffset *commonLowerBound;
  449. if(!bounds0->relativeLowerBounds.TryGetReference(bounds1ValueNumber, &commonLowerBound))
  450. commonLowerBound = nullptr;
  451. const ValueRelativeOffset *commonUpperBound;
  452. if(!bounds0->relativeUpperBounds.TryGetReference(bounds1ValueNumber, &commonUpperBound))
  453. commonUpperBound = nullptr;
  454. if(constantBounds.LowerBound() == IntConstMin &&
  455. constantBounds.UpperBound() == IntConstMax &&
  456. !commonLowerBound &&
  457. !commonUpperBound)
  458. {
  459. return nullptr;
  460. }
  461. IntBounds *const mergedBounds = New(constantBounds, false, bounds0->relativeLowerBounds.GetAllocator());
  462. // A value is implicitly bounded by itself, so preserve and merge bounds where one value is bounded by the other
  463. if(bounds0Value->GetValueNumber() == bounds1ValueNumber)
  464. return mergedBounds;
  465. if(commonLowerBound)
  466. {
  467. ValueRelativeOffset mergedLowerBound(*commonLowerBound);
  468. if(constantBounds1.IsConstant())
  469. mergedLowerBound.MergeConstantValue<true, false>(constantBounds1.LowerBound());
  470. else
  471. mergedLowerBound.Merge<true, false>(ValueRelativeOffset(bounds1Value, true));
  472. mergedBounds->relativeLowerBounds.Add(mergedLowerBound);
  473. }
  474. if(commonUpperBound)
  475. {
  476. ValueRelativeOffset mergedUpperBound(*commonUpperBound);
  477. if(constantBounds1.IsConstant())
  478. mergedUpperBound.MergeConstantValue<false, false>(constantBounds1.LowerBound());
  479. else
  480. mergedUpperBound.Merge<false, false>(ValueRelativeOffset(bounds1Value, true));
  481. mergedBounds->relativeUpperBounds.Add(mergedUpperBound);
  482. }
  483. mergedBounds->Verify();
  484. return mergedBounds;
  485. }
  486. const IntBounds *IntBounds::Merge(
  487. const Value *const bounds0Value,
  488. const IntBounds *const bounds0,
  489. const Value *const bounds1Value,
  490. const IntBounds *const bounds1)
  491. {
  492. Assert(bounds0Value);
  493. bounds0->Verify();
  494. Assert(bounds1Value);
  495. bounds1->Verify();
  496. if(bounds0 == bounds1)
  497. return bounds0;
  498. JitArenaAllocator *const allocator = bounds0->relativeLowerBounds.GetAllocator();
  499. IntBounds *const mergedBounds =
  500. New(IntConstantBounds(
  501. min(bounds0->constantLowerBound, bounds1->constantLowerBound),
  502. max(bounds0->constantUpperBound, bounds1->constantUpperBound)),
  503. bounds0->WasConstantUpperBoundEstablishedExplicitly() && bounds1->WasConstantUpperBoundEstablishedExplicitly(),
  504. allocator);
  505. MergeBoundSets<true>(bounds0Value, bounds0, bounds1Value, bounds1, mergedBounds);
  506. MergeBoundSets<false>(bounds0Value, bounds0, bounds1Value, bounds1, mergedBounds);
  507. if(mergedBounds->HasBounds())
  508. {
  509. mergedBounds->Verify();
  510. return mergedBounds;
  511. }
  512. mergedBounds->Delete();
  513. return nullptr;
  514. }
  515. template<bool Lower>
  516. void IntBounds::MergeBoundSets(
  517. const Value *const bounds0Value,
  518. const IntBounds *const bounds0,
  519. const Value *const bounds1Value,
  520. const IntBounds *const bounds1,
  521. IntBounds *const mergedBounds)
  522. {
  523. Assert(bounds0Value);
  524. bounds0->Verify();
  525. Assert(bounds1Value);
  526. bounds1->Verify();
  527. Assert(bounds0 != bounds1);
  528. Assert(mergedBounds);
  529. Assert(mergedBounds != bounds0);
  530. Assert(mergedBounds != bounds1);
  531. RelativeIntBoundSet *mergedBoundSet;
  532. const RelativeIntBoundSet *boundSet0, *boundSet1;
  533. if(Lower)
  534. {
  535. mergedBoundSet = &mergedBounds->relativeLowerBounds;
  536. boundSet0 = &bounds0->relativeLowerBounds;
  537. boundSet1 = &bounds1->relativeLowerBounds;
  538. }
  539. else
  540. {
  541. mergedBoundSet = &mergedBounds->relativeUpperBounds;
  542. boundSet0 = &bounds0->relativeUpperBounds;
  543. boundSet1 = &bounds1->relativeUpperBounds;
  544. }
  545. // Iterate over the smaller set and look up in the larger set for compatible bounds that can be merged
  546. const RelativeIntBoundSet *iterateOver, *lookUpIn;
  547. if(boundSet0->Count() <= boundSet1->Count())
  548. {
  549. iterateOver = boundSet0;
  550. lookUpIn = boundSet1;
  551. }
  552. else
  553. {
  554. iterateOver = boundSet1;
  555. lookUpIn = boundSet0;
  556. }
  557. for(auto it = iterateOver->GetIterator(); it.IsValid(); it.MoveNext())
  558. {
  559. const ValueRelativeOffset &iterateOver_bound(it.CurrentValue());
  560. const ValueNumber baseValueNumber = iterateOver_bound.BaseValueNumber();
  561. const ValueRelativeOffset *lookUpIn_bound;
  562. if(!lookUpIn->TryGetReference(baseValueNumber, &lookUpIn_bound))
  563. continue;
  564. ValueRelativeOffset mergedBound(iterateOver_bound);
  565. mergedBound.Merge<Lower, false>(*lookUpIn_bound);
  566. mergedBoundSet->Add(mergedBound);
  567. }
  568. // A value is implicitly bounded by itself, so preserve and merge bounds where one value is bounded by the other
  569. const ValueNumber bounds0ValueNumber = bounds0Value->GetValueNumber(), bounds1ValueNumber = bounds1Value->GetValueNumber();
  570. if(bounds0ValueNumber == bounds1ValueNumber)
  571. return;
  572. const ValueRelativeOffset *bound;
  573. if(boundSet0->TryGetReference(bounds1ValueNumber, &bound))
  574. {
  575. ValueRelativeOffset mergedBound(bounds1Value, true);
  576. mergedBound.Merge<Lower, false>(*bound);
  577. mergedBoundSet->Add(mergedBound);
  578. }
  579. if(boundSet1->TryGetReference(bounds0ValueNumber, &bound))
  580. {
  581. ValueRelativeOffset mergedBound(bounds0Value, true);
  582. mergedBound.Merge<Lower, false>(*bound);
  583. mergedBoundSet->Add(mergedBound);
  584. }
  585. }
  586. #pragma endregion
  587. #pragma region IntBoundCheckCompatibilityId and IntBoundCheck
  588. IntBoundCheckCompatibilityId::IntBoundCheckCompatibilityId(
  589. const ValueNumber leftValueNumber,
  590. const ValueNumber rightValueNumber)
  591. : leftValueNumber(leftValueNumber), rightValueNumber(rightValueNumber)
  592. {
  593. }
  594. bool IntBoundCheckCompatibilityId::operator ==(const IntBoundCheckCompatibilityId &other) const
  595. {
  596. return leftValueNumber == other.leftValueNumber && rightValueNumber == other.rightValueNumber;
  597. }
  598. IntBoundCheckCompatibilityId::operator hash_t() const
  599. {
  600. return static_cast<hash_t>(static_cast<hash_t>(leftValueNumber) + static_cast<hash_t>(rightValueNumber));
  601. }
  602. IntBoundCheck::IntBoundCheck()
  603. #if DBG
  604. : leftValueNumber(InvalidValueNumber)
  605. #endif
  606. {
  607. Assert(!IsValid());
  608. }
  609. IntBoundCheck::IntBoundCheck(
  610. const ValueNumber leftValueNumber,
  611. const ValueNumber rightValueNumber,
  612. IR::Instr *const instr,
  613. BasicBlock *const block)
  614. : leftValueNumber(leftValueNumber), rightValueNumber(rightValueNumber), instr(instr), block(block)
  615. {
  616. Assert(IsValid());
  617. }
  618. #if DBG
  619. bool IntBoundCheck::IsValid() const
  620. {
  621. return leftValueNumber != InvalidValueNumber;
  622. }
  623. #endif
  624. ValueNumber IntBoundCheck::LeftValueNumber() const
  625. {
  626. Assert(IsValid());
  627. return leftValueNumber;
  628. }
  629. ValueNumber IntBoundCheck::RightValueNumber() const
  630. {
  631. Assert(IsValid());
  632. return rightValueNumber;
  633. }
  634. IR::Instr *IntBoundCheck::Instr() const
  635. {
  636. Assert(IsValid());
  637. return instr;
  638. }
  639. BasicBlock *IntBoundCheck::Block() const
  640. {
  641. Assert(IsValid());
  642. return block;
  643. }
  644. IntBoundCheckCompatibilityId IntBoundCheck::CompatibilityId() const
  645. {
  646. return IntBoundCheckCompatibilityId(leftValueNumber, rightValueNumber);
  647. }
  648. bool IntBoundCheck::SetBoundOffset(const int offset, const bool isLoopCountBasedBound) const
  649. {
  650. Assert(IsValid());
  651. // Determine the previous offset from the instruction (src1 <= src2 + dst)
  652. IR::IntConstOpnd *dstOpnd = nullptr;
  653. IntConstType previousOffset = 0;
  654. if (instr->GetDst())
  655. {
  656. dstOpnd = instr->GetDst()->AsIntConstOpnd();
  657. previousOffset = dstOpnd->GetValue();
  658. }
  659. IR::IntConstOpnd *src1Opnd = nullptr;
  660. if (instr->GetSrc1()->IsIntConstOpnd())
  661. {
  662. src1Opnd = instr->GetSrc1()->AsIntConstOpnd();
  663. if (IntConstMath::Sub(previousOffset, src1Opnd->GetValue(), &previousOffset))
  664. return false;
  665. }
  666. IR::IntConstOpnd *src2Opnd = (instr->GetSrc2()->IsIntConstOpnd() ? instr->GetSrc2()->AsIntConstOpnd() : nullptr);
  667. if(src2Opnd && IntConstMath::Add(previousOffset, src2Opnd->GetValue(), &previousOffset))
  668. return false;
  669. // Given a bounds check (a <= b + offset), the offset may only be decreased such that it does not invalidate the invariant
  670. // previously established by the check. If the offset needs to be increased, that requirement is already satisfied by the
  671. // previous check.
  672. if(offset >= previousOffset)
  673. return true;
  674. IntConstType offsetDecrease;
  675. if(IntConstMath::Sub(previousOffset, offset, &offsetDecrease))
  676. return false;
  677. Assert(offsetDecrease > 0);
  678. if(src1Opnd)
  679. {
  680. // Prefer to increase src1, as this is an upper bound check and src1 corresponds to the index
  681. IntConstType newSrc1Value;
  682. if(IntConstMath::Add(src1Opnd->GetValue(), offsetDecrease, &newSrc1Value))
  683. return false;
  684. src1Opnd->SetValue(newSrc1Value);
  685. }
  686. else if(dstOpnd)
  687. {
  688. IntConstType newDstValue;
  689. if(IntConstMath::Sub(dstOpnd->GetValue(), offsetDecrease, &newDstValue))
  690. return false;
  691. if (newDstValue == 0)
  692. instr->FreeDst();
  693. else
  694. dstOpnd->SetValue(newDstValue);
  695. }
  696. else
  697. instr->SetDst(IR::IntConstOpnd::New(-offsetDecrease, TyMachReg, instr->m_func, true));
  698. switch(instr->GetBailOutKind())
  699. {
  700. case IR::BailOutOnFailedHoistedBoundCheck:
  701. if(isLoopCountBasedBound)
  702. instr->SetBailOutKind(IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck);
  703. break;
  704. case IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck:
  705. break;
  706. default:
  707. instr->SetBailOutKind(
  708. isLoopCountBasedBound
  709. ? IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck
  710. : IR::BailOutOnFailedHoistedBoundCheck);
  711. break;
  712. }
  713. return true;
  714. }
  715. #pragma endregion