@@ -113,7 +113,7 @@ APInt swift::constantFoldCast(APInt val, const BuiltinInfo &BI) {
113
113
SrcTy->castTo <BuiltinIntegerType>()->getGreatestWidth ();
114
114
uint32_t DestBitWidth =
115
115
DestTy->castTo <BuiltinIntegerType>()->getGreatestWidth ();
116
-
116
+
117
117
APInt CastResV;
118
118
if (SrcBitWidth == DestBitWidth) {
119
119
return val;
@@ -1761,7 +1761,46 @@ ConstantFolder::processWorkList() {
1761
1761
FoldedUsers.insert (TI);
1762
1762
}
1763
1763
1764
- // We were able to fold, so all users should use the new folded value.
1764
+ // We were able to fold, so all users should use the new folded
1765
+ // value. If we don't have any such users, continue.
1766
+ //
1767
+ // NOTE: The reason why we check if our result has uses is that if
1768
+ // User is a MultipleValueInstruction an infinite loop can result if
1769
+ // User has a result different than the one at Index that we can not
1770
+ // constant fold and if C's defining instruction is an aggregate that
1771
+ // defines an operand of I.
1772
+ //
1773
+ // As an elucidating example, consider the following SIL:
1774
+ //
1775
+ // %w = integer_literal $Builtin.Word, 1
1776
+ // %0 = struct $Int (%w : $Builtin.Word) (*)
1777
+ // %1 = apply %f() : $@convention(thin) () -> @owned Klass
1778
+ // %2 = tuple (%0 : $Int, %1 : $Klass)
1779
+ // (%3, %4) = destructure_tuple %2 : $(Int, Klass)
1780
+ // store %4 to [init] %mem2: %*Klass
1781
+ //
1782
+ // Without this check, we would infinite loop by processing our
1783
+ // worklist as follows:
1784
+ //
1785
+ // 1. We visit %w and add %0 to the worklist unconditionally since it
1786
+ // is a StructInst.
1787
+ //
1788
+ // 2. We visit %0 and then since %2 is a tuple, we add %2 to the
1789
+ // worklist unconditionally.
1790
+ //
1791
+ // 3. We visit %2 and see that it has a destructure_tuple user. We see
1792
+ // that we can simplify %3 -> %0, but cannot simplify %4. This
1793
+ // means that if we just assume success if we can RAUW %3 without
1794
+ // checking if we will actually replace anything, we will add %0's
1795
+ // defining instruction (*) to the worklist. Q.E.D.
1796
+ //
1797
+ // In contrast, if we realize that RAUWing %3 does nothing and skip
1798
+ // it, we exit the worklist as expected.
1799
+ SILValue r = User->getResult (Index);
1800
+ if (r->use_empty ())
1801
+ continue ;
1802
+
1803
+ // Otherwise, do the RAUW.
1765
1804
User->getResult (Index)->replaceAllUsesWith (C);
1766
1805
1767
1806
// The new constant could be further folded now, add it to the
0 commit comments