|
15 | 15 | //===----------------------------------------------------------------------===//
|
16 | 16 |
|
17 | 17 | #include "swift/SIL/SILInstruction.h"
|
18 |
| -#include "swift/Basic/Assertions.h" |
19 | 18 | #include "swift/Basic/AssertImplements.h"
|
| 19 | +#include "swift/Basic/Assertions.h" |
20 | 20 | #include "swift/Basic/Unicode.h"
|
21 | 21 | #include "swift/Basic/type_traits.h"
|
22 | 22 | #include "swift/SIL/ApplySite.h"
|
23 | 23 | #include "swift/SIL/DynamicCasts.h"
|
24 | 24 | #include "swift/SIL/InstructionUtils.h"
|
| 25 | +#include "swift/SIL/NodeDatastructures.h" |
25 | 26 | #include "swift/SIL/OwnershipUtils.h"
|
| 27 | +#include "swift/SIL/PrunedLiveness.h" |
26 | 28 | #include "swift/SIL/SILBuilder.h"
|
27 | 29 | #include "swift/SIL/SILCloner.h"
|
28 | 30 | #include "swift/SIL/SILDebugScope.h"
|
@@ -1876,29 +1878,72 @@ PartialApplyInst::visitOnStackLifetimeEnds(
|
1876 | 1878 | && "only meaningful for OSSA stack closures");
|
1877 | 1879 | bool noUsers = true;
|
1878 | 1880 |
|
1879 |
| - auto visitUnknownUse = [](Operand *unknownUse) { |
1880 |
| - // There shouldn't be any dead-end consumptions of a nonescaping |
1881 |
| - // partial_apply that don't forward it along, aside from destroy_value. |
1882 |
| - // |
1883 |
| - // On-stack partial_apply cannot be cloned, so it should never be used by a |
1884 |
| - // BranchInst. |
1885 |
| - // |
1886 |
| - // This is a fatal error because it performs SIL verification that is not |
1887 |
| - // separately checked in the verifier. It is the only check that verifies |
1888 |
| - // the structural requirements of on-stack partial_apply uses. |
1889 |
| - llvm::errs() << "partial_apply [on_stack] use:\n"; |
1890 |
| - auto *user = unknownUse->getUser(); |
1891 |
| - user->printInContext(llvm::errs()); |
1892 |
| - if (isa<BranchInst>(user)) { |
1893 |
| - llvm::report_fatal_error("partial_apply [on_stack] cannot be cloned"); |
1894 |
| - } |
1895 |
| - llvm::report_fatal_error("partial_apply [on_stack] must be directly " |
1896 |
| - "forwarded to a destroy_value"); |
1897 |
| - return false; |
1898 |
| - }; |
1899 |
| - if (!visitRecursivelyLifetimeEndingUses(this, noUsers, func, |
1900 |
| - visitUnknownUse)) { |
1901 |
| - return false; |
| 1881 | + auto *function = getFunction(); |
| 1882 | + |
| 1883 | + SmallVector<SILBasicBlock *, 32> discoveredBlocks; |
| 1884 | + SSAPrunedLiveness liveness(function, &discoveredBlocks); |
| 1885 | + liveness.initializeDef(this); |
| 1886 | + |
| 1887 | + StackList<SILValue> values(function); |
| 1888 | + values.push_back(this); |
| 1889 | + ValueSet seenValues(function); |
| 1890 | + |
| 1891 | + while (!values.empty()) { |
| 1892 | + auto value = values.pop_back_val(); |
| 1893 | + seenValues.insert(value); |
| 1894 | + for (auto *use : value->getUses()) { |
| 1895 | + if (!use->isConsuming()) { |
| 1896 | + if (auto *cvi = dyn_cast<CopyValueInst>(use->getUser())) { |
| 1897 | + values.push_back(cvi); |
| 1898 | + } |
| 1899 | + continue; |
| 1900 | + } |
| 1901 | + noUsers = false; |
| 1902 | + if (isa<DestroyValueInst>(use->getUser())) { |
| 1903 | + liveness.updateForUse(use->getUser(), /*lifetimeEnding=*/true); |
| 1904 | + continue; |
| 1905 | + } |
| 1906 | + auto forward = ForwardingOperand(use); |
| 1907 | + if (!forward) { |
| 1908 | + // There shouldn't be any non-forwarding consumptions of a nonescaping |
| 1909 | + // partial_apply that don't forward it along, aside from destroy_value. |
| 1910 | + // |
| 1911 | + // On-stack partial_apply cannot be cloned, so it should never be used |
| 1912 | + // by a BranchInst. |
| 1913 | + // |
| 1914 | + // This is a fatal error because it performs SIL verification that is |
| 1915 | + // not separately checked in the verifier. It is the only check that |
| 1916 | + // verifies the structural requirements of on-stack partial_apply uses. |
| 1917 | + if (isa<StoreInst>(use->getUser()) && use->get() != SILValue(this)) { |
| 1918 | + // Stores of copies are okay. They are lowered to copy_addrs. |
| 1919 | + continue; |
| 1920 | + } |
| 1921 | + llvm::errs() << "partial_apply [on_stack] use:\n"; |
| 1922 | + auto *user = use->getUser(); |
| 1923 | + user->printInContext(llvm::errs()); |
| 1924 | + if (isa<BranchInst>(user)) { |
| 1925 | + llvm::report_fatal_error("partial_apply [on_stack] cannot be cloned"); |
| 1926 | + } |
| 1927 | + llvm::report_fatal_error("partial_apply [on_stack] must be directly " |
| 1928 | + "forwarded to a destroy_value"); |
| 1929 | + } |
| 1930 | + forward.visitForwardedValues([&values](auto value) { |
| 1931 | + values.push_back(value); |
| 1932 | + return true; |
| 1933 | + }); |
| 1934 | + } |
| 1935 | + } |
| 1936 | + PrunedLivenessBoundary boundary; |
| 1937 | + liveness.computeBoundary(boundary); |
| 1938 | + |
| 1939 | + for (auto *inst : boundary.lastUsers) { |
| 1940 | + // Only destroy_values were added to liveness, so only destroy_values can be |
| 1941 | + // the last users. |
| 1942 | + auto *dvi = cast<DestroyValueInst>(inst); |
| 1943 | + auto keepGoing = func(&dvi->getOperandRef()); |
| 1944 | + if (!keepGoing) { |
| 1945 | + return false; |
| 1946 | + } |
1902 | 1947 | }
|
1903 | 1948 | return !noUsers;
|
1904 | 1949 | }
|
|
0 commit comments