IntBounds.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  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 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 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. const int constantBound = constantBoundBase + offset;
  270. return
  271. offset >= 0
  272. ? constantBound >= constantBoundBase && constantValue >= constantBound
  273. : constantBound >= constantBoundBase || constantValue >= constantBound;
  274. }
  275. bool IntBounds::IsLessThanOrEqualTo(const int constantValue, const int constantBoundBase, const int offset)
  276. {
  277. if(offset == 0)
  278. return constantValue <= constantBoundBase;
  279. if(offset == -1)
  280. return constantValue < constantBoundBase;
  281. const int constantBound = constantBoundBase + offset;
  282. return
  283. offset >= 0
  284. ? constantBound < constantBoundBase || constantValue <= constantBound
  285. : constantBound < constantBoundBase && constantValue <= constantBound;
  286. }
  287. bool IntBounds::IsGreaterThanOrEqualTo(const int constantBoundBase, const int offset) const
  288. {
  289. return IsGreaterThanOrEqualTo(constantLowerBound, constantBoundBase, offset);
  290. }
  291. bool IntBounds::IsLessThanOrEqualTo(const int constantBoundBase, const int offset) const
  292. {
  293. return IsLessThanOrEqualTo(constantUpperBound, constantBoundBase, offset);
  294. }
  295. bool IntBounds::IsGreaterThanOrEqualTo(const Value *const value, const int offset) const
  296. {
  297. Assert(value);
  298. ValueInfo *const valueInfo = value->GetValueInfo();
  299. int constantBoundBase;
  300. const bool success = valueInfo->TryGetIntConstantUpperBound(&constantBoundBase, true);
  301. Assert(success);
  302. if(IsGreaterThanOrEqualTo(constantBoundBase, offset))
  303. return true;
  304. if(valueInfo->HasIntConstantValue())
  305. return false;
  306. const ValueRelativeOffset *bound;
  307. return relativeLowerBounds.TryGetReference(value->GetValueNumber(), &bound) && bound->Offset() >= offset;
  308. }
  309. bool IntBounds::IsLessThanOrEqualTo(const Value *const value, const int offset) const
  310. {
  311. Assert(value);
  312. ValueInfo *const valueInfo = value->GetValueInfo();
  313. int constantBoundBase;
  314. const bool success = valueInfo->TryGetIntConstantLowerBound(&constantBoundBase, true);
  315. Assert(success);
  316. if(IsLessThanOrEqualTo(constantBoundBase, offset))
  317. return true;
  318. if(valueInfo->HasIntConstantValue())
  319. return false;
  320. const ValueRelativeOffset *bound;
  321. return relativeUpperBounds.TryGetReference(value->GetValueNumber(), &bound) && bound->Offset() <= offset;
  322. }
  323. const IntBounds *IntBounds::Add(
  324. const Value *const baseValue,
  325. const int n,
  326. const bool baseValueInfoIsPrecise,
  327. const IntConstantBounds &newConstantBounds,
  328. JitArenaAllocator *const allocator)
  329. {
  330. Assert(baseValue);
  331. Assert(baseValue->GetValueInfo()->IsLikelyInt());
  332. Assert(!baseValue->GetValueInfo()->HasIntConstantValue());
  333. // Determine whether the new constant upper bound was established explicitly
  334. bool wasConstantUpperBoundEstablishedExplicitly = false;
  335. ValueInfo *const baseValueInfo = baseValue->GetValueInfo();
  336. const IntBounds *const baseBounds = baseValueInfo->IsIntBounded() ? baseValueInfo->AsIntBounded()->Bounds() : nullptr;
  337. if(baseBounds && baseBounds->WasConstantUpperBoundEstablishedExplicitly())
  338. {
  339. int baseAdjustedConstantUpperBound;
  340. if(!Int32Math::Add(baseBounds->ConstantUpperBound(), n, &baseAdjustedConstantUpperBound) &&
  341. baseAdjustedConstantUpperBound == newConstantBounds.UpperBound())
  342. {
  343. wasConstantUpperBoundEstablishedExplicitly = true;
  344. }
  345. }
  346. // Create the new bounds. Don't try to determine the constant bounds by offsetting the current constant bounds, as loop
  347. // prepasses are conservative. Use the constant bounds that are passed in.
  348. IntBounds *const newBounds = New(newConstantBounds, wasConstantUpperBoundEstablishedExplicitly, allocator);
  349. // Adjust the relative bounds by the constant. The base value info would not be precise for instance, when we're in a loop
  350. // and the value was created before the loop or in a previous loop iteration.
  351. if(n < 0 && !baseValueInfoIsPrecise)
  352. {
  353. // Don't know the number of similar decreases in value that will take place
  354. Assert(newBounds->constantLowerBound == IntConstMin);
  355. }
  356. else if(baseBounds)
  357. {
  358. Assert(!baseBounds->relativeLowerBounds.ContainsKey(baseValue->GetValueNumber()));
  359. newBounds->relativeLowerBounds.Copy(&baseBounds->relativeLowerBounds);
  360. if(n != 0)
  361. {
  362. for(auto it = newBounds->relativeLowerBounds.GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
  363. {
  364. ValueRelativeOffset &bound = it.CurrentValueReference();
  365. if(!bound.Add(n))
  366. it.RemoveCurrent();
  367. }
  368. }
  369. }
  370. if(n > 0 && !baseValueInfoIsPrecise)
  371. {
  372. // Don't know the number of similar increases in value that will take place, so clear the relative upper bounds
  373. Assert(newBounds->constantUpperBound == IntConstMax);
  374. }
  375. else if(baseBounds)
  376. {
  377. Assert(!baseBounds->relativeUpperBounds.ContainsKey(baseValue->GetValueNumber()));
  378. newBounds->relativeUpperBounds.Copy(&baseBounds->relativeUpperBounds);
  379. if(n != 0)
  380. {
  381. for(auto it = newBounds->relativeUpperBounds.GetIteratorWithRemovalSupport(); it.IsValid(); it.MoveNext())
  382. {
  383. ValueRelativeOffset &bound = it.CurrentValueReference();
  384. if(!bound.Add(n))
  385. it.RemoveCurrent();
  386. }
  387. }
  388. }
  389. // The result is equal to (baseValue +/- n), so set that as a relative lower and upper bound
  390. if(baseValueInfo->HasIntConstantValue())
  391. return newBounds;
  392. const ValueRelativeOffset bound(baseValue, n, true);
  393. if(n >= 0 || baseValueInfoIsPrecise)
  394. newBounds->relativeLowerBounds.Add(bound);
  395. if(n <= 0 || baseValueInfoIsPrecise)
  396. newBounds->relativeUpperBounds.Add(bound);
  397. return newBounds;
  398. }
  399. bool IntBounds::AddCannotOverflowBasedOnRelativeBounds(const int n) const
  400. {
  401. Assert(n != 0);
  402. if(n >= 0)
  403. {
  404. const int maxBoundOffset = -n;
  405. for(auto it = relativeUpperBounds.GetIterator(); it.IsValid(); it.MoveNext())
  406. {
  407. // If (a < b), then (a + 1) cannot overflow
  408. const ValueRelativeOffset &bound = it.CurrentValue();
  409. if(bound.Offset() <= maxBoundOffset)
  410. return true;
  411. }
  412. return false;
  413. }
  414. return n != IntConstMin && SubCannotOverflowBasedOnRelativeBounds(-n);
  415. }
  416. bool IntBounds::SubCannotOverflowBasedOnRelativeBounds(const int n) const
  417. {
  418. Assert(n != 0);
  419. if(n >= 0)
  420. {
  421. const int minBoundOffset = n;
  422. for(auto it = relativeLowerBounds.GetIterator(); it.IsValid(); it.MoveNext())
  423. {
  424. // If (a > b), then (a - 1) cannot overflow
  425. const ValueRelativeOffset &bound = it.CurrentValue();
  426. if(bound.Offset() >= minBoundOffset)
  427. return true;
  428. }
  429. return false;
  430. }
  431. return n != IntConstMin && AddCannotOverflowBasedOnRelativeBounds(-n);
  432. }
  433. const IntBounds *IntBounds::Merge(
  434. const Value *const bounds0Value,
  435. const IntBounds *const bounds0,
  436. const Value *const bounds1Value,
  437. const IntConstantBounds &constantBounds1)
  438. {
  439. Assert(bounds0Value);
  440. bounds0->Verify();
  441. Assert(bounds1Value);
  442. const IntConstantBounds constantBounds(
  443. min(bounds0->ConstantLowerBound(), constantBounds1.LowerBound()),
  444. max(bounds0->ConstantUpperBound(), constantBounds1.UpperBound()));
  445. const ValueNumber bounds1ValueNumber = bounds1Value->GetValueNumber();
  446. const ValueRelativeOffset *commonLowerBound;
  447. if(!bounds0->relativeLowerBounds.TryGetReference(bounds1ValueNumber, &commonLowerBound))
  448. commonLowerBound = nullptr;
  449. const ValueRelativeOffset *commonUpperBound;
  450. if(!bounds0->relativeUpperBounds.TryGetReference(bounds1ValueNumber, &commonUpperBound))
  451. commonUpperBound = nullptr;
  452. if(constantBounds.LowerBound() == IntConstMin &&
  453. constantBounds.UpperBound() == IntConstMax &&
  454. !commonLowerBound &&
  455. !commonUpperBound)
  456. {
  457. return nullptr;
  458. }
  459. IntBounds *const mergedBounds = New(constantBounds, false, bounds0->relativeLowerBounds.GetAllocator());
  460. // A value is implicitly bounded by itself, so preserve and merge bounds where one value is bounded by the other
  461. if(bounds0Value->GetValueNumber() == bounds1ValueNumber)
  462. return mergedBounds;
  463. if(commonLowerBound)
  464. {
  465. ValueRelativeOffset mergedLowerBound(*commonLowerBound);
  466. if(constantBounds1.IsConstant())
  467. mergedLowerBound.MergeConstantValue<true, false>(constantBounds1.LowerBound());
  468. else
  469. mergedLowerBound.Merge<true, false>(ValueRelativeOffset(bounds1Value, true));
  470. mergedBounds->relativeLowerBounds.Add(mergedLowerBound);
  471. }
  472. if(commonUpperBound)
  473. {
  474. ValueRelativeOffset mergedUpperBound(*commonUpperBound);
  475. if(constantBounds1.IsConstant())
  476. mergedUpperBound.MergeConstantValue<false, false>(constantBounds1.LowerBound());
  477. else
  478. mergedUpperBound.Merge<false, false>(ValueRelativeOffset(bounds1Value, true));
  479. mergedBounds->relativeUpperBounds.Add(mergedUpperBound);
  480. }
  481. mergedBounds->Verify();
  482. return mergedBounds;
  483. }
  484. const IntBounds *IntBounds::Merge(
  485. const Value *const bounds0Value,
  486. const IntBounds *const bounds0,
  487. const Value *const bounds1Value,
  488. const IntBounds *const bounds1)
  489. {
  490. Assert(bounds0Value);
  491. bounds0->Verify();
  492. Assert(bounds1Value);
  493. bounds1->Verify();
  494. if(bounds0 == bounds1)
  495. return bounds0;
  496. JitArenaAllocator *const allocator = bounds0->relativeLowerBounds.GetAllocator();
  497. IntBounds *const mergedBounds =
  498. New(IntConstantBounds(
  499. min(bounds0->constantLowerBound, bounds1->constantLowerBound),
  500. max(bounds0->constantUpperBound, bounds1->constantUpperBound)),
  501. bounds0->WasConstantUpperBoundEstablishedExplicitly() && bounds1->WasConstantUpperBoundEstablishedExplicitly(),
  502. allocator);
  503. MergeBoundSets<true>(bounds0Value, bounds0, bounds1Value, bounds1, mergedBounds);
  504. MergeBoundSets<false>(bounds0Value, bounds0, bounds1Value, bounds1, mergedBounds);
  505. if(mergedBounds->HasBounds())
  506. {
  507. mergedBounds->Verify();
  508. return mergedBounds;
  509. }
  510. mergedBounds->Delete();
  511. return nullptr;
  512. }
  513. template<bool Lower>
  514. void IntBounds::MergeBoundSets(
  515. const Value *const bounds0Value,
  516. const IntBounds *const bounds0,
  517. const Value *const bounds1Value,
  518. const IntBounds *const bounds1,
  519. IntBounds *const mergedBounds)
  520. {
  521. Assert(bounds0Value);
  522. bounds0->Verify();
  523. Assert(bounds1Value);
  524. bounds1->Verify();
  525. Assert(bounds0 != bounds1);
  526. Assert(mergedBounds);
  527. Assert(mergedBounds != bounds0);
  528. Assert(mergedBounds != bounds1);
  529. RelativeIntBoundSet *mergedBoundSet;
  530. const RelativeIntBoundSet *boundSet0, *boundSet1;
  531. if(Lower)
  532. {
  533. mergedBoundSet = &mergedBounds->relativeLowerBounds;
  534. boundSet0 = &bounds0->relativeLowerBounds;
  535. boundSet1 = &bounds1->relativeLowerBounds;
  536. }
  537. else
  538. {
  539. mergedBoundSet = &mergedBounds->relativeUpperBounds;
  540. boundSet0 = &bounds0->relativeUpperBounds;
  541. boundSet1 = &bounds1->relativeUpperBounds;
  542. }
  543. // Iterate over the smaller set and look up in the larger set for compatible bounds that can be merged
  544. const RelativeIntBoundSet *iterateOver, *lookUpIn;
  545. if(boundSet0->Count() <= boundSet1->Count())
  546. {
  547. iterateOver = boundSet0;
  548. lookUpIn = boundSet1;
  549. }
  550. else
  551. {
  552. iterateOver = boundSet1;
  553. lookUpIn = boundSet0;
  554. }
  555. for(auto it = iterateOver->GetIterator(); it.IsValid(); it.MoveNext())
  556. {
  557. const ValueRelativeOffset &iterateOver_bound(it.CurrentValue());
  558. const ValueNumber baseValueNumber = iterateOver_bound.BaseValueNumber();
  559. const ValueRelativeOffset *lookUpIn_bound;
  560. if(!lookUpIn->TryGetReference(baseValueNumber, &lookUpIn_bound))
  561. continue;
  562. ValueRelativeOffset mergedBound(iterateOver_bound);
  563. mergedBound.Merge<Lower, false>(*lookUpIn_bound);
  564. mergedBoundSet->Add(mergedBound);
  565. }
  566. // A value is implicitly bounded by itself, so preserve and merge bounds where one value is bounded by the other
  567. const ValueNumber bounds0ValueNumber = bounds0Value->GetValueNumber(), bounds1ValueNumber = bounds1Value->GetValueNumber();
  568. if(bounds0ValueNumber == bounds1ValueNumber)
  569. return;
  570. const ValueRelativeOffset *bound;
  571. if(boundSet0->TryGetReference(bounds1ValueNumber, &bound))
  572. {
  573. ValueRelativeOffset mergedBound(bounds1Value, true);
  574. mergedBound.Merge<Lower, false>(*bound);
  575. mergedBoundSet->Add(mergedBound);
  576. }
  577. if(boundSet1->TryGetReference(bounds0ValueNumber, &bound))
  578. {
  579. ValueRelativeOffset mergedBound(bounds0Value, true);
  580. mergedBound.Merge<Lower, false>(*bound);
  581. mergedBoundSet->Add(mergedBound);
  582. }
  583. }
  584. #pragma endregion
  585. #pragma region IntBoundCheckCompatibilityId and IntBoundCheck
  586. IntBoundCheckCompatibilityId::IntBoundCheckCompatibilityId(
  587. const ValueNumber leftValueNumber,
  588. const ValueNumber rightValueNumber)
  589. : leftValueNumber(leftValueNumber), rightValueNumber(rightValueNumber)
  590. {
  591. }
  592. bool IntBoundCheckCompatibilityId::operator ==(const IntBoundCheckCompatibilityId &other) const
  593. {
  594. return leftValueNumber == other.leftValueNumber && rightValueNumber == other.rightValueNumber;
  595. }
  596. IntBoundCheckCompatibilityId::operator hash_t() const
  597. {
  598. return static_cast<hash_t>(static_cast<hash_t>(leftValueNumber) + static_cast<hash_t>(rightValueNumber));
  599. }
  600. IntBoundCheck::IntBoundCheck()
  601. #if DBG
  602. : leftValueNumber(InvalidValueNumber)
  603. #endif
  604. {
  605. Assert(!IsValid());
  606. }
  607. IntBoundCheck::IntBoundCheck(
  608. const ValueNumber leftValueNumber,
  609. const ValueNumber rightValueNumber,
  610. IR::Instr *const instr,
  611. BasicBlock *const block)
  612. : leftValueNumber(leftValueNumber), rightValueNumber(rightValueNumber), instr(instr), block(block)
  613. {
  614. Assert(IsValid());
  615. }
  616. #if DBG
  617. bool IntBoundCheck::IsValid() const
  618. {
  619. return leftValueNumber != InvalidValueNumber;
  620. }
  621. #endif
  622. ValueNumber IntBoundCheck::LeftValueNumber() const
  623. {
  624. Assert(IsValid());
  625. return leftValueNumber;
  626. }
  627. ValueNumber IntBoundCheck::RightValueNumber() const
  628. {
  629. Assert(IsValid());
  630. return rightValueNumber;
  631. }
  632. IR::Instr *IntBoundCheck::Instr() const
  633. {
  634. Assert(IsValid());
  635. return instr;
  636. }
  637. BasicBlock *IntBoundCheck::Block() const
  638. {
  639. Assert(IsValid());
  640. return block;
  641. }
  642. IntBoundCheckCompatibilityId IntBoundCheck::CompatibilityId() const
  643. {
  644. return IntBoundCheckCompatibilityId(leftValueNumber, rightValueNumber);
  645. }
  646. bool IntBoundCheck::SetBoundOffset(const int offset, const bool isLoopCountBasedBound) const
  647. {
  648. Assert(IsValid());
  649. // Determine the previous offset from the instruction (src1 <= src2 + dst)
  650. IR::IntConstOpnd *dstOpnd = nullptr;
  651. IntConstType previousOffset = 0;
  652. if (instr->GetDst())
  653. {
  654. dstOpnd = instr->GetDst()->AsIntConstOpnd();
  655. previousOffset = dstOpnd->GetValue();
  656. }
  657. IR::IntConstOpnd *src1Opnd = nullptr;
  658. if (instr->GetSrc1()->IsIntConstOpnd())
  659. {
  660. src1Opnd = instr->GetSrc1()->AsIntConstOpnd();
  661. if (IntConstMath::Sub(previousOffset, src1Opnd->GetValue(), &previousOffset))
  662. return false;
  663. }
  664. IR::IntConstOpnd *src2Opnd = (instr->GetSrc2()->IsIntConstOpnd() ? instr->GetSrc2()->AsIntConstOpnd() : nullptr);
  665. if(src2Opnd && IntConstMath::Add(previousOffset, src2Opnd->GetValue(), &previousOffset))
  666. return false;
  667. // Given a bounds check (a <= b + offset), the offset may only be decreased such that it does not invalidate the invariant
  668. // previously established by the check. If the offset needs to be increased, that requirement is already satisfied by the
  669. // previous check.
  670. if(offset >= previousOffset)
  671. return true;
  672. IntConstType offsetDecrease;
  673. if(IntConstMath::Sub(previousOffset, offset, &offsetDecrease))
  674. return false;
  675. Assert(offsetDecrease > 0);
  676. if(src1Opnd)
  677. {
  678. // Prefer to increase src1, as this is an upper bound check and src1 corresponds to the index
  679. IntConstType newSrc1Value;
  680. if(IntConstMath::Add(src1Opnd->GetValue(), offsetDecrease, &newSrc1Value))
  681. return false;
  682. src1Opnd->SetValue(newSrc1Value);
  683. }
  684. else if(dstOpnd)
  685. {
  686. IntConstType newDstValue;
  687. if(IntConstMath::Sub(dstOpnd->GetValue(), offsetDecrease, &newDstValue))
  688. return false;
  689. if (newDstValue == 0)
  690. instr->FreeDst();
  691. else
  692. dstOpnd->SetValue(newDstValue);
  693. }
  694. else
  695. instr->SetDst(IR::IntConstOpnd::New(-offsetDecrease, TyMachReg, instr->m_func, true));
  696. switch(instr->GetBailOutKind())
  697. {
  698. case IR::BailOutOnFailedHoistedBoundCheck:
  699. if(isLoopCountBasedBound)
  700. instr->SetBailOutKind(IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck);
  701. break;
  702. case IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck:
  703. break;
  704. default:
  705. instr->SetBailOutKind(
  706. isLoopCountBasedBound
  707. ? IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck
  708. : IR::BailOutOnFailedHoistedBoundCheck);
  709. break;
  710. }
  711. return true;
  712. }
  713. #pragma endregion