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
+ #include " swift/SIL/InstWrappers.h"
24
25
#include " swift/SIL/InstructionUtils.h"
26
+ #include " swift/SIL/NodeDatastructures.h"
25
27
#include " swift/SIL/OwnershipUtils.h"
28
+ #include " swift/SIL/PrunedLiveness.h"
26
29
#include " swift/SIL/SILBuilder.h"
27
30
#include " swift/SIL/SILCloner.h"
28
31
#include " swift/SIL/SILDebugScope.h"
@@ -1869,6 +1872,38 @@ visitRecursivelyLifetimeEndingUses(
1869
1872
return true ;
1870
1873
}
1871
1874
1875
+ static SILValue lookThroughOwnershipAndForwardingInsts (SILValue value) {
1876
+ auto current = value;
1877
+ while (true ) {
1878
+ if (auto *inst = current->getDefiningInstruction ()) {
1879
+ switch (inst->getKind ()) {
1880
+ case SILInstructionKind::MoveValueInst:
1881
+ case SILInstructionKind::CopyValueInst:
1882
+ case SILInstructionKind::BeginBorrowInst:
1883
+ current = inst->getOperand (0 );
1884
+ continue ;
1885
+ default :
1886
+ break ;
1887
+ }
1888
+ auto forward = ForwardingOperation (inst);
1889
+ Operand *op = nullptr ;
1890
+ if (forward && (op = forward.getSingleForwardingOperand ())) {
1891
+ current = op->get ();
1892
+ continue ;
1893
+ }
1894
+ } else if (auto *result = SILArgument::isTerminatorResult (current)) {
1895
+ auto *op = result->forwardedTerminatorResultOperand ();
1896
+ if (!op) {
1897
+ break ;
1898
+ }
1899
+ current = op->get ();
1900
+ continue ;
1901
+ }
1902
+ break ;
1903
+ }
1904
+ return current;
1905
+ }
1906
+
1872
1907
bool
1873
1908
PartialApplyInst::visitOnStackLifetimeEnds (
1874
1909
llvm::function_ref<bool (Operand *)> func) const {
@@ -1877,29 +1912,74 @@ PartialApplyInst::visitOnStackLifetimeEnds(
1877
1912
&& " only meaningful for OSSA stack closures" );
1878
1913
bool noUsers = true ;
1879
1914
1880
- auto visitUnknownUse = [](Operand *unknownUse) {
1881
- // There shouldn't be any dead-end consumptions of a nonescaping
1882
- // partial_apply that don't forward it along, aside from destroy_value.
1883
- //
1884
- // On-stack partial_apply cannot be cloned, so it should never be used by a
1885
- // BranchInst.
1886
- //
1887
- // This is a fatal error because it performs SIL verification that is not
1888
- // separately checked in the verifier. It is the only check that verifies
1889
- // the structural requirements of on-stack partial_apply uses.
1890
- llvm::errs () << " partial_apply [on_stack] use:\n " ;
1891
- auto *user = unknownUse->getUser ();
1892
- user->printInContext (llvm::errs ());
1893
- if (isa<BranchInst>(user)) {
1894
- llvm::report_fatal_error (" partial_apply [on_stack] cannot be cloned" );
1895
- }
1896
- llvm::report_fatal_error (" partial_apply [on_stack] must be directly "
1897
- " forwarded to a destroy_value" );
1898
- return false ;
1899
- };
1900
- if (!visitRecursivelyLifetimeEndingUses (this , noUsers, func,
1901
- visitUnknownUse)) {
1902
- return false ;
1915
+ auto *function = getFunction ();
1916
+
1917
+ SmallVector<SILBasicBlock *, 32 > discoveredBlocks;
1918
+ SSAPrunedLiveness liveness (function, &discoveredBlocks);
1919
+ liveness.initializeDef (this );
1920
+
1921
+ StackList<SILValue> values (function);
1922
+ values.push_back (this );
1923
+
1924
+ while (!values.empty ()) {
1925
+ auto value = values.pop_back_val ();
1926
+ for (auto *use : value->getUses ()) {
1927
+ if (!use->isConsuming ()) {
1928
+ if (auto *cvi = dyn_cast<CopyValueInst>(use->getUser ())) {
1929
+ values.push_back (cvi);
1930
+ }
1931
+ continue ;
1932
+ }
1933
+ noUsers = false ;
1934
+ if (isa<DestroyValueInst>(use->getUser ())) {
1935
+ liveness.updateForUse (use->getUser (), /* lifetimeEnding=*/ true );
1936
+ continue ;
1937
+ }
1938
+ auto forward = ForwardingOperand (use);
1939
+ if (!forward) {
1940
+ // There shouldn't be any non-forwarding consumptions of a nonescaping
1941
+ // partial_apply that don't forward it along, aside from destroy_value.
1942
+ //
1943
+ // On-stack partial_apply cannot be cloned, so it should never be used
1944
+ // by a BranchInst.
1945
+ //
1946
+ // This is a fatal error because it performs SIL verification that is
1947
+ // not separately checked in the verifier. It is the only check that
1948
+ // verifies the structural requirements of on-stack partial_apply uses.
1949
+ if (lookThroughOwnershipAndForwardingInsts (use->get ()) !=
1950
+ SILValue (this )) {
1951
+ // Consumes of values which aren't "essentially" the
1952
+ // partial_apply [on_stack]
1953
+ // are okay. For example, a not-on_stack partial_apply that captures
1954
+ // it.
1955
+ continue ;
1956
+ }
1957
+ llvm::errs () << " partial_apply [on_stack] use:\n " ;
1958
+ auto *user = use->getUser ();
1959
+ user->printInContext (llvm::errs ());
1960
+ if (isa<BranchInst>(user)) {
1961
+ llvm::report_fatal_error (" partial_apply [on_stack] cannot be cloned" );
1962
+ }
1963
+ llvm::report_fatal_error (" partial_apply [on_stack] must be directly "
1964
+ " forwarded to a destroy_value" );
1965
+ }
1966
+ forward.visitForwardedValues ([&values](auto value) {
1967
+ values.push_back (value);
1968
+ return true ;
1969
+ });
1970
+ }
1971
+ }
1972
+ PrunedLivenessBoundary boundary;
1973
+ liveness.computeBoundary (boundary);
1974
+
1975
+ for (auto *inst : boundary.lastUsers ) {
1976
+ // Only destroy_values were added to liveness, so only destroy_values can be
1977
+ // the last users.
1978
+ auto *dvi = cast<DestroyValueInst>(inst);
1979
+ auto keepGoing = func (&dvi->getOperandRef ());
1980
+ if (!keepGoing) {
1981
+ return false ;
1982
+ }
1903
1983
}
1904
1984
return !noUsers;
1905
1985
}
0 commit comments