1111// ===----------------------------------------------------------------------===//
1212
1313#define DEBUG_TYPE " condbranch-forwarding"
14- #include " swift/SILOptimizer/PassManager/Passes.h"
15- #include " swift/SILOptimizer/PassManager/Transforms.h"
16- #include " swift/SIL/SILInstruction.h"
17- #include " swift/SIL/SILArgument.h"
14+ #include " swift/SIL/BasicBlockBits.h"
1815#include " swift/SIL/DebugUtils.h"
16+ #include " swift/SIL/OwnershipUtils.h"
17+ #include " swift/SIL/SILArgument.h"
1918#include " swift/SIL/SILBuilder.h"
19+ #include " swift/SIL/SILInstruction.h"
2020#include " swift/SIL/SILUndef.h"
21- #include " swift/SIL/BasicBlockBits.h"
21+ #include " swift/SILOptimizer/PassManager/Passes.h"
22+ #include " swift/SILOptimizer/PassManager/Transforms.h"
2223
2324using namespace swift ;
2425
@@ -101,15 +102,12 @@ class ConditionForwarding : public SILFunctionTransform {
101102
102103 // / The entry point to the transformation.
103104 void run () override {
104- LLVM_DEBUG (llvm::dbgs () << " ** StackPromotion **\n " );
105-
106105 bool Changed = false ;
107106
108107 SILFunction *F = getFunction ();
109108
110- // FIXME: Add ownership support.
111- if (F->hasOwnership ())
112- return ;
109+ LLVM_DEBUG (llvm::dbgs ()
110+ << " ** ConditionForwarding on " << F->getName () << " **\n " );
113111
114112 for (SILBasicBlock &BB : *F) {
115113 if (auto *SEI = dyn_cast<SwitchEnumInst>(BB.getTerminator ())) {
@@ -143,6 +141,11 @@ static bool hasNoRelevantSideEffects(SILBasicBlock *BB) {
143141 return false ;
144142 continue ;
145143 }
144+ if (isa<BeginBorrowInst>(&I) || isa<EndBorrowInst>(&I)) {
145+ continue ;
146+ }
147+ LLVM_DEBUG (llvm::dbgs () << " Bailing out, found inst with side-effects " );
148+ LLVM_DEBUG (I.dump ());
146149 return false ;
147150 }
148151 return true ;
@@ -226,6 +229,15 @@ bool ConditionForwarding::tryOptimize(SwitchEnumInst *SEI) {
226229 if (CommonBranchBlock->getSuccessors ().size () != PredBlocks.size ())
227230 return false ;
228231
232+ if (getFunction ()->hasOwnership ()) {
233+ // TODO: Currently disabled because this case may need lifetime extension
234+ // Disabling this conservatively for now.
235+ assert (Condition->getNumOperands () == 1 );
236+ BorrowedValue conditionOp (Condition->getOperand (0 ));
237+ if (conditionOp && conditionOp.isLocalScope ()) {
238+ return false ;
239+ }
240+ }
229241 // Now do the transformation!
230242 // First thing to do is to replace all uses of the Enum (= the merging block
231243 // argument), as this argument gets deleted.
@@ -247,8 +259,8 @@ bool ConditionForwarding::tryOptimize(SwitchEnumInst *SEI) {
247259 SILArgument *NewArg = nullptr ;
248260 if (NeedEnumArg.insert (UseBlock)) {
249261 // The first Enum use in this UseBlock.
250- NewArg =
251- UseBlock-> createPhiArgument ( Arg->getType (), OwnershipKind::Owned );
262+ NewArg = UseBlock-> createPhiArgument (Arg-> getType (),
263+ Arg->getOwnershipKind () );
252264 } else {
253265 // We already inserted the Enum argument for this UseBlock.
254266 assert (UseBlock->getNumArguments () >= 1 );
@@ -281,10 +293,30 @@ bool ConditionForwarding::tryOptimize(SwitchEnumInst *SEI) {
281293 if (HasEnumArg) {
282294 // The successor block has a new argument (which we created above) where
283295 // we have to pass the Enum.
296+ assert (!getFunction ()->hasOwnership () ||
297+ EI->getType ().isTrivial (*getFunction ()));
284298 BranchArgs.push_back (EI);
285299 }
286300 B.createBranch (BI->getLoc (), SEDest, BranchArgs);
287301 BI->eraseFromParent ();
302+ if (EI->use_empty ()) {
303+ assert (!HasEnumArg);
304+ EI->eraseFromParent ();
305+ } else {
306+ // If an @owned EI has uses remaining, ownership fixup is needed.
307+ // 1. Create a copy_value of EI's operand and
308+ // use it in the branch to avoid a double-consume.
309+ // 2. Create a destroy_value of EI, to avoid a leak.
310+ if (getFunction ()->hasOwnership () && EI->hasOperand () &&
311+ EI->getOwnershipKind () == OwnershipKind::Owned) {
312+ auto *term = EI->getParent ()->getTerminator ();
313+ assert (!HasEnumArg);
314+ auto *copy = SILBuilderWithScope (EI).createCopyValue (EI->getLoc (),
315+ EI->getOperand ());
316+ term->getOperandRef (0 ).set (copy);
317+ SILBuilderWithScope (term).createDestroyValue (EI->getLoc (), EI);
318+ }
319+ }
288320 }
289321
290322 // Final step: replace the switch_enum by the condition.
0 commit comments