Skip to content

Commit 978395b

Browse files
authored
Merge pull request swiftlang#62959 from meg-gupta/simplifycfgossapr3
Migrate simple and dominator based jump threading to OSSA
2 parents 392bbfd + 8fafdd1 commit 978395b

14 files changed

+1146
-1081
lines changed

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 80 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,21 @@
5858
#include "llvm/Support/CommandLine.h"
5959
#include "llvm/Support/Debug.h"
6060

61-
// This is temporarily used for testing until Swift 5.5 branches to reduce risk.
62-
llvm::cl::opt<bool> EnableOSSASimplifyCFG(
63-
"enable-ossa-simplify-cfg",
64-
llvm::cl::desc(
65-
"Enable non-trivial OSSA simplify-cfg and simple jump threading "
66-
"(staging)."));
67-
68-
// This requires new OwnershipOptUtilities which aren't well tested yet.
69-
llvm::cl::opt<bool> EnableOSSARewriteTerminator(
70-
"enable-ossa-rewriteterminator",
71-
llvm::cl::desc(
72-
"Enable OSSA simplify-cfg with non-trivial terminator rewriting "
73-
"(staging)."));
61+
llvm::cl::opt<bool> EnableOSSACheckedCastBrJumpThreading(
62+
"enable-ossa-checked-cast-br-jump-threading",
63+
llvm::cl::desc("Enable OSSA checked cast branch jump threading "
64+
"(staging)."),
65+
llvm::cl::init(true));
66+
67+
llvm::cl::opt<bool> EnableOSSASimpleJumpThreading(
68+
"enable-ossa-simple-jump-threading",
69+
llvm::cl::desc("Enable OSSA simple jump threading (staging)."),
70+
llvm::cl::init(true));
71+
72+
llvm::cl::opt<bool> EnableOSSADominatorBasedSimplify(
73+
"enable-ossa-dominator-based-simplify",
74+
llvm::cl::desc("Enable OSSA dominator based simplifications (staging)."),
75+
llvm::cl::init(true));
7476

