1515// ===----------------------------------------------------------------------===//
1616
1717#include " swift/SIL/SILInstruction.h"
18- #include " swift/Basic/Assertions.h"
1918#include " swift/Basic/AssertImplements.h"
19+ #include " swift/Basic/Assertions.h"
2020#include " swift/Basic/Unicode.h"
2121#include " swift/Basic/type_traits.h"
2222#include " swift/SIL/ApplySite.h"
2323#include " swift/SIL/DynamicCasts.h"
24+ #include " swift/SIL/InstWrappers.h"
2425#include " swift/SIL/InstructionUtils.h"
26+ #include " swift/SIL/NodeDatastructures.h"
2527#include " swift/SIL/OwnershipUtils.h"
28+ #include " swift/SIL/PrunedLiveness.h"
2629#include " swift/SIL/SILBuilder.h"
2730#include " swift/SIL/SILCloner.h"
2831#include " swift/SIL/SILDebugScope.h"
@@ -1869,6 +1872,38 @@ visitRecursivelyLifetimeEndingUses(
18691872 return true ;
18701873}
18711874
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+
18721907bool
18731908PartialApplyInst::visitOnStackLifetimeEnds (
18741909 llvm::function_ref<bool (Operand *)> func) const {
@@ -1877,29 +1912,74 @@ PartialApplyInst::visitOnStackLifetimeEnds(
18771912 && " only meaningful for OSSA stack closures" );
18781913 bool noUsers = true ;
18791914
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+ }
19031983 }
19041984 return !noUsers;
19051985}
0 commit comments