Skip to content

Commit e80cbe7

Browse files
authored
Migrate ConditionForwarding to OSSA (swiftlang#39734)
1 parent 8504265 commit e80cbe7

File tree

4 files changed

+838
-12
lines changed

4 files changed

+838
-12
lines changed

lib/SILOptimizer/Transforms/ConditionForwarding.cpp

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
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

2324
using 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.

test/SILOptimizer/conditionforwarding.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,3 +356,35 @@ bb7:
356356
%r = tuple ()
357357
return %r : $()
358358
}
359+
360+
// CHECK-LABEL: sil @forwarding_second_enum_use :
361+
// CHECK-NOT: switch_enum
362+
// CHECK-LABEL:} // end sil function 'forwarding_second_enum_use'
363+
sil @forwarding_second_enum_use : $@convention(thin) (Builtin.Int1) -> () {
364+
bb0(%0 : $Builtin.Int1):
365+
cond_br %0, bb1, bb2
366+
367+
bb1:
368+
%1 = enum $E, #E.A!enumelt
369+
br bb3(%1 : $E)
370+
371+
bb2:
372+
%2 = enum $E, #E.B!enumelt
373+
br bb3(%2 : $E)
374+
375+
bb3(%14 : $E):
376+
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
377+
378+
bb4:
379+
%15 = function_ref @use_enum : $@convention(thin) (E) -> ()
380+
%16 = apply %15(%14) : $@convention(thin) (E) -> ()
381+
br bb6
382+
383+
bb5:
384+
br bb6
385+
386+
bb6:
387+
%r = tuple ()
388+
return %r : $()
389+
}
390+

0 commit comments

Comments
 (0)