7577
llvm::cl::opt<bool> IsInfiniteJumpThreadingBudget(
7678
"sil-infinite-jump-threading-budget",
@@ -183,7 +185,6 @@ bool SimplifyCFG::threadEdge(const ThreadInfo &ti) {
183185
return false;
184186

185187
Cloner.cloneBranchTarget(SrcTerm);
186-
187188
// We have copied the threaded block into the edge.
188189
auto *clonedSrc = Cloner.getNewBB();
189190
SmallVector<SILBasicBlock *, 4> clonedSuccessors(
@@ -207,7 +208,6 @@ bool SimplifyCFG::threadEdge(const ThreadInfo &ti) {
207208
ThreadedSuccessorBlock, Args);
208209

209210
CondTerm->eraseFromParent();
210-
211211
} else {
212212
// Get the enum element and the destination block of the block we jump
213213
// thread.
@@ -217,21 +217,29 @@ bool SimplifyCFG::threadEdge(const ThreadInfo &ti) {
217217
// Instantiate the payload if necessary.
218218
SILBuilderWithScope Builder(SEI);
219219
if (!ThreadedSuccessorBlock->args_empty()) {
220-
auto EnumVal = SEI->getOperand();
221-
auto EnumTy = EnumVal->getType();
222-
auto Loc = SEI->getLoc();
223-
auto Ty = EnumTy.getEnumElementType(ti.EnumCase, SEI->getModule(),
224-
Builder.getTypeExpansionContext());
225-
SILValue UED(
226-
Builder.createUncheckedEnumData(Loc, EnumVal, ti.EnumCase, Ty));
227-
assert(UED->getType()
228-
== (*ThreadedSuccessorBlock->args_begin())->getType()
229-
&& "Argument types must match");
230-
Builder.createBranch(SEI->getLoc(), ThreadedSuccessorBlock, {UED});
231-
220+
if (ti.EnumCase->hasAssociatedValues() &&
221+
(!SEI->hasDefault() ||
222+
ThreadedSuccessorBlock != SEI->getDefaultBB())) {
223+
auto EnumVal = SEI->getOperand();
224+
auto EnumTy = EnumVal->getType();
225+
auto Loc = SEI->getLoc();
226+
auto Ty = EnumTy.getEnumElementType(ti.EnumCase, SEI->getModule(),
227+
Builder.getTypeExpansionContext());
228+
SILValue UED(
229+
Builder.createUncheckedEnumData(Loc, EnumVal, ti.EnumCase, Ty));
230+
assert(UED->getType() ==
231+
(*ThreadedSuccessorBlock->args_begin())->getType() &&
232+
"Argument types must match");
233+
Builder.createBranch(SEI->getLoc(), ThreadedSuccessorBlock, {UED});
234+
} else {
235+
assert(SEI->getDefaultBB() == ThreadedSuccessorBlock);
236+
auto *OldBlockArg = ThreadedSuccessorBlock->getArgument(0);
237+
OldBlockArg->replaceAllUsesWith(SEI->getOperand());
238+
ThreadedSuccessorBlock->eraseArgument(0);
239+
Builder.createBranch(SEI->getLoc(), ThreadedSuccessorBlock);
240+
}
232241
} else {
233-
Builder.createBranch(SEI->getLoc(), ThreadedSuccessorBlock,
234-
ArrayRef<SILValue>());
242+
Builder.createBranch(SEI->getLoc(), ThreadedSuccessorBlock);
235243
}
236244
SEI->eraseFromParent();
237245
}
@@ -495,11 +503,15 @@ bool SimplifyCFG::simplifyThreadedTerminators() {
495503
if (auto *EI = dyn_cast<EnumInst>(SEI->getOperand())) {
496504
LLVM_DEBUG(llvm::dbgs() << "simplify threaded " << *SEI);
497505
auto *LiveBlock = SEI->getCaseDestination(EI->getElement());
498-
if (EI->hasOperand() && !LiveBlock->args_empty())
499-
SILBuilderWithScope(SEI)
500-
.createBranch(SEI->getLoc(), LiveBlock, EI->getOperand());
501-
else
506+
if (!LiveBlock->args_empty()) {
507+
auto *LiveBlockArg = LiveBlock->getArgument(0);
508+
auto NewValue = EI->hasOperand() ? EI->getOperand() : EI;
509+
LiveBlockArg->replaceAllUsesWith(NewValue);
510+
LiveBlock->eraseArgument(0);
511+
SILBuilderWithScope(SEI).createBranch(SEI->getLoc(), LiveBlock);
512+
} else {
502513
SILBuilderWithScope(SEI).createBranch(SEI->getLoc(), LiveBlock);
514+
}
503515
SEI->eraseFromParent();
504516
if (EI->use_empty())
505517
EI->eraseFromParent();
@@ -536,7 +548,7 @@ bool SimplifyCFG::dominatorBasedSimplify(DominanceAnalysis *DA) {
536548
// Get the dominator tree.
537549
DT = DA->get(&Fn);
538550

539-
if (!EnableOSSASimplifyCFG && Fn.hasOwnership())
551+
if (!EnableOSSADominatorBasedSimplify && Fn.hasOwnership())
540552
return false;
541553

542554
// Split all critical edges such that we can move code onto edges. This is
@@ -560,7 +572,7 @@ bool SimplifyCFG::dominatorBasedSimplify(DominanceAnalysis *DA) {
560572
// and MUST NOT change the CFG without updating the dominator tree to
561573
// reflect such change.
562574
if (tryCheckedCastBrJumpThreading(&Fn, DT, deBlocks, BlocksForWorklist,
563-
EnableOSSARewriteTerminator)) {
575+
EnableOSSACheckedCastBrJumpThreading)) {
564576
for (auto BB: BlocksForWorklist)
565577
addToWorklist(BB);
566578

@@ -907,19 +919,13 @@ static bool hasInjectedEnumAtEndOfBlock(SILBasicBlock *block, SILValue enumAddr)
907919
/// tryJumpThreading - Check to see if it looks profitable to duplicate the
908920
/// destination of an unconditional jump into the bottom of this block.
909921
bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
910-
if (!EnableOSSASimplifyCFG && Fn.hasOwnership())
922+
if (!EnableOSSASimpleJumpThreading && Fn.hasOwnership())
911923
return false;
912924

913925
auto *DestBB = BI->getDestBB();
914926
auto *SrcBB = BI->getParent();
915927
TermInst *destTerminator = DestBB->getTerminator();
916-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
917-
if (llvm::any_of(DestBB->getArguments(), [this](SILValue op) {
918-
return !op->getType().isTrivial(Fn);
919-
})) {
920-
return false;
921-
}
922-
}
928+
923929
// If the destination block ends with a return, we don't want to duplicate it.
924930
// We want to maintain the canonical form of a single return where possible.
925931
if (destTerminator->isFunctionExiting())
@@ -948,14 +954,13 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
948954
for (unsigned i : indices(BI->getArgs())) {
949955
SILValue Arg = BI->getArg(i);
950956

951-
// TODO: Verify if we need to jump thread to remove releases in OSSA.
952957
// If the value being substituted on is release there is a chance we could
953958
// remove the release after jump threading.
954-
if (!Arg->getType().isTrivial(*SrcBB->getParent()) &&
955-
couldRemoveRelease(SrcBB, Arg, DestBB,
956-
DestBB->getArgument(i))) {
957-
ThreadingBudget = 8;
958-
break;
959+
// In ossa, copy propagation can do this, avoid jump threading.
960+
if (!Fn.hasOwnership() && !Arg->getType().isTrivial(*SrcBB->getParent()) &&
961+
couldRemoveRelease(SrcBB, Arg, DestBB, DestBB->getArgument(i))) {
962+
ThreadingBudget = 8;
963+
break;
959964
}
960965

961966
// If the value being substituted is an enum, check to see if there are any
@@ -2954,10 +2959,8 @@ static bool shouldTailDuplicate(SILBasicBlock &Block) {
29542959
bool SimplifyCFG::tailDuplicateObjCMethodCallSuccessorBlocks() {
29552960
SmallVector<SILBasicBlock *, 16> ObjCBlocks;
29562961

2957-
// TODO: OSSA phi support. Even if all block arguments are trivial,
2958-
// jump-threading may require creation of guaranteed phis, which may require
2959-
// creation of nested borrow scopes.
2960-
if (!EnableOSSARewriteTerminator && Fn.hasOwnership()) {
2962+
if (Fn.hasOwnership()) {
2963+
// TODO: This needs additional support in ossa.
29612964
return false;
29622965
}
29632966
// Collect blocks to tail duplicate.
@@ -3166,8 +3169,8 @@ RemoveDeadArgsWhenSplitting("sroa-args-remove-dead-args-after",
31663169
llvm::cl::init(true));
31673170

31683171
bool ArgumentSplitter::split() {
3169-
if (!EnableOSSARewriteTerminator && Arg->getFunction()->hasOwnership()) {
3170-
// TODO: OSSA phi support
3172+
if (Arg->getFunction()->hasOwnership()) {
3173+
// TODO: Additional work is needed to create non-trivial projections in ossa
31713174
if (!Arg->getType().isTrivial(*Arg->getFunction()))
31723175
return false;
31733176
}
@@ -3688,6 +3691,19 @@ bool SimplifyCFG::simplifyArgument(SILBasicBlock *BB, unsigned i) {
36883691
auto *Use = *A->use_begin();
36893692
auto *User = Use->getUser();
36903693

3694+
auto disableInOSSA = [](SingleValueInstruction *inst) {
3695+
assert(isa<StructInst>(inst) || isa<TupleInst>(inst) ||
3696+
isa<EnumInst>(inst));
3697+
if (!inst->getFunction()->hasOwnership()) {
3698+
return false;
3699+
}
3700+
if (inst->getOwnershipKind() == OwnershipKind::Owned)
3701+
return !inst->getSingleUse();
3702+
if (BorrowedValue borrow = BorrowedValue(inst->getOperand(0)))
3703+
return borrow.isLocalScope();
3704+
return false;
3705+
};
3706+
36913707
// Handle projections.
36923708
if (!isa<StructExtractInst>(User) &&
36933709
!isa<TupleExtractInst>(User) &&
@@ -3702,15 +3718,17 @@ bool SimplifyCFG::simplifyArgument(SILBasicBlock *BB, unsigned i) {
37023718
return false;
37033719
auto *Branch = cast<BranchInst>(Pred->getTerminator());
37043720
SILValue BranchArg = Branch->getArg(i);
3705-
if (isa<StructInst>(BranchArg))
3706-
continue;
3707-
if (isa<TupleInst>(BranchArg))
3708-
continue;
3721+
if (!isa<StructInst>(BranchArg) && !isa<TupleInst>(BranchArg) &&
3722+
!isa<EnumInst>(BranchArg)) {
3723+
return false;
3724+
}
37093725
if (auto *EI = dyn_cast<EnumInst>(BranchArg)) {
3710-
if (EI->getElement() == cast<UncheckedEnumDataInst>(proj)->getElement())
3711-
continue;
3726+
if (EI->getElement() != cast<UncheckedEnumDataInst>(proj)->getElement())
3727+
return false;
3728+
}
3729+
if (disableInOSSA(cast<SingleValueInstruction>(BranchArg))) {
3730+
return false;
37123731
}
3713-
return false;
37143732
}
37153733

37163734
// Okay, we'll replace the BB arg with one with the right type, replace

stdlib/public/core/IntegerParsing.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ internal func _parseIntegerDigits<Result: FixedWidthInteger>(
5757
}
5858

5959
@_alwaysEmitIntoClient
60+
@inline(__always)
6061
internal func _parseInteger<Result: FixedWidthInteger>(
6162
ascii codeUnits: UnsafeBufferPointer<UInt8>, radix: Int
6263
) -> Result? {

test/IRGen/temporary_allocation/codegen.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-swift-frontend -primary-file %s -O -emit-ir | %FileCheck %s
2+
// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib
23

34
@_silgen_name("blackHole")
45
func blackHole(_ value: UnsafeMutableRawPointer?) -> Void
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-swift-frontend %s -emit-ir -o /dev/null -verify
2+
import Builtin
3+
4+
sil @stack_alloc_builtin: $@convention(thin) () -> () {
5+
bb0:
6+
%0 = integer_literal $Builtin.Word, -1
7+
%1 = integer_literal $Builtin.Word, 8
8+
%2 = builtin "stackAlloc"(%0 : $Builtin.Word, %1 : $Builtin.Word, %1 : $Builtin.Word) : $Builtin.RawPointer // expected-error{{allocation capacity must be greater than or equal to zero}}
9+
%3 = builtin "stackDealloc"(%2 : $Builtin.RawPointer) : $()
10+
%r = tuple ()
11+
return %r : $()
12+
}

test/IRGen/temporary_allocation/negative_size.swift

Lines changed: 0 additions & 9 deletions
This file was deleted.

test/SILOptimizer/simplify_cfg_and_combine_ossa.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplify-cfg -enable-ossa-simplify-cfg -sil-combine -simplify-cfg -sil-combine | %FileCheck %s
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplify-cfg -sil-combine -simplify-cfg -sil-combine | %FileCheck %s
22

33
// These tests require both SimplifyCFG and SILCombine
44

test/SILOptimizer/simplify_cfg_checkcast.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-sil-opt -enable-sil-verify-all %s -jumpthread-simplify-cfg -enable-ossa-simplify-cfg -enable-ossa-rewriteterminator | %FileCheck %s
2-
// RUN: %target-sil-opt -enable-sil-verify-all %s -jumpthread-simplify-cfg -enable-ossa-simplify-cfg -enable-ossa-rewriteterminator -debug-only=sil-simplify-cfg 2>&1 | %FileCheck %s --check-prefix=CHECK-TRACE
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
2+
// RUN: %target-sil-opt -enable-sil-verify-all %s -jumpthread-simplify-cfg -debug-only=sil-simplify-cfg 2>&1 | %FileCheck %s --check-prefix=CHECK-TRACE
33
//
44
// REQUIRES: asserts
55

test/SILOptimizer/simplify_cfg_ossa.sil

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all %s -simplify-cfg -enable-ossa-simplify-cfg | %FileCheck %s
1+
// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
22

33
// OSSA form of tests from simplify_cfg.sil and simplify_cfg_simple.sil.
44
//
@@ -1787,3 +1787,4 @@ bb5:
17871787
bb6(%14 : $FakeBool):
17881788
return %14 : $FakeBool
17891789
}
1790+

0 commit comments

Comments
 (0)