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"
@@ -1828,6 +1831,134 @@ bool SILInstruction::maySuspend() const {
1828
1831
return false ;
1829
1832
}
1830
1833
1834
+ static SILValue lookThroughOwnershipAndForwardingInsts (SILValue value) {
1835
+ auto current = value;
1836
+ while (true ) {
1837
+ if (auto *inst = current->getDefiningInstruction ()) {
1838
+ switch (inst->getKind ()) {
1839
+ case SILInstructionKind::MoveValueInst:
1840
+ case SILInstructionKind::CopyValueInst:
1841
+ case SILInstructionKind::BeginBorrowInst:
1842
+ current = inst->getOperand (0 );
1843
+ continue ;
1844
+ default :
1845
+ break ;
1846
+ }
1847
+ auto forward = ForwardingOperation (inst);
1848
+ Operand *op = nullptr ;
1849
+ if (forward && (op = forward.getSingleForwardingOperand ())) {
1850
+ current = op->get ();
1851
+ continue ;
1852
+ }
1853
+ } else if (auto *result = SILArgument::isTerminatorResult (current)) {
1854
+ auto *op = result->forwardedTerminatorResultOperand ();
1855
+ if (!op) {
1856
+ break ;
1857
+ }
1858
+ current = op->get ();
1859
+ continue ;
1860
+ }
1861
+ break ;
1862
+ }
1863
+ return current;
1864
+ }
1865
+
1866
+ bool
1867
+ PartialApplyInst::visitOnStackLifetimeEnds (
1868
+ llvm::function_ref<bool (Operand *)> func) const {
1869
+ assert (getFunction ()->hasOwnership ()
1870
+ && isOnStack ()
1871
+ && " only meaningful for OSSA stack closures" );
1872
+ bool noUsers = true ;
1873
+
1874
+ auto *function = getFunction ();
1875
+
1876
+ SmallVector<SILBasicBlock *, 32 > discoveredBlocks;
1877
+ SSAPrunedLiveness liveness (function, &discoveredBlocks);
1878
+ liveness.initializeDef (this );
1879
+
1880
+ StackList<SILValue> values (function);
1881
+ values.push_back (this );
1882
+
1883
+ while (!values.empty ()) {
1884
+ auto value = values.pop_back_val ();
1885
+ for (auto *use : value->getUses ()) {
1886
+ if (!use->isConsuming ()) {
1887
+ if (auto *cvi = dyn_cast<CopyValueInst>(use->getUser ())) {
1888
+ values.push_back (cvi);
1889
+ }
1890
+ continue ;
1891
+ }
1892
+ noUsers = false ;
1893
+ if (isa<DestroyValueInst>(use->getUser ())) {
1894
+ liveness.updateForUse (use->getUser (), /* lifetimeEnding=*/ true );
1895
+ continue ;
1896
+ }
1897
+ auto forward = ForwardingOperand (use);
1898
+ if (!forward) {
1899
+ // There shouldn't be any non-forwarding consumptions of a nonescaping
1900
+ // partial_apply that don't forward it along, aside from destroy_value.
1901
+ //
1902
+ // On-stack partial_apply cannot be cloned, so it should never be used
1903
+ // by a BranchInst.
1904
+ //
1905
+ // This is a fatal error because it performs SIL verification that is
1906
+ // not separately checked in the verifier. It is the only check that
1907
+ // verifies the structural requirements of on-stack partial_apply uses.
1908
+ if (lookThroughOwnershipAndForwardingInsts (use->get ()) !=
1909
+ SILValue (this )) {
1910
+ // Consumes of values which aren't "essentially" the
1911
+ // partial_apply [on_stack]
1912
+ // are okay. For example, a not-on_stack partial_apply that captures
1913
+ // it.
1914
+ continue ;
1915
+ }
1916
+ llvm::errs () << " partial_apply [on_stack] use:\n " ;
1917
+ auto *user = use->getUser ();
1918
+ user->printInContext (llvm::errs ());
1919
+ if (isa<BranchInst>(user)) {
1920
+ llvm::report_fatal_error (" partial_apply [on_stack] cannot be cloned" );
1921
+ }
1922
+ llvm::report_fatal_error (" partial_apply [on_stack] must be directly "
1923
+ " forwarded to a destroy_value" );
1924
+ }
1925
+ forward.visitForwardedValues ([&values](auto value) {
1926
+ values.push_back (value);
1927
+ return true ;
1928
+ });
1929
+ }
1930
+ }
1931
+ PrunedLivenessBoundary boundary;
1932
+ liveness.computeBoundary (boundary);
1933
+
1934
+ for (auto *inst : boundary.lastUsers ) {
1935
+ // Only destroy_values were added to liveness, so only destroy_values can be
1936
+ // the last users.
1937
+ auto *dvi = cast<DestroyValueInst>(inst);
1938
+ auto keepGoing = func (&dvi->getOperandRef ());
1939
+ if (!keepGoing) {
1940
+ return false ;
1941
+ }
1942
+ }
1943
+ return !noUsers;
1944
+ }
1945
+
1946
+ namespace swift ::test {
1947
+ FunctionTest PartialApplyPrintOnStackLifetimeEnds (
1948
+ " partial_apply_print_on_stack_lifetime_ends" ,
1949
+ [](auto &function, auto &arguments, auto &test) {
1950
+ auto *inst = arguments.takeInstruction ();
1951
+ auto *pai = cast<PartialApplyInst>(inst);
1952
+ function.print (llvm::outs ());
1953
+ auto result = pai->visitOnStackLifetimeEnds ([](auto *operand) {
1954
+ operand->print (llvm::outs ());
1955
+ return true ;
1956
+ });
1957
+ const char *resultString = result ? " true" : " false" ;
1958
+ llvm::outs () << " returned: " << resultString << " \n " ;
1959
+ });
1960
+ } // end namespace swift::test
1961
+
1831
1962
static bool
1832
1963
visitRecursivelyLifetimeEndingUses (
1833
1964
SILValue i, bool &noUsers,
@@ -1867,17 +1998,6 @@ visitRecursivelyLifetimeEndingUses(
1867
1998
}
1868
1999
}
1869
2000
return true ;
1870
- }
1871
-
1872
- bool
1873
- PartialApplyInst::visitOnStackLifetimeEnds (
1874
- llvm::function_ref<bool (Operand *)> func) const {
1875
- assert (getFunction ()->hasOwnership ()
1876
- && isOnStack ()
1877
- && " only meaningful for OSSA stack closures" );
1878
- bool noUsers = true ;
1879
-
1880
- auto visitUnknownUse = [](Operand *unknownUse) {
1881
2001
// There shouldn't be any dead-end consumptions of a nonescaping
1882
2002
// partial_apply that don't forward it along, aside from destroy_value.
1883
2003
//
@@ -1887,21 +2007,6 @@ PartialApplyInst::visitOnStackLifetimeEnds(
1887
2007
// This is a fatal error because it performs SIL verification that is not
1888
2008
// separately checked in the verifier. It is the only check that verifies
1889
2009
// 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 ;
1903
- }
1904
- return !noUsers;
1905
2010
}
1906
2011
1907
2012
// FIXME: Rather than recursing through all results, this should only recurse
0 commit comments