Skip to content

Commit 10c2a1d

Browse files
committed
Fix SimplifyCFG::simplifySwitchEnumOnObjcClassOptional for OSSA
1 parent bdb01d6 commit 10c2a1d

File tree

6 files changed

+137
-426
lines changed

6 files changed

+137
-426
lines changed

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@ bool swift::onlyAffectsRefCount(SILInstruction *user) {
279279
switch (user->getKind()) {
280280
default:
281281
return false;
282-
case SILInstructionKind::AutoreleaseValueInst:
282+
case SILInstructionKind::CopyValueInst:
283283
case SILInstructionKind::DestroyValueInst:
284+
case SILInstructionKind::AutoreleaseValueInst:
284285
case SILInstructionKind::ReleaseValueInst:
285286
case SILInstructionKind::RetainValueInst:
286287
case SILInstructionKind::StrongReleaseInst:

lib/SILOptimizer/Mandatory/DiagnoseInvalidEscapingCaptures.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,25 @@ static bool checkNoEscapePartialApplyUse(Operand *oper, FollowUse followUses) {
5555
isa<CopyBlockWithoutEscapingInst>(user))
5656
return false;
5757

58+
// Look through copies, borrows, and conversions.
59+
// getSingleValueCopyOrCast handles all result producing instructions for
60+
// which onlyAffectsRefCount returns true.
61+
if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
62+
// Only follow the copied operand. Other operands are incidental,
63+
// as in the second operand of mark_dependence.
64+
if (oper->getOperandNumber() == 0)
65+
followUses(copy);
66+
67+
return false;
68+
}
69+
5870
// Ignore uses that are totally uninteresting. partial_apply [stack] is
5971
// terminated by a dealloc_stack instruction.
6072
if (isIncidentalUse(user) || onlyAffectsRefCount(user) ||
61-
isa<DeallocStackInst>(user))
73+
isa<DeallocStackInst>(user)) {
74+
assert(user->getNumResults() == 0);
6275
return false;
76+
}
6377

6478
// Before checking conversions in general below (getSingleValueCopyOrCast),
6579
// check for convert_function to [without_actually_escaping]. Assume such
@@ -69,16 +83,6 @@ static bool checkNoEscapePartialApplyUse(Operand *oper, FollowUse followUses) {
6983
return false;
7084
}
7185

72-
// Look through copies, borrows, and conversions.
73-
if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
74-
// Only follow the copied operand. Other operands are incidental,
75-
// as in the second operand of mark_dependence.
76-
if (oper->getOperandNumber() == 0)
77-
followUses(copy);
78-
79-
return false;
80-
}
81-
8286
// Look through `differentiable_function`.
8387
if (auto *DFI = dyn_cast<DifferentiableFunctionInst>(user)) {
8488
followUses(DFI);

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,7 +1847,9 @@ static bool containsOnlyObjMethodCallOnOptional(SILValue optionalValue,
18471847

18481848
// The branch should forward one of the objc_method call.
18491849
if (auto *br = dyn_cast<BranchInst>(inst)) {
1850-
if (br->getNumArgs() == 0 || br->getNumArgs() > 1)
1850+
if (br->getNumArgs() == 0)
1851+
continue;
1852+
if (br->getNumArgs() > 1)
18511853
return false;
18521854
auto branchArg = br->getArg(0);
18531855
if (std::find(objCApplies.begin(), objCApplies.end(), branchArg) ==
@@ -1895,6 +1897,9 @@ static bool onlyForwardsNone(SILBasicBlock *noneBB, SILBasicBlock *someBB,
18951897
continue;
18961898
}
18971899
if (auto *noneBranch = dyn_cast<BranchInst>(inst)) {
1900+
if (noneBranch->getNumArgs() == 0) {
1901+
continue;
1902+
}
18981903
if (noneBranch->getNumArgs() != 1 ||
18991904
(noneBranch->getArg(0) != SEI->getOperand() &&
19001905
noneBranch->getArg(0) != optionalNone))
@@ -2006,12 +2011,6 @@ static bool hasSameUltimateSuccessor(SILBasicBlock *noneBB, SILBasicBlock *someB
20062011
/// %4 = enum #Optional.none
20072012
/// br mergeBB(%4)
20082013
bool SimplifyCFG::simplifySwitchEnumOnObjcClassOptional(SwitchEnumInst *SEI) {
2009-
// TODO: OSSA; handle non-trivial enum case cleanup
2010-
// (simplify_switch_enum_objc.sil).
2011-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
2012-
return false;
2013-
}
2014-
20152014
auto optional = SEI->getOperand();
20162015
auto optionalPayloadType = optional->getType().getOptionalObjectType();
20172016
if (!optionalPayloadType ||
@@ -2048,10 +2047,20 @@ bool SimplifyCFG::simplifySwitchEnumOnObjcClassOptional(SwitchEnumInst *SEI) {
20482047
optionalPayloadType);
20492048
optionalPayload->replaceAllUsesWith(payloadCast);
20502049
auto *switchBB = SEI->getParent();
2051-
if (someBB->getNumArguments())
2052-
Builder.createBranch(SEI->getLoc(), someBB, SILValue(payloadCast));
2053-
else
2050+
2051+
if (!someBB->args_empty()) {
2052+
assert(someBB->getNumArguments() == 1);
2053+
auto *someBBArg = someBB->getArgument(0);
2054+
if (!someBBArg->use_empty()) {
2055+
assert(optionalPayload != someBBArg);
2056+
someBBArg->replaceAllUsesWith(payloadCast);
2057+
}
2058+
someBB->eraseArgument(0);
20542059
Builder.createBranch(SEI->getLoc(), someBB);
2060+
} else {
2061+
assert(!Fn.hasOwnership());
2062+
Builder.createBranch(SEI->getLoc(), someBB);
2063+
}
20552064

20562065
SEI->eraseFromParent();
20572066
addToWorklist(switchBB);

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ struct SimplifyCFGSimplifySwitchEnumBlock : UnitTest {
319319
}
320320
};
321321

322+
struct SimplifyCFGSwitchEnumOnObjcClassOptional : UnitTest {
323+
SimplifyCFGSwitchEnumOnObjcClassOptional(UnitTestRunner *pass)
324+
: UnitTest(pass) {}
325+
void invoke(Arguments &arguments) override {
326+
auto *passToRun = cast<SILFunctionTransform>(createSimplifyCFG());
327+
passToRun->injectPassManager(getPass()->getPassManager());
328+
passToRun->injectFunction(getFunction());
329+
SimplifyCFG(*getFunction(), *passToRun, /*VerifyAll=*/false,
330+
/*EnableJumpThread=*/false)
331+
.simplifySwitchEnumOnObjcClassOptional(
332+
cast<SwitchEnumInst>(arguments.takeInstruction()));
333+
}
334+
};
335+
322336
struct SimplifyCFGSimplifySwitchEnumUnreachableBlocks : UnitTest {
323337
SimplifyCFGSimplifySwitchEnumUnreachableBlocks(UnitTestRunner *pass)
324338
: UnitTest(pass) {}
@@ -513,6 +527,9 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
513527
ADD_UNIT_TEST_SUBCLASS(
514528
"simplify-cfg-simplify-switch-enum-unreachable-blocks",
515529
SimplifyCFGSimplifySwitchEnumUnreachableBlocks)
530+
ADD_UNIT_TEST_SUBCLASS(
531+
"simplify-cfg-simplify-switch-enum-on-objc-class-optional",
532+
SimplifyCFGSwitchEnumOnObjcClassOptional)
516533
ADD_UNIT_TEST_SUBCLASS(
517534
"simplify-cfg-simplify-term-with-identical-dest-blocks",
518535
SimplifyCFGSimplifyTermWithIdenticalDestBlocks)

test/SILOptimizer/outliner.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public func testOutlining() {
6363
// CHECK: [[OBJ:%.*]] = open_existential_ref {{.*}} : $AnyObject to $@opened("{{.*}}", AnyObject) Self
6464
// CHECK: [[METH:%.*]] = objc_method [[OBJ]] : $@opened("{{.*}}", AnyObject) Self, #Treeish.treeishChildren!foreign : <Self where Self : Treeish> (Self) -> () -> [Any]?
6565
// CHECK: [[RES:%.*]] = apply [[METH]]([[OBJ]]) : $@convention(objc_method)
66-
// CHECK: switch_enum [[RES]]
6766
// CHECK: } // end sil function '$s8outliner9dontCrash1ayyp_tF'
6867

6968
// CHECK-LABEL: sil shared [noinline] @$sSo5GizmoC14stringPropertySSSgvgToTeab_ : {{.*}} {

0 commit comments

Comments
 (0)