Merge pull request #19886 from atrick/silgen-critedge
SILGen: simplify cleanups and avoid critical edges.
diff --git a/include/swift/SIL/BasicBlockUtils.h b/include/swift/SIL/BasicBlockUtils.h
index 7f51651..eb8977c 100644
--- a/include/swift/SIL/BasicBlockUtils.h
+++ b/include/swift/SIL/BasicBlockUtils.h
@@ -20,6 +20,11 @@
class SILFunction;
class SILBasicBlock;
+/// \brief Merge a basic block ending in a branch with its successor
+/// if possible.
+void mergeBasicBlockWithSingleSuccessor(SILBasicBlock *BB,
+ SILBasicBlock *succBB);
+
/// A utility for finding dead-end blocks.
///
/// Dead-end blocks are blocks from which there is no path to the function exit
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index 8aaf025..54359a5 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -173,11 +173,20 @@
/// location.
///
/// Clients should prefer this constructor.
- SILBuilder(SILInstruction *I, SILBuilderContext &C)
+ SILBuilder(SILInstruction *I, const SILDebugScope *DS, SILBuilderContext &C)
: TempContext(C.getModule()), C(C), F(I->getFunction()) {
+ assert(DS && "instruction has no debug scope");
+ setCurrentDebugScope(DS);
setInsertionPoint(I);
}
+ SILBuilder(SILBasicBlock *BB, const SILDebugScope *DS, SILBuilderContext &C)
+ : TempContext(C.getModule()), C(C), F(BB->getParent()) {
+ assert(DS && "block has no debug scope");
+ setCurrentDebugScope(DS);
+ setInsertionPoint(BB);
+ }
+
// Allow a pass to override the current SIL module conventions. This should
// only be done by a pass responsible for lowering SIL to a new stage
// (e.g. AddressLowering).
@@ -2123,10 +2132,8 @@
///
/// Clients should prefer this constructor.
SILBuilderWithScope(SILInstruction *I, SILBuilderContext &C)
- : SILBuilder(I, C) {
- assert(I->getDebugScope() && "instruction has no debug scope");
- setCurrentDebugScope(I->getDebugScope());
- }
+ : SILBuilder(I, I->getDebugScope(), C)
+ {}
explicit SILBuilderWithScope(
SILInstruction *I,
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index 57f00bd..2e65b6e 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -614,6 +614,10 @@
assert(preorderBlocks.empty());
// First clone the CFG region.
+ //
+ // FIXME: Add reverse iteration to SILSuccessor, then convert this to an RPOT
+ // traversal. We would prefer to keep CFG regions in RPO order, and this would
+ // be more scalable for functions with many large switches.
SmallVector<SILBasicBlock *, 8> dfsWorklist(1, startBB);
while (!dfsWorklist.empty()) {
auto *BB = dfsWorklist.pop_back_val();
diff --git a/lib/SIL/BasicBlockUtils.cpp b/lib/SIL/BasicBlockUtils.cpp
index 0801381..100560b 100644
--- a/lib/SIL/BasicBlockUtils.cpp
+++ b/lib/SIL/BasicBlockUtils.cpp
@@ -11,11 +11,31 @@
//===----------------------------------------------------------------------===//
#include "swift/SIL/BasicBlockUtils.h"
-#include "swift/SIL/SILFunction.h"
+#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBasicBlock.h"
+#include "swift/SIL/SILFunction.h"
using namespace swift;
+/// Merge the basic block with its successor if possible.
+void swift::mergeBasicBlockWithSingleSuccessor(SILBasicBlock *BB,
+ SILBasicBlock *succBB) {
+ auto *BI = cast<BranchInst>(BB->getTerminator());
+ assert(succBB->getSinglePredecessorBlock());
+
+ // If there are any BB arguments in the destination, replace them with the
+ // branch operands, since they must dominate the dest block.
+ for (unsigned i = 0, e = BI->getArgs().size(); i != e; ++i)
+ succBB->getArgument(i)->replaceAllUsesWith(BI->getArg(i));
+
+ BI->eraseFromParent();
+
+ // Move the instruction from the successor block to the current block.
+ BB->spliceAtEnd(succBB);
+
+ succBB->eraseFromParent();
+}
+
//===----------------------------------------------------------------------===//
// DeadEndBlocks
//===----------------------------------------------------------------------===//
diff --git a/lib/SILGen/Cleanup.cpp b/lib/SILGen/Cleanup.cpp
index 477ca21..5e1fdf7 100644
--- a/lib/SILGen/Cleanup.cpp
+++ b/lib/SILGen/Cleanup.cpp
@@ -154,16 +154,13 @@
}
/// Emit a new block that jumps to the specified location and runs necessary
-/// cleanups based on its level. If there are no cleanups to run, this just
-/// returns the dest block.
+/// cleanups based on its level. Emit a block even if there are no cleanups;
+/// this is usually the destination of a conditional branch, so jumping
+/// straight to `dest` creates a critical edge.
SILBasicBlock *CleanupManager::emitBlockForCleanups(JumpDest dest,
SILLocation branchLoc,
ArrayRef<SILValue> args,
ForUnwind_t forUnwind) {
- // If there are no cleanups to run, just return the Dest block directly.
- if (!hasAnyActiveCleanups(dest.getDepth()))
- return dest.getBlock();
-
// Otherwise, create and emit a new block.
auto *newBlock = SGF.createBasicBlock();
SILGenSavedInsertionPoint IPRAII(SGF, newBlock);
diff --git a/lib/SILGen/Condition.cpp b/lib/SILGen/Condition.cpp
index db91a0b..270b50f 100644
--- a/lib/SILGen/Condition.cpp
+++ b/lib/SILGen/Condition.cpp
@@ -19,14 +19,9 @@
using namespace swift;
using namespace Lowering;
-void Condition::enterTrue(SILGenFunction &SGF) {
- assert(TrueBB && "Cannot call enterTrue without a True block!");
-
- // TrueBB has already been inserted somewhere unless there's a
- // continuation block.
- if (!ContBB) return;
-
- SGF.B.emitBlock(TrueBB);
+void Condition::enter(SILGenFunction &SGF, SILBasicBlock *destBB) {
+ assert(destBB && "Cannot reenter a finished block.");
+ SGF.B.emitBlock(destBB);
}
/// Extract the last SILLocation used in BB.
@@ -36,110 +31,24 @@
return L;
return Fallback;
}
-void Condition::exitTrue(SILGenFunction &SGF, ArrayRef<SILValue> Args) {
- // If there's no continuation block, it's because the condition was
- // folded to true. In that case, we just continue emitting code as
- // if we were still in the true case, and we're unreachable iff the
- // end of the true case is unreachable. In other words, there's
- // nothing to do.
- if (!ContBB) {
- assert(!FalseBB && "no continuation");
+void Condition::exit(SILGenFunction &SGF, SILBasicBlock *destBB,
+ ArrayRef<SILValue> Args) {
+ // If the current point it reachable, branch to the continuation block.
+ if (!SGF.B.hasValidInsertionPoint())
return;
- }
- // If there is a continuation block, we should branch to it if the
- // current point is reachable.
- if (!SGF.B.hasValidInsertionPoint()) {
- // If there is no false code, the continuation block has a use
- // because the main condition jumps directly to it.
- assert(ContBB->pred_empty() || !FalseBB);
- return;
- }
-
- // Otherwise, resume into the continuation block. This branch might
- // be folded by exitFalse if it turns out that that point is
- // unreachable.
SGF.B.createBranch(getContinuationLoc(*SGF.B.getInsertionBB(), Loc),
ContBB, Args);
-
- // Coming out of exitTrue, we can be in one of three states:
- // - a valid non-terminal IP, but only if there is no continuation
- // block, which is only possible if there is no false block;
- // - a valid terminal IP, if the end of the true block was reachable; or
- // - a cleared IP, if the end of the true block was not reachable.
-}
-
-void Condition::enterFalse(SILGenFunction &SGF) {
- assert(FalseBB && "entering the false branch when it was not valid");
-
- // FalseBB has already been inserted somewhere unless there's a
- // continuation block.
- if (!ContBB) return;
-
- // It's possible to have no insertion point here if the end of the
- // true case was unreachable.
- SGF.B.emitBlock(FalseBB);
-}
-
-void Condition::exitFalse(SILGenFunction &SGF, ArrayRef<SILValue> Args) {
- // If there's no continuation block, it's because the condition was
- // folded to false. In that case, we just continue emitting code as
- // if we were still in the false case, and we're unreachable iff the
- // end of the false case is unreachable. In other words, there's
- // nothing to do.
- if (!ContBB) return;
-
- if (ContBB->pred_empty()) {
- // If the true case didn't need the continuation block, then
- // we don't either, regardless of whether the current location
- // is reachable. Just keep inserting / being unreachable
- // right where we are.
- } else if (!SGF.B.hasValidInsertionPoint()) {
- // If the true case did need the continuation block, but the false
- // case doesn't, just merge the continuation block back into its
- // single predecessor and move the IP there.
- //
- // Note that doing this tends to strand the false code after
- // everything else in the function, so maybe it's not a great idea.
- auto PI = ContBB->pred_begin();
- SILBasicBlock *ContPred = *PI;
-
- // Verify there was only a single predecessor to ContBB.
- ++PI;
- assert(PI == ContBB->pred_end() && "Only expect one branch to the ContBB");
-
- // Insert before the uncond branch and zap it.
- auto *Br = cast<BranchInst>(ContPred->getTerminator());
- SGF.B.setInsertionPoint(Br->getParent());
-
- Br->eraseFromParent();
- assert(ContBB->pred_empty() &&
- "Zapping the branch should make ContBB dead");
- } else {
- // Otherwise, branch to the continuation block and start inserting there.
- SGF.B.createBranch(getContinuationLoc(*SGF.B.getInsertionBB(), Loc),
- ContBB, Args);
- }
}
SILBasicBlock *Condition::complete(SILGenFunction &SGF) {
- // If there is no continuation block, it's because we
- // constant-folded the branch. The case-exit will have left us in a
- // normal insertion state (i.e. not a post-terminator IP) with
- // nothing to clean up after.
- if (!ContBB) {
- return SGF.B.getInsertionBB();
+ assert(!TrueBB && "enterTrue is always called.");
+ if (FalseBB) {
+ assert(ContBB->getNumArguments() == 0 &&
+ "block arguments require a non-empty false path.");
+ SILGenBuilder(SGF.B, FalseBB).createBranch(Loc, ContBB);
+ FalseBB = nullptr;
}
-
- // Kill the continuation block if it's not being used. Case-exits
- // only leave themselves post-terminator if they use the
- // continuation block, so we're in an acceptable insertion state.
- if (ContBB->pred_empty() && ContBB->args_empty()) {
- SGF.eraseBasicBlock(ContBB);
- return SGF.B.hasValidInsertionPoint() ? SGF.B.getInsertionBB() : nullptr;
- }
-
- // Okay, we need to insert the continuation block.
SGF.B.emitBlock(ContBB);
return ContBB;
}
diff --git a/lib/SILGen/Condition.h b/lib/SILGen/Condition.h
index b171a0c..1b21fb7 100644
--- a/lib/SILGen/Condition.h
+++ b/lib/SILGen/Condition.h
@@ -32,10 +32,12 @@
/// A condition is the result of evaluating a boolean expression as
/// control flow.
+///
+/// For each Condition instance, `enterTrue` must be called before `complete`.
+/// If `enterFalse` is skipped, then an empty fall-through block is created.
class LLVM_LIBRARY_VISIBILITY Condition {
- /// The blocks responsible for executing the true and false conditions. A
- /// block is non-null if that branch is possible, but it's only an independent
- /// block if both branches are possible.
+ /// The blocks responsible for executing the true and false conditions. These
+ /// are initialized non-null and set to null after being emitted.
SILBasicBlock *TrueBB;
SILBasicBlock *FalseBB;
@@ -50,30 +52,39 @@
SILBasicBlock *ContBB,
SILLocation L)
: TrueBB(TrueBB), FalseBB(FalseBB), ContBB(ContBB), Loc(L)
- {}
-
- bool hasTrue() const { return TrueBB; }
- bool hasFalse() const { return FalseBB; }
-
- /// enterTrue - Begin the emission of the true block. This should only be
- /// called if hasTrue() returns true.
- void enterTrue(SILGenFunction &SGF);
-
- /// exitTrue - End the emission of the true block. This must be called after
- /// enterTrue but before anything else on this Condition.
- void exitTrue(SILGenFunction &SGF, ArrayRef<SILValue> Args = {});
-
- /// enterFalse - Begin the emission of the false block. This should only be
- /// called if hasFalse() returns true.
- void enterFalse(SILGenFunction &SGF);
-
- /// exitFalse - End the emission of the true block. This must be called after
- /// enterFalse but before anything else on this Condition.
- void exitFalse(SILGenFunction &SGF, ArrayRef<SILValue> Args = {});
-
+ {
+ assert((TrueBB != nullptr && FalseBB != nullptr) &&
+ "Requires non-null block pointers.");
+ }
+
+ /// enterTrue - Begin the emission of the true block.
+ void enterTrue(SILGenFunction &SGF) { enter(SGF, TrueBB); }
+
+ /// exitTrue - End the emission of the true block.
+ void exitTrue(SILGenFunction &SGF, ArrayRef<SILValue> Args = {}) {
+ exit(SGF, TrueBB, Args);
+ TrueBB = nullptr;
+ }
+
+ /// enterFalse - Begin the emission of the false block.
+ void enterFalse(SILGenFunction &SGF) { enter(SGF, FalseBB); }
+
+ /// exitFalse - End the emission of the true block.
+ void exitFalse(SILGenFunction &SGF, ArrayRef<SILValue> Args = {}) {
+ exit(SGF, FalseBB, Args);
+ FalseBB = nullptr;
+ }
+
/// complete - Complete this conditional execution. This should be called
/// only after all other calls on this Condition have been made.
+ /// This leaves SGF's SILGenBuilder at the continuation block.
SILBasicBlock *complete(SILGenFunction &SGF);
+
+protected:
+ void enter(SILGenFunction &SGF, SILBasicBlock *destBB);
+
+ void exit(SILGenFunction &SGF, SILBasicBlock *destBB,
+ ArrayRef<SILValue> Args = {});
};
/// A conditional value is one that depends on conditional execution.
diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h
index f6cb98c..a3920ae 100644
--- a/lib/SILGen/SILGenBuilder.h
+++ b/lib/SILGen/SILGenBuilder.h
@@ -63,6 +63,14 @@
SILBasicBlock::iterator insertInst)
: SILGenBuilder(SGF, &*insertBB, insertInst) {}
+ // Create a new builder, inheriting the given builder's context and debug
+ // scope.
+ SILGenBuilder(SILGenBuilder &builder, SILBasicBlock *insertBB)
+ : SILBuilder(insertBB, builder.getCurrentDebugScope(),
+ builder.getBuilderContext()),
+ SGF(builder.SGF)
+ {}
+
SILGenModule &getSILGenModule() const;
SILGenFunction &getSILGenFunction() const { return SGF; }
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index 1d77860..2979c04 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -1264,7 +1264,7 @@
/// specified JumpDest. The insertion point is left in the block where the
/// condition has matched and any bound variables are in scope.
///
-void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FailDest,
+void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FalseDest,
SILLocation loc,
ProfileCounter NumTrueTaken,
ProfileCounter NumFalseTaken) {
@@ -1279,7 +1279,7 @@
switch (elt.getKind()) {
case StmtConditionElement::CK_PatternBinding: {
InitializationPtr initialization =
- InitializationForPattern(*this, FailDest).visit(elt.getPattern());
+ InitializationForPattern(*this, FalseDest).visit(elt.getPattern());
// Emit the initial value into the initialization.
FullExpr Scope(Cleanups, CleanupLocation(elt.getInitializer()));
@@ -1320,8 +1320,8 @@
// Just branch on the condition. On failure, we unwind any active cleanups,
// on success we fall through to a new block.
+ auto FailBB = Cleanups.emitBlockForCleanups(FalseDest, loc);
SILBasicBlock *ContBB = createBasicBlock();
- auto FailBB = Cleanups.emitBlockForCleanups(FailDest, loc);
B.createCondBranch(booleanTestLoc, booleanTestValue, ContBB, FailBB,
NumTrueTaken, NumFalseTaken);
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index f63848c..f53f386 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -3346,9 +3346,11 @@
C.getBoolDecl()->getStoredProperties().front(), i1Ty);
auto isTrueBB = subSGF.createBasicBlock();
-
- subSGF.B.createCondBranch(loc, isEqualI1, isTrueBB, isFalseBB);
-
+ // Each false condition needs its own block to avoid critical edges.
+ auto falseEdgeBB = subSGF.createBasicBlockAndBranch(loc, isFalseBB);
+
+ subSGF.B.createCondBranch(loc, isEqualI1, isTrueBB, falseEdgeBB);
+
subSGF.B.emitBlock(isTrueBB);
}
@@ -4436,7 +4438,6 @@
// FIXME: We could avoid imploding and reexploding tuples here.
Condition cond = SGF.emitCondition(E->getCondExpr(),
- /*hasFalse*/ true,
/*invertCondition*/ false,
SGF.getLoweredType(E->getType()),
NumTrueTaken, NumFalseTaken);
@@ -4473,7 +4474,6 @@
E, lowering.getLoweredType(), C);
Condition cond = SGF.emitCondition(E->getCondExpr(),
- /*hasFalse*/ true,
/*invertCondition*/ false,
/*contArgs*/ {},
NumTrueTaken, NumFalseTaken);
diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp
index b4928ca..b36f2b5 100644
--- a/lib/SILGen/SILGenFunction.cpp
+++ b/lib/SILGen/SILGenFunction.cpp
@@ -401,6 +401,8 @@
emitStmt(fd->getBody());
emitEpilog(fd);
+
+ mergeCleanupBlocks();
}
void SILGenFunction::emitClosure(AbstractClosureExpr *ace) {
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index a011c37..3f41ca6 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -679,12 +679,10 @@
//===--------------------------------------------------------------------===//
// Control flow
//===--------------------------------------------------------------------===//
-
+
/// emitCondition - Emit a boolean expression as a control-flow condition.
///
/// \param E - The expression to be evaluated as a condition.
- /// \param hasFalseCode - true if the false branch doesn't just lead
- /// to the fallthrough.
/// \param invertValue - true if this routine should invert the value before
/// testing true/false.
/// \param contArgs - the types of the arguments to the continuation BB.
@@ -693,14 +691,15 @@
/// \param NumTrueTaken - The number of times the condition evaluates to true.
/// \param NumFalseTaken - The number of times the condition evaluates to
/// false.
- Condition emitCondition(Expr *E, bool hasFalseCode = true,
- bool invertValue = false,
+ ///
+ /// If `contArgs` is nonempty, then both Condition::exitTrue() and
+ /// Condition::exitFalse() must be called.
+ Condition emitCondition(Expr *E, bool invertValue = false,
ArrayRef<SILType> contArgs = {},
ProfileCounter NumTrueTaken = ProfileCounter(),
ProfileCounter NumFalseTaken = ProfileCounter());
- Condition emitCondition(SILValue V, SILLocation Loc, bool hasFalseCode = true,
- bool invertValue = false,
+ Condition emitCondition(SILValue V, SILLocation Loc, bool invertValue = false,
ArrayRef<SILType> contArgs = {},
ProfileCounter NumTrueTaken = ProfileCounter(),
ProfileCounter NumFalseTaken = ProfileCounter());
@@ -727,6 +726,9 @@
/// section.
SILBasicBlock *createBasicBlock(FunctionSection section);
+ SILBasicBlock *createBasicBlockAndBranch(SILLocation loc,
+ SILBasicBlock *destBB);
+
/// Erase a basic block that was speculatively created and turned
/// out to be unneeded.
///
@@ -736,6 +738,8 @@
/// The block should be empty and have no predecessors.
void eraseBasicBlock(SILBasicBlock *block);
+ void mergeCleanupBlocks();
+
//===--------------------------------------------------------------------===//
// Memory management
//===--------------------------------------------------------------------===//
@@ -1041,7 +1045,7 @@
//===--------------------------------------------------------------------===//
SILValue emitOSVersionRangeCheck(SILLocation loc, const VersionRange &range);
- void emitStmtCondition(StmtCondition Cond, JumpDest FailDest, SILLocation loc,
+ void emitStmtCondition(StmtCondition Cond, JumpDest FalseDest, SILLocation loc,
ProfileCounter NumTrueTaken = ProfileCounter(),
ProfileCounter NumFalseTaken = ProfileCounter());
diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp
index d2ac885..df9f587 100644
--- a/lib/SILGen/SILGenStmt.cpp
+++ b/lib/SILGen/SILGenStmt.cpp
@@ -20,6 +20,7 @@
#include "SwitchEnumBuilder.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/Basic/ProfileCounter.h"
+#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/SILArgument.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -79,6 +80,14 @@
llvm_unreachable("bad function section");
}
+SILBasicBlock *
+SILGenFunction::createBasicBlockAndBranch(SILLocation loc,
+ SILBasicBlock *destBB) {
+ auto *newBB = createBasicBlock();
+ SILGenBuilder(B, newBB).createBranch(loc, destBB);
+ return newBB;
+}
+
void SILGenFunction::eraseBasicBlock(SILBasicBlock *block) {
assert(block->pred_empty() && "erasing block with predecessors");
assert(block->empty() && "erasing block with content");
@@ -89,6 +98,76 @@
block->eraseFromParent();
}
+// Merge blocks during a single traversal of the block list. Only unconditional
+// branch edges are visited. Consequently, this takes only as much time as a
+// linked list traversal and requires no additional storage.
+//
+// For each block, check if it can be merged with its successor. Place the
+// merged block at the successor position in the block list.
+//
+// Typically, the successor occurs later in the list. This is most efficient
+// because merging moves instructions from the successor to the
+// predecessor. This way, instructions will only be moved once. Furthermore, the
+// merged block will be visited again to determine if it can be merged with it's
+// successor, and so on, so no edges are skipped.
+//
+// In rare cases, the predessor is merged with its earlier successor, which has
+// already been visited. If the successor can also be merged, then it has
+// already happened, and there is no need to revisit the merged block.
+void SILGenFunction::mergeCleanupBlocks() {
+ for (auto bbPos = F.begin(), bbEnd = F.end(), nextPos = bbPos; bbPos != bbEnd;
+ bbPos = nextPos) {
+ // A forward iterator refering to the next unprocessed block in the block
+ // list. If blocks are merged and moved, then this will be updated.
+ nextPos = std::next(bbPos);
+
+ // Consider the current block as the predecessor.
+ auto *predBB = &*bbPos;
+ auto *BI = dyn_cast<BranchInst>(predBB->getTerminator());
+ if (!BI)
+ continue;
+
+ // predBB has an unconditional branch to succBB. If succBB has no other
+ // predecessors, then merge the blocks.
+ auto *succBB = BI->getDestBB();
+ if (!succBB->getSinglePredecessorBlock())
+ continue;
+
+ // Before merging, establish iterators that won't be invalidated by erasing
+ // succBB. Use a reverse iterator to remember the position before a block.
+ //
+ // Remember the block before the current successor as a position for placing
+ // the merged block.
+ auto beforeSucc = std::next(SILFunction::reverse_iterator(succBB));
+
+ // Remember the position before the current predecessor to avoid skipping
+ // blocks or revisiting blocks unnecessarilly.
+ auto beforePred = std::next(SILFunction::reverse_iterator(predBB));
+ // Since succBB will be erased, move before it.
+ if (beforePred == SILFunction::reverse_iterator(succBB))
+ ++beforePred;
+
+ // Merge `predBB` with `succBB`. This erases `succBB`.
+ mergeBasicBlockWithSingleSuccessor(predBB, succBB);
+
+ // If predBB is first in the list, then it must be the entry block which
+ // cannot be moved.
+ if (beforePred != F.rend()) {
+ // Move the merged block into the successor position. (If the blocks are
+ // not already adjacent, then the first is typically the trampoline.)
+ assert(beforeSucc != F.rend()
+ && "entry block cannot have a predecessor.");
+ predBB->moveAfter(&*beforeSucc);
+ }
+ // If after moving predBB there are no more blocks to process, then break.
+ if (beforePred == F.rbegin())
+ break;
+
+ // Update the loop iterator to the next unprocessed block.
+ nextPos = SILFunction::iterator(&*std::prev(beforePred));
+ }
+}
+
//===----------------------------------------------------------------------===//
// SILGenFunction emitStmt implementation
//===----------------------------------------------------------------------===//
@@ -146,8 +225,7 @@
SGF.B.emitBlock(BB, BranchLoc);
}
-Condition SILGenFunction::emitCondition(Expr *E, bool hasFalseCode,
- bool invertValue,
+Condition SILGenFunction::emitCondition(Expr *E, bool invertValue,
ArrayRef<SILType> contArgs,
ProfileCounter NumTrueTaken,
ProfileCounter NumFalseTaken) {
@@ -162,12 +240,12 @@
}
assert(V->getType().castTo<BuiltinIntegerType>()->isFixedWidth(1));
- return emitCondition(V, E, hasFalseCode, invertValue, contArgs, NumTrueTaken,
+ return emitCondition(V, E, invertValue, contArgs, NumTrueTaken,
NumFalseTaken);
}
Condition SILGenFunction::emitCondition(SILValue V, SILLocation Loc,
- bool hasFalseCode, bool invertValue,
+ bool invertValue,
ArrayRef<SILType> contArgs,
ProfileCounter NumTrueTaken,
ProfileCounter NumFalseTaken) {
@@ -179,23 +257,14 @@
for (SILType argTy : contArgs) {
ContBB->createPhiArgument(argTy, ValueOwnershipKind::Owned);
}
-
- SILBasicBlock *FalseBB, *FalseDestBB;
- if (hasFalseCode) {
- FalseBB = FalseDestBB = createBasicBlock();
- } else {
- FalseBB = nullptr;
- FalseDestBB = ContBB;
- }
+ SILBasicBlock *FalseBB = createBasicBlock();
SILBasicBlock *TrueBB = createBasicBlock();
if (invertValue)
- B.createCondBranch(Loc, V, FalseDestBB, TrueBB, NumFalseTaken,
- NumTrueTaken);
+ B.createCondBranch(Loc, V, FalseBB, TrueBB, NumFalseTaken, NumTrueTaken);
else
- B.createCondBranch(Loc, V, TrueBB, FalseDestBB, NumTrueTaken,
- NumFalseTaken);
+ B.createCondBranch(Loc, V, TrueBB, FalseBB, NumTrueTaken, NumFalseTaken);
return Condition(TrueBB, FalseBB, ContBB, Loc);
}
@@ -507,8 +576,7 @@
void StmtEmitter::visitIfStmt(IfStmt *S) {
Scope condBufferScope(SGF.Cleanups, S);
- // Create a continuation block. We need it if there is a labeled break out
- // of the if statement or if there is an if/then/else.
+ // Create a continuation block.
JumpDest contDest = createJumpDest(S->getThenStmt());
auto contBB = contDest.getBlock();
@@ -774,7 +842,7 @@
// to the continuation block.
auto NumTrueTaken = SGF.loadProfilerCount(S->getBody());
auto NumFalseTaken = SGF.loadProfilerCount(S);
- Condition Cond = SGF.emitCondition(S->getCond(), /*hasFalseCode*/ false,
+ Condition Cond = SGF.emitCondition(S->getCond(),
/*invertValue*/ false, /*contArgs*/ {},
NumTrueTaken, NumFalseTaken);
@@ -881,8 +949,7 @@
// condition.
// If it fails, loop around as if 'continue' happened.
if (auto *Where = S->getWhere()) {
- auto cond =
- SGF.emitCondition(Where, /*hasFalse*/ false, /*invert*/ true);
+ auto cond = SGF.emitCondition(Where, /*invert*/ true);
// If self is null, branch to the epilog.
cond.enterTrue(SGF);
SGF.Cleanups.emitBranchAndCleanups(loopDest, Where, {});
diff --git a/lib/SILOptimizer/Utils/CFG.cpp b/lib/SILOptimizer/Utils/CFG.cpp
index b59b1de..e72a947 100644
--- a/lib/SILOptimizer/Utils/CFG.cpp
+++ b/lib/SILOptimizer/Utils/CFG.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/Dominance.h"
#include "swift/SIL/LoopInfo.h"
#include "swift/SIL/SILArgument.h"
@@ -740,16 +741,6 @@
if (BB == SuccBB || !SuccBB->getSinglePredecessorBlock())
return false;
- // If there are any BB arguments in the destination, replace them with the
- // branch operands, since they must dominate the dest block.
- for (unsigned i = 0, e = Branch->getArgs().size(); i != e; ++i)
- SuccBB->getArgument(i)->replaceAllUsesWith(Branch->getArg(i));
-
- Branch->eraseFromParent();
-
- // Move the instruction from the successor block to the current block.
- BB->spliceAtEnd(SuccBB);
-
if (DT)
if (auto *SuccBBNode = DT->getNode(SuccBB)) {
// Change the immediate dominator for children of the successor to be the
@@ -766,7 +757,7 @@
if (LI)
LI->removeBlock(SuccBB);
- SuccBB->eraseFromParent();
+ mergeBasicBlockWithSingleSuccessor(BB, SuccBB);
return true;
}
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index d0ae002..65f1bf3 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -411,6 +411,10 @@
BasicBlockMap.clear();
// Assign a value ID to each SILInstruction that has value and to each basic
// block argument.
+ //
+ // FIXME: Add reverse iteration to SILSuccessor and convert this to a "stable"
+ // RPO order. Currently, the serializer inverts the order of successors each
+ // time they are processed.
unsigned ValueID = 0;
llvm::ReversePostOrderTraversal<SILFunction *> RPOT(
const_cast<SILFunction *>(&F));
diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift
index b52c1f7..31f7697 100644
--- a/test/IRGen/enum_resilience.swift
+++ b/test/IRGen/enum_resilience.swift
@@ -221,14 +221,11 @@
// CHECK: br label %[[END]]
// CHECK: ; <label>:[[DEFAULT_CASE]]
-// CHECK: br label %[[DEFAULT_CASE_DESTROY:.*]]
-
-// CHECK: <label>:[[DEFAULT_CASE_DESTROY]]
// CHeCK: call void %destroy
// CHECK: br label %[[END]]
// CHECK: ; <label>:[[END]]
-// CHECK: = phi [[INT]] [ 3, %[[DEFAULT_CASE_DESTROY]] ], [ {{.*}}, %[[PAMPHLET_CASE_LABEL]] ], [ 2, %[[CANVAS_CASE_LABEL]] ], [ 1, %[[PAPER_CASE_LABEL]] ]
+// CHECK: = phi [[INT]] [ 3, %[[DEFAULT_CASE]] ], [ {{.*}}, %[[PAMPHLET_CASE_LABEL]] ], [ 2, %[[CANVAS_CASE_LABEL]] ], [ 1, %[[PAPER_CASE_LABEL]] ]
// CHECK: ret
public func resilientSwitchTest(_ m: Medium) -> Int {
diff --git a/test/SILGen/auto_generated_super_init_call.swift b/test/SILGen/auto_generated_super_init_call.swift
index a3471d3..34a21a0 100644
--- a/test/SILGen/auto_generated_super_init_call.swift
+++ b/test/SILGen/auto_generated_super_init_call.swift
@@ -40,7 +40,7 @@
// Check that we are emitting the super.init expr into the epilog block.
// CHECK-LABEL: sil hidden @$s30auto_generated_super_init_call16SomeDerivedClassC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Bool, @owned SomeDerivedClass) -> @owned SomeDerivedClass
-// CHECK: bb4:
+// CHECK: bb5:
// SEMANTIC ARC TODO: Another case of needing a mutable load_borrow.
// CHECK-NEXT: [[SELFLOAD:%[0-9]+]] = load [take] [[SELF:%[0-9]+]] : $*SomeDerivedClass
// CHECK-NEXT: [[SELFLOAD_PARENT_CAST:%.*]] = upcast [[SELFLOAD]]
diff --git a/test/SILGen/errors.swift b/test/SILGen/errors.swift
index f2f67f8..548b19e 100644
--- a/test/SILGen/errors.swift
+++ b/test/SILGen/errors.swift
@@ -694,12 +694,10 @@
// CHECK-NEXT: destroy_value [[RESULT]] : $Optional<Cat>
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
// CHECK-NEXT: return [[VOID]] : $()
-// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : @owned $Error):
+// CHECK: [[CLEANUPS:.+]]([[ERROR:%.*]] : @owned $Error):
// CHECK-NEXT: destroy_value [[ERROR]]
// CHECK-NEXT: [[NONE:%.+]] = enum $Optional<Cat>, #Optional.none!enumelt
// CHECK-NEXT: br [[DONE]]([[NONE]] : $Optional<Cat>)
-// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $Error):
-// CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $Error)
// CHECK: } // end sil function '$s6errors15testOptionalTryyyF'
func testOptionalTry() {
_ = try? make_a_cat()
@@ -729,12 +727,10 @@
// CHECK-NEXT: destroy_value [[BOX]] : ${ var Optional<Cat> }
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
// CHECK-NEXT: return [[VOID]] : $()
-// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : @owned $Error):
+// CHECK: [[CLEANUPS:.+]]([[ERROR:%.*]] : @owned $Error):
// CHECK-NEXT: destroy_value [[ERROR]]
// CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional<Cat>, #Optional.none!enumelt
// CHECK-NEXT: br [[DONE]]
-// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $Error):
-// CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $Error)
// CHECK: } // end sil function '$s6errors18testOptionalTryVaryyF'
func testOptionalTryVar() {
var cat = try? make_a_cat() // expected-warning {{initialization of variable 'cat' was never used; consider replacing with assignment to '_' or removing it}}
@@ -755,12 +751,10 @@
// CHECK-NOT: destroy_addr %0 : $*T
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
// CHECK-NEXT: return [[VOID]] : $()
-// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : @owned $Error):
+// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $Error):
// CHECK-NEXT: destroy_value [[ERROR]]
// CHECK-NEXT: inject_enum_addr [[BOX]] : $*Optional<T>, #Optional.none!enumelt
// CHECK-NEXT: br [[DONE]]
-// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $Error):
-// CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $Error)
// CHECK: } // end sil function '$s6errors26testOptionalTryAddressOnlyyyxlF'
func testOptionalTryAddressOnly<T>(_ obj: T) {
_ = try? dont_return(obj)
@@ -781,12 +775,10 @@
// CHECK-NOT: destroy_addr %0 : $*T
// CHECK-NEXT: [[VOID:%.+]] = tuple ()
// CHECK-NEXT: return [[VOID]] : $()
-// CHECK: [[FAILURE:.+]]([[ERROR:%.*]] : @owned $Error):
+// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $Error):
// CHECK-NEXT: destroy_value [[ERROR]]
// CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional<T>, #Optional.none!enumelt
// CHECK-NEXT: br [[DONE]]
-// CHECK: [[CLEANUPS]]([[ERROR:%.+]] : @owned $Error):
-// CHECK-NEXT: br [[FAILURE]]([[ERROR]] : $Error)
// CHECK: } // end sil function '$s6errors29testOptionalTryAddressOnlyVaryyxlF'
func testOptionalTryAddressOnlyVar<T>(_ obj: T) {
var copy = try? dont_return(obj) // expected-warning {{initialization of variable 'copy' was never used; consider replacing with assignment to '_' or removing it}}
diff --git a/test/SILGen/force_cast_chained_optional.swift b/test/SILGen/force_cast_chained_optional.swift
index 96317ce..7487cef 100644
--- a/test/SILGen/force_cast_chained_optional.swift
+++ b/test/SILGen/force_cast_chained_optional.swift
@@ -18,9 +18,6 @@
// CHECK: select_enum_addr {{%.*}}
// CHECK: cond_br {{%.*}}, [[SOME_BAR:bb[0-9]+]], [[NO_BAR:bb[0-9]+]]
//
-// CHECK: [[NO_BAR]]:
-// CHECK: br [[TRAP:bb[0-9]+]]
-//
// CHECK: [[SOME_BAR]]:
// CHECK: [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr {{%.*}} : $*Optional<Bar>
// CHECK: [[BAR:%.*]] = load [copy] [[PAYLOAD_ADDR]]
@@ -30,7 +27,7 @@
// CHECK: end_borrow [[BORROWED_BAR]]
// CHECK: unconditional_checked_cast {{%.*}} : $C to $D
//
-// CHECK: [[TRAP]]:
+// CHECK: [[NO_BAR]]:
// CHECK: unreachable
func test(_ x: Foo) -> D {
return x.bar?.bas as! D
diff --git a/test/SILGen/foreach.swift b/test/SILGen/foreach.swift
index 716e51f..789534e 100644
--- a/test/SILGen/foreach.swift
+++ b/test/SILGen/foreach.swift
@@ -59,15 +59,12 @@
// CHECK: [[LOOP_DEST]]:
// CHECK: switch_enum [[IND_VAR:%.*]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
-// CHECK: [[NONE_BB]]:
-// CHECK: br [[CONT_BLOCK:bb[0-9]+]]
-//
// CHECK: [[SOME_BB]]([[VAR:%.*]] : @trivial $Int):
// CHECK: [[LOOP_END_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
// CHECK: apply [[LOOP_END_FUNC]]()
// CHECK: br [[LOOP_DEST]]
//
-// CHECK: [[CONT_BLOCK]]:
+// CHECK: [[NONE_BB]]:
// CHECK: destroy_value [[ITERATOR_BOX]]
// CHECK: [[FUNC_END_FUNC:%.*]] = function_ref @funcEnd : $@convention(thin) () -> ()
// CHECK: apply [[FUNC_END_FUNC]]()
@@ -123,9 +120,6 @@
// CHECK: [[IND_VAR:%.*]] = load [trivial] [[GET_ELT_STACK]]
// CHECK: switch_enum [[IND_VAR]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
-// CHECK: [[NONE_BB]]:
-// CHECK: br [[CONT_BLOCK_JUMP:bb[0-9]+]]
-//
// CHECK: [[SOME_BB]]([[VAR:%.*]] : @trivial $Int):
// CHECK: cond_br {{%.*}}, [[LOOP_BREAK_END_BLOCK:bb[0-9]+]], [[CONTINUE_CHECK_BLOCK:bb[0-9]+]]
//
@@ -147,7 +141,7 @@
// CHECK: apply [[LOOP_BODY_FUNC]]()
// CHECK: br [[LOOP_DEST]]
//
-// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK: [[NONE_BB]]:
// CHECK: br [[CONT_BLOCK]]
//
// CHECK: [[CONT_BLOCK]]
@@ -225,9 +219,6 @@
// CHECK: apply [[FUNC_REF]]<[P]>([[ELT_STACK]], [[WRITE]])
// CHECK: switch_enum_addr [[ELT_STACK]] : $*Optional<P>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
-// CHECK: [[NONE_BB]]:
-// CHECK: br [[CONT_BLOCK_JUMP:bb[0-9]+]]
-//
// CHECK: [[SOME_BB]]:
// CHECK: [[T0:%.*]] = alloc_stack $P, let, name "x"
// CHECK: [[ELT_STACK_TAKE:%.*]] = unchecked_take_enum_data_addr [[ELT_STACK]] : $*Optional<P>, #Optional.some!enumelt.1
@@ -258,7 +249,7 @@
// CHECK: dealloc_stack [[T0]]
// CHECK: br [[LOOP_DEST]]
//
-// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK: [[NONE_BB]]:
// CHECK: br [[CONT_BLOCK]]
//
// CHECK: [[CONT_BLOCK]]
@@ -388,9 +379,6 @@
// CHECK: apply [[FUNC_REF]]<[GenericStruct<T>]>([[ELT_STACK]], [[WRITE]])
// CHECK: switch_enum_addr [[ELT_STACK]] : $*Optional<GenericStruct<T>>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
-// CHECK: [[NONE_BB]]:
-// CHECK: br [[CONT_BLOCK_JUMP:bb[0-9]+]]
-//
// CHECK: [[SOME_BB]]:
// CHECK: [[T0:%.*]] = alloc_stack $GenericStruct<T>, let, name "x"
// CHECK: [[ELT_STACK_TAKE:%.*]] = unchecked_take_enum_data_addr [[ELT_STACK]] : $*Optional<GenericStruct<T>>, #Optional.some!enumelt.1
@@ -421,7 +409,7 @@
// CHECK: dealloc_stack [[T0]]
// CHECK: br [[LOOP_DEST]]
//
-// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK: [[NONE_BB]]:
// CHECK: br [[CONT_BLOCK]]
//
// CHECK: [[CONT_BLOCK]]
@@ -497,9 +485,6 @@
// CHECK: apply [[GET_NEXT_FUNC]]<T.Iterator>([[ELT_STACK]], [[WRITE]])
// CHECK: switch_enum_addr [[ELT_STACK]] : $*Optional<T.Element>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
-// CHECK: [[NONE_BB]]:
-// CHECK: br [[CONT_BLOCK_JUMP:bb[0-9]+]]
-//
// CHECK: [[SOME_BB]]:
// CHECK: [[T0:%.*]] = alloc_stack $T.Element, let, name "x"
// CHECK: [[ELT_STACK_TAKE:%.*]] = unchecked_take_enum_data_addr [[ELT_STACK]] : $*Optional<T.Element>, #Optional.some!enumelt.1
@@ -530,7 +515,7 @@
// CHECK: dealloc_stack [[T0]]
// CHECK: br [[LOOP_DEST]]
//
-// CHECK: [[CONT_BLOCK_JUMP]]:
+// CHECK: [[NONE_BB]]:
// CHECK: br [[CONT_BLOCK]]
//
// CHECK: [[CONT_BLOCK]]
@@ -562,27 +547,27 @@
// CHECK-LABEL: sil hidden @$s7foreach13tupleElementsyySayAA1CC_ADtGF
func tupleElements(_ xx: [(C, C)]) {
- // CHECK: bb3([[PAYLOAD:%.*]] : @owned $(C, C)):
+ // CHECK: bb{{.*}}([[PAYLOAD:%.*]] : @owned $(C, C)):
// CHECK: ([[A:%.*]], [[B:%.*]]) = destructure_tuple [[PAYLOAD]]
// CHECK: destroy_value [[B]]
// CHECK: destroy_value [[A]]
for (a, b) in xx {}
- // CHECK: bb7([[PAYLOAD:%.*]] : @owned $(C, C)):
+ // CHECK: bb{{.*}}([[PAYLOAD:%.*]] : @owned $(C, C)):
// CHECK: ([[A:%.*]], [[B:%.*]]) = destructure_tuple [[PAYLOAD]]
// CHECK: destroy_value [[B]]
// CHECK: destroy_value [[A]]
for (a, _) in xx {}
- // CHECK: bb11([[PAYLOAD:%.*]] : @owned $(C, C)):
+ // CHECK: bb{{.*}}([[PAYLOAD:%.*]] : @owned $(C, C)):
// CHECK: ([[A:%.*]], [[B:%.*]]) = destructure_tuple [[PAYLOAD]]
// CHECK: destroy_value [[A]]
// CHECK: destroy_value [[B]]
for (_, b) in xx {}
- // CHECK: bb15([[PAYLOAD:%.*]] : @owned $(C, C)):
+ // CHECK: bb{{.*}}([[PAYLOAD:%.*]] : @owned $(C, C)):
// CHECK: ([[A:%.*]], [[B:%.*]]) = destructure_tuple [[PAYLOAD]]
// CHECK: destroy_value [[B]]
// CHECK: destroy_value [[A]]
for (_, _) in xx {}
- // CHECK: bb19([[PAYLOAD:%.*]] : @owned $(C, C)):
+ // CHECK: bb{{.*}}([[PAYLOAD:%.*]] : @owned $(C, C)):
// CHECK: ([[A:%.*]], [[B:%.*]]) = destructure_tuple [[PAYLOAD]]
// CHECK: destroy_value [[B]]
// CHECK: destroy_value [[A]]
@@ -599,9 +584,6 @@
// CHECK: [[LOOP_DEST]]:
// CHECK: switch_enum [[OPT_VAL:%.*]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
-// CHECK: [[NONE_BB]]:
-// CHECK: br [[CONT_BB:bb[0-9]+]]
-//
// CHECK: [[SOME_BB]]([[VAL:%.*]] : @trivial $Int):
// CHECK: [[LOOP_END_FUNC:%.*]] = function_ref @loopBodyEnd : $@convention(thin) () -> ()
// CHECK: apply [[LOOP_END_FUNC]]
diff --git a/test/SILGen/if_while_binding.swift b/test/SILGen/if_while_binding.swift
index 346c544..65db13d 100644
--- a/test/SILGen/if_while_binding.swift
+++ b/test/SILGen/if_while_binding.swift
@@ -42,9 +42,6 @@
// CHECK-NEXT: [[OPT_RES:%.*]] = apply [[FOO]]()
// CHECK-NEXT: switch_enum [[OPT_RES]] : $Optional<String>, case #Optional.some!enumelt.1: [[YESX:bb[0-9]+]], case #Optional.none!enumelt: [[NOX:bb[0-9]+]]
if let x = foo() {
- // CHECK: [[NOX]]:
- // CHECK: br [[FAILURE_DESTX:bb[0-9]+]]
- //
// CHECK: [[YESX]]([[VAL:%[0-9]+]] : @owned $String):
// CHECK: debug_value [[VAL]] : $String, let, name "x"
// CHECK: [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]]
@@ -55,26 +52,22 @@
// CHECK: br [[CONT_X:bb[0-9]+]]
a(x)
//
- // CHECK: [[FAILURE_DESTX]]:
+ // CHECK: [[NOX]]:
// CHECK: alloc_box ${ var String }, var, name "y"
- // CHECK: switch_enum {{.*}} : $Optional<String>, case #Optional.some!enumelt.1: [[YESY:bb[0-9]+]], case #Optional.none!enumelt: [[ELSE1:bb[0-9]+]]
- // CHECK: [[ELSE1]]:
- // CHECK: dealloc_box {{.*}} ${ var String }
- // CHECK: br [[ELSE:bb[0-9]+]]
+ // CHECK: switch_enum {{.*}} : $Optional<String>, case #Optional.some!enumelt.1: [[YESY:bb[0-9]+]], case #Optional.none!enumelt: [[ELSE:bb[0-9]+]]
} else if var y = bar() {
// CHECK: [[YESY]]([[VAL:%[0-9]+]] : @owned $String):
// CHECK: br [[CONT_Y:bb[0-9]+]]
- // CHECK: [[CONT_Y]]:
- // CHECK: br [[CONT_Y2:bb[0-9]+]]
b(y)
} else {
// CHECK: [[ELSE]]:
- // CHECK: function_ref if_while_binding.c
+ // CHECK: dealloc_box {{.*}} ${ var String }
+ // CHECK: function_ref if_while_binding.c
c("")
- // CHECK: br [[CONT_Y2]]
+ // CHECK: br [[CONT_Y]]
}
- // CHECK: [[CONT_Y2]]:
+ // CHECK: [[CONT_Y]]:
// br [[CONT_X]]
// CHECK: [[CONT_X]]:
}
@@ -90,10 +83,7 @@
// CHECK: br [[LOOP_EXIT:bb[0-9]+]]
while let x = foo() {
// CHECK: [[LOOP_BODY]]([[X:%[0-9]+]] : @owned $String):
- // CHECK: switch_enum {{.*}} : $Optional<String>, case #Optional.some!enumelt.1: [[YES:bb[0-9]+]], case #Optional.none!enumelt: [[NO_TRAMPOLINE_2:bb[0-9]+]]
- //
- // CHECK: [[NO_TRAMPOLINE_2]]:
- // CHECK: br [[FAILURE_DEST_2:bb[0-9]+]]
+ // CHECK: switch_enum {{.*}} : $Optional<String>, case #Optional.some!enumelt.1: [[YES:bb[0-9]+]], case #Optional.none!enumelt: [[FAILURE_DEST_2:bb[0-9]+]]
if let y = bar() {
// CHECK: [[YES]]([[Y:%[0-9]+]] : @owned $String):
a(y)
@@ -119,17 +109,15 @@
// CHECK: [[X:%.*]] = alloc_stack $T, let, name "x"
// CHECK: [[OPTBUF:%[0-9]+]] = alloc_stack $Optional<T>
// CHECK: switch_enum_addr {{.*}}, case #Optional.some!enumelt.1: [[LOOPBODY:bb.*]], case #Optional.none!enumelt: [[OUT:bb[0-9]+]]
-// CHECK: [[OUT]]:
-// CHECK: dealloc_stack [[OPTBUF]]
-// CHECK: dealloc_stack [[X]]
-// CHECK: br [[DONE:bb[0-9]+]]
// CHECK: [[LOOPBODY]]:
// CHECK: [[ENUMVAL:%.*]] = unchecked_take_enum_data_addr
// CHECK: copy_addr [take] [[ENUMVAL]] to [initialization] [[X]]
// CHECK: destroy_addr [[X]]
// CHECK: dealloc_stack [[X]]
// CHECK: br [[COND]]
-// CHECK: [[DONE]]:
+// CHECK: [[OUT]]:
+// CHECK: dealloc_stack [[OPTBUF]]
+// CHECK: dealloc_stack [[X]]
// CHECK: return
// CHECK: } // end sil function '$s16if_while_binding0B13_loop_generic{{[_0-9a-zA-Z]*}}F'
func while_loop_generic<T>(_ source: () -> T?) {
@@ -247,7 +235,7 @@
// CHECK: switch_enum {{.*}}, case #Optional.some!enumelt.1: [[CHECKBUF2:bb.*]], case #Optional.none!enumelt: [[NONE_TRAMPOLINE:bb[0-9]+]]
//
// CHECK: [[NONE_TRAMPOLINE]]:
- // CHECK: br [[ELSE:bb[0-9]+]]
+ // CHECK: br [[DONE:bb[0-9]+]]
// CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : @owned $String):
// CHECK: debug_value [[A]] : $String, let, name "a"
// CHECK: [[BBOX:%[0-9]+]] = alloc_box ${ var String }, var, name "b"
@@ -256,23 +244,23 @@
// CHECK: [[IF_EXIT1a]]:
// CHECK: dealloc_box {{.*}} ${ var String }
// CHECK: destroy_value [[A]]
- // CHECK: br [[ELSE]]
+ // CHECK: br [[DONE]]
// CHECK: [[CHECK_WHERE]]([[B:%[0-9]+]] : @owned $String):
// CHECK: function_ref Swift.Bool._getBuiltinLogicValue() -> Builtin.Int1
// CHECK: cond_br {{.*}}, [[IF_BODY:bb[0-9]+]], [[IF_EXIT3:bb[0-9]+]]
- // CHECK: [[IF_EXIT3]]:
- // CHECK: destroy_value [[BBOX]]
- // CHECK: destroy_value [[A]]
- // CHECK: br [[IF_DONE:bb[0-9]+]]
if let a = foo(), var b = bar(), a == b {
// CHECK: [[IF_BODY]]:
// CHECK: destroy_value [[BBOX]]
// CHECK: destroy_value [[A]]
- // CHECK: br [[IF_DONE]]
+ // CHECK: br [[DONE]]
let c = a
}
- // CHECK: [[IF_DONE]]:
+ // CHECK: [[IF_EXIT3]]:
+ // CHECK: destroy_value [[BBOX]]
+ // CHECK: destroy_value [[A]]
+ // CHECK: br [[DONE]]
+ // CHECK: [[DONE]]:
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
}
@@ -288,13 +276,13 @@
// CHECK: [[FN:%.*]] = function_ref {{.*}}
// CHECK-NEXT: [[EQRESULTI1:%[0-9]+]] = apply [[FN:%.*]]([[EQRESULT]]) : $@convention(method) (Bool) -> Builtin.Int1
- // CHECK-NEXT: cond_br [[EQRESULTI1]], [[CHECKFOO:bb[0-9]+]], [[IFDONE:bb[0-9]+]]
+ // CHECK-NEXT: cond_br [[EQRESULTI1]], [[CHECKFOO:bb[0-9]+]], [[ELSE:bb[0-9]+]]
// Call Foo and test for the optional being present.
// CHECK: [[CHECKFOO]]:
// CHECK: [[OPTRESULT:%[0-9]+]] = apply {{.*}}() : $@convention(thin) () -> @owned Optional<String>
- // CHECK: switch_enum [[OPTRESULT]] : $Optional<String>, case #Optional.some!enumelt.1: [[SUCCESS:bb.*]], case #Optional.none!enumelt: [[IF_DONE:bb[0-9]+]]
+ // CHECK: switch_enum [[OPTRESULT]] : $Optional<String>, case #Optional.some!enumelt.1: [[SUCCESS:bb.*]], case #Optional.none!enumelt: [[IFDONE:bb[0-9]+]]
// CHECK: [[SUCCESS]]([[B:%[0-9]+]] : @owned $String):
// CHECK: debug_value [[B]] : $String, let, name "b"
@@ -304,10 +292,12 @@
// CHECK: end_borrow [[BORROWED_B]]
// CHECK: destroy_value [[B_COPY]]
// CHECK: destroy_value [[B]]
- // CHECK: br [[IFDONE]]
+ // CHECK: br [[IFDONE:bb[0-9]+]]
if a == a, let b = foo() {
let c = b
}
+ // CHECK: [[ELSE]]:
+ // CHECK: br [[IFDONE]]
// CHECK: [[IFDONE]]:
// CHECK-NEXT: tuple ()
@@ -368,11 +358,11 @@
//
// CHECK: [[SOME_BB]]([[PAYLOAD:%.*]] : @trivial $Bool):
// CHECK: [[ISTRUE:%[0-9]+]] = struct_extract [[PAYLOAD]] : $Bool, #Bool._value
- // CHECK: cond_br [[ISTRUE]], [[TRUE_TRAMPOLINE_BB:bb[0-9]+]], [[CONT_BB]]
- //
- // CHECK: [[TRUE_TRAMPOLINE_BB:bb[0-9]+]]
- // CHECK: br [[TRUE_BB:bb[0-9]+]]
- //
+ // CHECK: cond_br [[ISTRUE]], [[TRUE_BB:bb[0-9]+]], [[FALSE_TRAMPOLINE:bb[0-9]+]]
+
+ // CHECK: [[FALSE_TRAMPOLINE]]:
+ // CHECK: br [[CONT_BB]]
+
// CHECK: [[TRUE_BB]]:
// CHECK: function_ref @$s16if_while_binding8marker_1yyF
// CHECK: br [[CONT_BB]]
@@ -388,10 +378,10 @@
// CHECK: [[SUCC_BB_2]]([[PAYLOAD2:%.*]] : @trivial $Bool):
// CHECK: [[ISTRUE:%[0-9]+]] = struct_extract [[PAYLOAD2]] : $Bool, #Bool._value
- // CHECK: cond_br [[ISTRUE]], [[EPILOG_BB]], [[FALSE2_TRAMPOLINE_BB:bb[0-9]+]]
+ // CHECK: cond_br [[ISTRUE]], [[TRUE3_BB:bb[0-9]+]], [[FALSE2_BB:bb[0-9]+]]
- // CHECK: [[FALSE2_TRAMPOLINE_BB]]:
- // CHECK: br [[FALSE2_BB:bb[0-9]+]]
+ // CHECK: [[TRUE3_BB]]:
+ // CHECK: br [[EPILOG_BB:bb[0-9]+]]
//
// CHECK: [[FALSE2_BB]]:
// CHECK: function_ref @$s16if_while_binding8marker_2yyF
diff --git a/test/SILGen/implicitly_unwrapped_optional.swift b/test/SILGen/implicitly_unwrapped_optional.swift
index da73905..2a86827 100644
--- a/test/SILGen/implicitly_unwrapped_optional.swift
+++ b/test/SILGen/implicitly_unwrapped_optional.swift
@@ -13,24 +13,24 @@
// CHECK: store [[T0_COPY]] to [init] [[PF]]
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PF]] : $*Optional<@callee_guaranteed () -> ()>
// CHECK: [[HASVALUE:%.*]] = select_enum_addr [[READ]]
-// CHECK: cond_br [[HASVALUE]], bb2, bb1
+// CHECK: cond_br [[HASVALUE]], bb1, bb3
//
// If it does, project and load the value out of the implicitly unwrapped
// optional...
-// CHECK: bb2:
+// CHECK: bb1:
// CHECK-NEXT: [[FN0_ADDR:%.*]] = unchecked_take_enum_data_addr [[READ]]
// CHECK-NEXT: [[FN0:%.*]] = load [copy] [[FN0_ADDR]]
// .... then call it
// CHECK: [[B:%.*]] = begin_borrow [[FN0]]
// CHECK: apply [[B]]() : $@callee_guaranteed () -> ()
// CHECK: end_borrow [[B]]
-// CHECK: br bb3
-// CHECK: bb3(
+// CHECK: br bb2
+// CHECK: bb2(
// CHECK: destroy_value [[F]]
// CHECK: return
-// CHECK: bb4:
+// CHECK: bb3:
// CHECK: enum $Optional<()>, #Optional.none!enumelt
-// CHECK: br bb3
+// CHECK: br bb2
// The rest of this is tested in optional.swift
// } // end sil function '{{.*}}foo{{.*}}'
diff --git a/test/SILGen/indirect_enum.swift b/test/SILGen/indirect_enum.swift
index 4f2556c..e7615f1 100644
--- a/test/SILGen/indirect_enum.swift
+++ b/test/SILGen/indirect_enum.swift
@@ -335,17 +335,13 @@
// CHECK: bb0([[ARG:%.*]] : @guaranteed $TreeA<T>):
do {
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
- // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
- // CHECK: destroy_value [[ORIGINAL_VALUE]]
+ // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO1:bb[0-9]+]]
// CHECK: [[YES]]:
guard case .Nil = tree else { return }
// CHECK: [[X:%.*]] = alloc_stack $T
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
- // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
- // CHECK: destroy_value [[ORIGINAL_VALUE]]
+ // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO2:bb[0-9]+]]
// CHECK: [[YES]]([[BOX:%.*]] : @owned $<τ_0_0> { var τ_0_0 } <T>):
// CHECK: [[VALUE_ADDR:%.*]] = project_box [[BOX]]
// CHECK: [[TMP:%.*]] = alloc_stack
@@ -355,9 +351,7 @@
guard case .Leaf(let x) = tree else { return }
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
- // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
- // CHECK: destroy_value [[ORIGINAL_VALUE]]
+ // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO3:bb[0-9]+]]
// CHECK: [[YES]]([[BOX:%.*]] : @owned $<τ_0_0> { var (left: TreeA<τ_0_0>, right: TreeA<τ_0_0>) } <T>):
// CHECK: [[VALUE_ADDR:%.*]] = project_box [[BOX]]
// CHECK: [[TUPLE:%.*]] = load_borrow [[VALUE_ADDR]]
@@ -374,8 +368,8 @@
do {
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
- // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
+ // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO4:bb[0-9]+]]
+ // CHECK: [[NO4]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
// CHECK: destroy_value [[ORIGINAL_VALUE]]
// CHECK: [[YES]]:
// CHECK: br
@@ -383,8 +377,8 @@
// CHECK: [[X:%.*]] = alloc_stack $T
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
- // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
+ // CHECK: switch_enum [[ARG_COPY]] : $TreeA<T>, case #TreeA.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO5:bb[0-9]+]]
+ // CHECK: [[NO5]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
// CHECK: destroy_value [[ORIGINAL_VALUE]]
// CHECK: [[YES]]([[BOX:%.*]] : @owned $<τ_0_0> { var τ_0_0 } <T>):
// CHECK: [[VALUE_ADDR:%.*]] = project_box [[BOX]]
@@ -411,37 +405,37 @@
// CHECK: destroy_value [[L]]
if case .Branch(left: let l, right: let r) = tree { }
}
+ // CHECK: [[NO3]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
+ // CHECK: destroy_value [[ORIGINAL_VALUE]]
+ // CHECK: [[NO2]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
+ // CHECK: destroy_value [[ORIGINAL_VALUE]]
+ // CHECK: [[NO1]]([[ORIGINAL_VALUE:%.*]] : @owned $TreeA<T>):
+ // CHECK: destroy_value [[ORIGINAL_VALUE]]
}
// CHECK-LABEL: sil hidden @$s13indirect_enum10guardTreeB{{[_0-9a-zA-Z]*}}F
func guardTreeB<T>(_ tree: TreeB<T>) {
do {
- // CHECK: copy_addr %0 to [initialization] [[TMP:%.*]] :
- // CHECK: switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]:
- // CHECK: destroy_addr [[TMP]]
+ // CHECK: copy_addr %0 to [initialization] [[TMP1:%.*]] :
+ // CHECK: switch_enum_addr [[TMP1]] : $*TreeB<T>, case #TreeB.Nil!enumelt: [[YES:bb[0-9]+]], default [[NO2:bb[0-9]+]]
// CHECK: [[YES]]:
- // CHECK: destroy_addr [[TMP]]
+ // CHECK: destroy_addr [[TMP1]]
guard case .Nil = tree else { return }
// CHECK: [[X:%.*]] = alloc_stack $T
- // CHECK: copy_addr %0 to [initialization] [[TMP:%.*]] :
- // CHECK: switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]:
- // CHECK: destroy_addr [[TMP]]
+ // CHECK: copy_addr %0 to [initialization] [[TMP2:%.*]] :
+ // CHECK: switch_enum_addr [[TMP2]] : $*TreeB<T>, case #TreeB.Leaf!enumelt.1: [[YES:bb[0-9]+]], default [[NO2:bb[0-9]+]]
// CHECK: [[YES]]:
- // CHECK: [[VALUE:%.*]] = unchecked_take_enum_data_addr [[TMP]]
+ // CHECK: [[VALUE:%.*]] = unchecked_take_enum_data_addr [[TMP2]]
// CHECK: copy_addr [take] [[VALUE]] to [initialization] [[X]]
- // CHECK: dealloc_stack [[TMP]]
+ // CHECK: dealloc_stack [[TMP2]]
guard case .Leaf(let x) = tree else { return }
// CHECK: [[L:%.*]] = alloc_stack $TreeB
// CHECK: [[R:%.*]] = alloc_stack $TreeB
- // CHECK: copy_addr %0 to [initialization] [[TMP:%.*]] :
- // CHECK: switch_enum_addr [[TMP]] : $*TreeB<T>, case #TreeB.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]]
- // CHECK: [[NO]]:
- // CHECK: destroy_addr [[TMP]]
+ // CHECK: copy_addr %0 to [initialization] [[TMP3:%.*]] :
+ // CHECK: switch_enum_addr [[TMP3]] : $*TreeB<T>, case #TreeB.Branch!enumelt.1: [[YES:bb[0-9]+]], default [[NO3:bb[0-9]+]]
// CHECK: [[YES]]:
- // CHECK: [[BOX_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP]]
+ // CHECK: [[BOX_ADDR:%.*]] = unchecked_take_enum_data_addr [[TMP3]]
// CHECK: [[BOX:%.*]] = load [take] [[BOX_ADDR]]
// CHECK: [[TUPLE_ADDR:%.*]] = project_box [[BOX]]
// CHECK: copy_addr [[TUPLE_ADDR]] to [initialization] [[TUPLE_COPY:%.*]] :
@@ -498,6 +492,12 @@
// CHECK: destroy_addr [[L]]
if case .Branch(left: let l, right: let r) = tree { }
}
+ // CHECK: [[NO3]]:
+ // CHECK: destroy_addr [[TMP3]]
+ // CHECK: [[NO2]]:
+ // CHECK: destroy_addr [[TMP2]]
+ // CHECK: [[NO1]]:
+ // CHECK: destroy_addr [[TMP1]]
}
// Just run guardTreeInt through the ownership verifier
@@ -526,20 +526,21 @@
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: switch_enum [[ARG_COPY]] : $TrivialButIndirect, case #TrivialButIndirect.Direct!enumelt.1: [[YES:bb[0-9]+]], case #TrivialButIndirect.Indirect!enumelt.1: [[NO:bb[0-9]+]]
//
- // CHECK: [[NO]]([[PAYLOAD:%.*]] : @owned ${ var Int }):
- // CHECK: destroy_value [[PAYLOAD]]
guard case .Direct(let foo) = x else { return }
// CHECK: [[YES]]({{%.*}} : @trivial $Int):
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
- // CHECK: switch_enum [[ARG_COPY]] : $TrivialButIndirect, case #TrivialButIndirect.Indirect!enumelt.1: [[YES:bb[0-9]+]], case #TrivialButIndirect.Direct!enumelt.1: [[NO:bb[0-9]+]]
-
- // CHECK: [[NO]]({{%.*}} : @trivial $Int):
- // CHECK-NOT: destroy_value
+ // CHECK: switch_enum [[ARG_COPY]] : $TrivialButIndirect, case #TrivialButIndirect.Indirect!enumelt.1: [[YES:bb[0-9]+]], case #TrivialButIndirect.Direct!enumelt.1: [[NO2:bb[0-9]+]]
// CHECK: [[YES]]([[BOX:%.*]] : @owned ${ var Int }):
// CHECK: destroy_value [[BOX]]
+ // CHECK: [[NO2]]({{%.*}} : @trivial $Int):
+ // CHECK-NOT: destroy_value
+
+ // CHECK: [[NO]]([[PAYLOAD:%.*]] : @owned ${ var Int }):
+ // CHECK: destroy_value [[PAYLOAD]]
+
guard case .Indirect(let bar) = x else { return }
}
// CHECK: } // end sil function '$s13indirect_enum35dontDisableCleanupOfIndirectPayloadyyAA010TrivialButG0OF'
diff --git a/test/SILGen/objc_blocks_bridging.swift b/test/SILGen/objc_blocks_bridging.swift
index 8cbf438..1a7fe02 100644
--- a/test/SILGen/objc_blocks_bridging.swift
+++ b/test/SILGen/objc_blocks_bridging.swift
@@ -96,7 +96,7 @@
// CHECK-LABEL: sil hidden @$s20objc_blocks_bridging3FooC19optCFunctionPointer{{[_0-9a-zA-Z]*}}F
// CHECK: switch_enum %0
//
- // CHECK: bb2([[FP_BUF:%.*]] : @trivial $@convention(c) (NSString) -> @autoreleased NSString):
+ // CHECK: bb1([[FP_BUF:%.*]] : @trivial $@convention(c) (NSString) -> @autoreleased NSString):
@objc dynamic func optCFunctionPointer(_ fp: (@convention(c) (String) -> String)?, x: String) -> String? {
return fp?(x)
}
diff --git a/test/SILGen/objc_error.swift b/test/SILGen/objc_error.swift
index 1a67fc0..acbfce4 100644
--- a/test/SILGen/objc_error.swift
+++ b/test/SILGen/objc_error.swift
@@ -64,7 +64,7 @@
// CHECK: unconditional_checked_cast_addr AnyObject in {{%.*}} : $*AnyObject to NSError in {{%.*}} : $*NSError
let nsForcedCast = (e as AnyObject) as! NSError
- // CHECK: checked_cast_addr_br {{.*}} Error in {{%.*}} : $*Error to NSError in {{%.*}} : $*NSError, bb3, bb4
+ // CHECK: checked_cast_addr_br {{.*}} Error in {{%.*}} : $*Error to NSError in {{%.*}} : $*NSError, bb1, bb2
do {
throw e
} catch _ as NSError {
diff --git a/test/SILGen/optional-cast.swift b/test/SILGen/optional-cast.swift
index d3ba748..1519692 100644
--- a/test/SILGen/optional-cast.swift
+++ b/test/SILGen/optional-cast.swift
@@ -12,9 +12,6 @@
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: switch_enum [[ARG_COPY]] : $Optional<A>, case #Optional.some!enumelt.1: [[IS_PRESENT:bb[0-9]+]], case #Optional.none!enumelt: [[NOT_PRESENT:bb[0-9]+]]
//
-// CHECK: [[NOT_PRESENT]]:
-// CHECK: br [[NOT_PRESENT_FINISH:bb[0-9]+]]
-//
// If so, pull the value out and check whether it's a B.
// CHECK: [[IS_PRESENT]]([[VAL:%.*]] :
// CHECK-NEXT: [[X_VALUE:%.*]] = init_enum_data_addr [[PB]] : $*Optional<B>, #Optional.some
@@ -44,7 +41,7 @@
// CHECK-NEXT: return
//
// Finish the not-present path.
-// CHECK: [[NOT_PRESENT_FINISH]]:
+// CHECK: [[NOT_PRESENT]]:
// CHECK-NEXT: inject_enum_addr [[PB]] {{.*}}none
// CHECK-NEXT: br [[RETURN_BB]]
func foo(_ y : A?) {
@@ -73,16 +70,10 @@
// CHECK: [[PP]]([[VALUE_OOA:%.*]] :
// CHECK-NEXT: switch_enum [[VALUE_OOA]] : ${{.*}}, case #Optional.some!enumelt.1: [[PPP:bb[0-9]+]], case #Optional.none!enumelt: [[NIL_DEPTH_3:bb[0-9]+]]
//
-// CHECK: [[NIL_DEPTH_3]]:
-// CHECK: br [[FINISH_NIL_1:bb[0-9]+]]
-//
// If so, drill down another level and check for some(some(some(some(...)))).
// CHECK: [[PPP]]([[VALUE_OA:%.*]] :
// CHECK-NEXT: switch_enum [[VALUE_OA]] : ${{.*}}, case #Optional.some!enumelt.1: [[PPPP:bb[0-9]+]], case #Optional.none!enumelt: [[NIL_DEPTH_4:bb[0-9]+]]
//
-// CHECK: [[NIL_DEPTH_4]]:
-// CHECK: br [[FINISH_NIL_2:bb[0-9]+]]
-//
// If so, pull out the A and check whether it's a B.
// CHECK: [[PPPP]]([[VAL:%.*]] :
// CHECK-NEXT: checked_cast_br [[VAL]] : $A to $B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]]
@@ -117,18 +108,18 @@
// Set X := some(OOB).
// CHECK: [[DONE_DEPTH1]]
// CHECK-NEXT: enum $Optional<Optional<Optional<B>>>, #Optional.some!enumelt.1,
-// CHECK: br [[DONE_DEPTH2:bb[0-9]+]]
+// CHECK: br [[DONE_DEPTH2:bb[0-9]+]]
// CHECK: [[DONE_DEPTH2]]
// CHECK-NEXT: destroy_value [[X]]
// CHECK-NOT: destroy_value %0
// CHECK: return
//
// On various failure paths, set OOB := nil.
-// CHECK: [[FINISH_NIL_2]]:
+// CHECK: [[NIL_DEPTH_4]]:
// CHECK-NEXT: enum $Optional<B>, #Optional.none!enumelt
// CHECK-NEXT: br [[DONE_DEPTH0]]
//
-// CHECK: [[FINISH_NIL_1]]:
+// CHECK: [[NIL_DEPTH_3]]:
// CHECK-NEXT: enum $Optional<Optional<B>>, #Optional.none!enumelt
// CHECK-NEXT: br [[DONE_DEPTH1]]
//
@@ -148,7 +139,7 @@
// CHECK-NEXT: [[PB:%.*]] = project_box [[X]]
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: switch_enum [[ARG_COPY]]
-// CHECK: bb2([[VAL:%.*]] : @owned $AnyObject):
+// CHECK: bb1([[VAL:%.*]] : @owned $AnyObject):
// CHECK-NEXT: [[X_VALUE:%.*]] = init_enum_data_addr [[PB]] : $*Optional<B>, #Optional.some
// CHECK-NEXT: checked_cast_br [[VAL]] : $AnyObject to $B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]]
// CHECK: [[IS_B]]([[CASTED_VALUE:%.*]] : @owned $B):
diff --git a/test/SILGen/optional.swift b/test/SILGen/optional.swift
index a49f763..e66669e 100644
--- a/test/SILGen/optional.swift
+++ b/test/SILGen/optional.swift
@@ -9,9 +9,6 @@
// CHECK: [[T0_COPY:%.*]] = copy_value [[T0]]
// CHECK-NEXT: switch_enum [[T0_COPY]] : $Optional<@callee_guaranteed () -> ()>, case #Optional.some!enumelt.1: [[SOME:bb[0-9]+]], case #Optional.none!enumelt: [[NONE:bb[0-9]+]]
//
-// CHECK: [[NONE]]:
-// CHECK: br [[NOTHING_BLOCK_EXIT:bb[0-9]+]]
-
// If it does, project and load the value out of the implicitly unwrapped
// optional...
@@ -23,7 +20,7 @@
// CHECK: br [[EXIT:bb[0-9]+]](
// (first nothing block)
-// CHECK: [[NOTHING_BLOCK_EXIT]]:
+// CHECK: [[NONE]]:
// CHECK-NEXT: enum $Optional<()>, #Optional.none!enumelt
// CHECK-NEXT: br [[EXIT]]
// CHECK: } // end sil function '$s8optional8testCallyyyycSgF'
@@ -44,9 +41,9 @@
// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] [[PBF]]
// Check whether 'f' holds a value.
// CHECK: [[HASVALUE:%.*]] = select_enum_addr [[READ]]
-// CHECK-NEXT: cond_br [[HASVALUE]], bb2, bb1
+// CHECK-NEXT: cond_br [[HASVALUE]], bb1, bb3
// If so, pull out the value...
-// CHECK: bb2:
+// CHECK: bb1:
// CHECK-NEXT: [[T1:%.*]] = unchecked_take_enum_data_addr [[READ]]
// CHECK-NEXT: [[T0:%.*]] = load [copy] [[T1]]
// CHECK-NEXT: end_access [[READ]]
@@ -56,9 +53,9 @@
// ...and coerce to T?
// CHECK: inject_enum_addr [[PBX]] {{.*}}some
// CHECK: destroy_value [[T0]]
-// CHECK-NEXT: br bb3
+// CHECK-NEXT: br bb2
// Continuation block.
-// CHECK: bb3
+// CHECK: bb2
// CHECK-NEXT: destroy_value [[X]]
// CHECK-NEXT: destroy_value [[F]]
// CHECK-NOT: destroy_value %0
@@ -66,9 +63,10 @@
// CHECK-NEXT: return [[T0]] : $()
// Nothing block.
-// CHECK: bb4:
+// CHECK: bb3:
+// CHECK-NEXT: end_access [[READ]]
// CHECK-NEXT: inject_enum_addr [[PBX]] {{.*}}none
-// CHECK-NEXT: br bb3
+// CHECK-NEXT: br bb2
// <rdar://problem/15180622>
diff --git a/test/SILGen/pointer_conversion.swift b/test/SILGen/pointer_conversion.swift
index bfb5127..6c6c79f 100644
--- a/test/SILGen/pointer_conversion.swift
+++ b/test/SILGen/pointer_conversion.swift
@@ -310,9 +310,6 @@
// CHECK: [[RESULT1:%.*]] = apply [[SIDE1]]()
// CHECK: switch_enum [[COPY]] : $Optional<Array<Int>>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
- // CHECK: [[NONE_BB]]:
- // CHECK: br [[NONE_BB_TARGET:bb[0-9]+]]
- //
// CHECK: [[SOME_BB]]([[SOME_VALUE:%.*]] :
// CHECK: [[CONVERT:%.*]] = function_ref @$ss35_convertConstArrayToPointerArgumentyyXlSg_q_tSayxGs01_E0R_r0_lF
// CHECK: [[BORROW_SOME_VALUE:%.*]] = begin_borrow [[SOME_VALUE]]
@@ -329,7 +326,7 @@
// CHECK: apply [[TAKES]]([[OPTDEP]], [[RESULT1]])
// CHECK: destroy_value [[OWNER]]
// CHECK-NOT: destroy_value %0
- // CHECK: [[NONE_BB_TARGET]]:
+ // CHECK: [[NONE_BB]]:
// CHECK: [[NO_VALUE:%.*]] = enum $Optional<UnsafePointer<Int>>, #Optional.none
// CHECK: [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
// CHECK: br [[CONT_BB]]([[NO_VALUE]] : $Optional<UnsafePointer<Int>>, [[NO_OWNER]] : $Optional<AnyObject>)
@@ -343,14 +340,9 @@
// CHECK: [[RESULT1:%.*]] = apply [[SIDE1]]()
// CHECK: switch_enum [[COPY]] : $Optional<Optional<Array<Int>>>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
- // CHECK: [[NONE_BB]]:
- // CHECK: br [[NONE_BB_TARGET:bb[0-9]+]]
- //
// CHECK: [[SOME_BB]]([[SOME_VALUE:%.*]] :
// CHECK: switch_enum [[SOME_VALUE]] : $Optional<Array<Int>>, case #Optional.some!enumelt.1: [[SOME_SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[SOME_NONE_BB:bb[0-9]+]]
//
- // CHECK: [[SOME_NONE_BB]]:
- // CHECK: br [[SOME_NONE_BB2:bb[0-9]+]]
// CHECK: [[SOME_SOME_BB]]([[SOME_SOME_VALUE:%.*]] :
// CHECK: [[CONVERT:%.*]] = function_ref @$ss35_convertConstArrayToPointerArgumentyyXlSg_q_tSayxGs01_E0R_r0_lF
// CHECK: [[SOME_SOME_VALUE_BORROW:%.*]] = begin_borrow [[SOME_SOME_VALUE]]
@@ -371,11 +363,11 @@
// CHECK: apply [[TAKES]]([[OPTOPTDEP]], [[RESULT1]])
// CHECK: destroy_value [[OWNER]]
// CHECK-NOT: destroy_value %0
- // CHECK: [[SOME_NONE_BB2]]:
+ // CHECK: [[SOME_NONE_BB]]:
// CHECK: [[NO_VALUE:%.*]] = enum $Optional<UnsafePointer<Int>>, #Optional.none
// CHECK: [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
// CHECK: br [[SOME_SOME_CONT_BB]]([[NO_VALUE]] : $Optional<UnsafePointer<Int>>, [[NO_OWNER]] : $Optional<AnyObject>)
- // CHECK: [[NONE_BB_TARGET]]:
+ // CHECK: [[NONE_BB]]:
// CHECK: [[NO_VALUE:%.*]] = enum $Optional<Optional<UnsafePointer<Int>>>, #Optional.none
// CHECK: [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
// CHECK: br [[SOME_CONT_BB]]([[NO_VALUE]] : $Optional<Optional<UnsafePointer<Int>>>, [[NO_OWNER]] : $Optional<AnyObject>)
@@ -389,9 +381,6 @@
// CHECK: [[RESULT1:%.*]] = apply [[SIDE1]]()
// CHECK: switch_enum [[COPY]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
- // CHECK: [[NONE_BB]]:
- // CHECK: br [[NONE_BB_TARGET:bb[0-9]+]]
- //
// CHECK: [[SOME_BB]]([[SOME_VALUE:%.*]] :
// CHECK: [[CONVERT:%.*]] = function_ref @$ss40_convertConstStringToUTF8PointerArgumentyyXlSg_xtSSs01_F0RzlF
// CHECK: [[BORROWED_SOME_VALUE:%.*]] = begin_borrow [[SOME_VALUE]]
@@ -408,7 +397,7 @@
// CHECK: apply [[TAKES]]([[OPTDEP]], [[RESULT1]])
// CHECK: destroy_value [[OWNER]]
// CHECK-NOT: destroy_value %0
- // CHECK: [[NONE_BB_TARGET]]:
+ // CHECK: [[NONE_BB]]:
// CHECK: [[NO_VALUE:%.*]] = enum $Optional<UnsafeRawPointer>, #Optional.none
// CHECK: [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
// CHECK: br [[CONT_BB]]([[NO_VALUE]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
@@ -423,13 +412,8 @@
// FIXME: this should really go somewhere that will make nil, not some(nil)
// CHECK: switch_enum [[COPY]] : $Optional<Optional<String>>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
- // CHECK: [[NONE_BB]]:
- // CHECK: br [[NONE_BB_TARGET:bb[0-9]+]]
- //
// CHECK: [[SOME_BB]]([[SOME_VALUE:%.*]] :
// CHECK: switch_enum [[SOME_VALUE]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[SOME_NONE_BB:bb[0-9]+]]
- // CHECK: [[SOME_NONE_BB]]:
- // CHECK: br [[SOME_NONE_BB2:bb[0-9]+]]
// CHECK: [[SOME_SOME_BB]]([[SOME_SOME_VALUE:%.*]] :
// CHECK: [[CONVERT:%.*]] = function_ref @$ss40_convertConstStringToUTF8PointerArgumentyyXlSg_xtSSs01_F0RzlF
// CHECK: [[BORROWED_SOME_SOME_VALUE:%.*]] = begin_borrow [[SOME_SOME_VALUE]]
@@ -450,11 +434,11 @@
// CHECK: apply [[TAKES]]([[OPTOPTDEP]], [[RESULT1]])
// CHECK: destroy_value [[OWNER]]
// CHECK-NOT: destroy_value %0
- // CHECK: [[SOME_NONE_BB2]]:
+ // CHECK: [[SOME_NONE_BB]]:
// CHECK: [[NO_VALUE:%.*]] = enum $Optional<UnsafeRawPointer>, #Optional.none
// CHECK: [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
// CHECK: br [[SOME_SOME_CONT_BB]]([[NO_VALUE]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
- // CHECK: [[NONE_BB_TARGET]]:
+ // CHECK: [[NONE_BB]]:
// CHECK: [[NO_VALUE:%.*]] = enum $Optional<Optional<UnsafeRawPointer>>, #Optional.none
// CHECK: [[NO_OWNER:%.*]] = enum $Optional<AnyObject>, #Optional.none
// CHECK: br [[SOME_CONT_BB]]([[NO_VALUE]] : $Optional<Optional<UnsafeRawPointer>>, [[NO_OWNER]] : $Optional<AnyObject>)
diff --git a/test/SILGen/sil_locations.swift b/test/SILGen/sil_locations.swift
index 410c06c..cad8643 100644
--- a/test/SILGen/sil_locations.swift
+++ b/test/SILGen/sil_locations.swift
@@ -12,8 +12,10 @@
// CHECK-LABEL: sil hidden @$s13sil_locations6ifexprSiyF
// CHECK: apply {{.*}}, loc "{{.*}}":[[@LINE-5]]:6
// CHECK: cond_br {{%.*}}, [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-6]]:6
- // CHECK: br [[FALSE_BB]], loc "{{.*}}":[[@LINE-5]]:3
- // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE-5]]:3, {{.*}}:return
+ // CHECK: [[TRUE_BB]]:
+ // CHECK: br [[CONT_BB:bb[0-9]+]], loc "{{.*}}":[[@LINE-6]]:3
+ // CHECK: [[CONT_BB]]:
+ // CHECK: return {{.*}}, loc "{{.*}}":[[@LINE-7]]:3, {{.*}}:return
}
func ifelseexpr() -> Int {
@@ -77,7 +79,7 @@
func useTemplateTest() -> Int {
return templateTest(5);
// CHECK-LABEL: sil hidden @$s13sil_locations15useTemplateTestSiyF
- // CHECK: function_ref @$sSi2{{[_0-9a-zA-Z]*}}fC :{{.*}}, loc "{{.*}}":78
+ // CHECK: function_ref @$sSi2{{[_0-9a-zA-Z]*}}fC :{{.*}}, loc "{{.*}}":[[@LINE-2]]
}
func foo(_ x: Int) -> Int {
diff --git a/test/SILGen/statements.swift b/test/SILGen/statements.swift
index 8a19193..5395056 100644
--- a/test/SILGen/statements.swift
+++ b/test/SILGen/statements.swift
@@ -270,18 +270,15 @@
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: switch_enum [[ARG_COPY]] : $Optional<C>, case #Optional.some!enumelt.1: [[TRUE:bb[0-9]+]], case #Optional.none!enumelt: [[FALSE:bb[0-9]+]]
- // CHECK: [[FALSE]]:
- // CHECK: br [[AFTER_FALSE:bb[0-9]+]]
if let x = c {
// CHECK: [[TRUE]]({{.*}} : @owned $C):
use(x)
- // CHECK: br [[CONT:bb[0-9]+]]
- // CHECK: [[CONT]]:
+ // CHECK: apply
// CHECK: br [[EPILOG:bb[0-9]+]]
} else {
- // CHECK: [[AFTER_FALSE]]:
+ // CHECK: [[FALSE]]:
// CHECK: apply
- // CHECK: br [[EPILOG]]
+ // CHECK: br [[EPILOG:bb[0-9]+]]
foo()
break label2
foo() // expected-warning {{will never be executed}}
@@ -297,17 +294,12 @@
// CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]]
// CHECK: switch_enum [[ARG2_COPY]] : $Optional<C>, case #Optional.some!enumelt.1: [[TRUE:bb[0-9]+]], case #Optional.none!enumelt: [[FALSE:bb[0-9]+]]
- // CHECK: [[FALSE]]:
- // CHECK: br [[COND2:bb[0-9]+]]
if let x = c {
// CHECK: [[TRUE]]({{.*}} : @owned $C):
use(x)
- // CHECK: br [[TRUE_TRAMPOLINE:bb[0-9]+]]
- //
- // CHECK: [[TRUE_TRAMPOLINE]]:
// CHECK: br [[EPILOG_BB:bb[0-9]+]]
} else if a {
- // CHECK: [[COND2]]:
+ // CHECK: [[FALSE]]:
// CHECK: cond_br {{.*}}, [[TRUE2:bb[0-9]+]], [[FALSE2:bb[0-9]+]]
//
// CHECK: [[TRUE2]]:
@@ -333,7 +325,7 @@
// CHECK: [[LOOP]]:
// CHECK: function_ref @$sSb21_getBuiltinLogicValue{{[_0-9a-zA-Z]*}}F
// CHECK-NEXT: apply
- // CHECK-NEXT: cond_br {{.*}}, [[LOOPTRUE:bb[0-9]+]], [[OUT:bb[0-9]+]]
+ // CHECK-NEXT: cond_br {{.*}}, [[LOOPTRUE:bb[0-9]+]], [[EXIT:bb[0-9]+]]
while a {
if a {
foo()
@@ -349,12 +341,15 @@
// [[IFTRUE]]:
// CHECK: function_ref statements.foo
- // CHECK: br [[OUT]]
+ // CHECK: br [[OUT:bb[0-9]+]]
// CHECK: [[IFFALSE]]:
// CHECK: function_ref statements.foo
// CHECK: br [[LOOP]]
+ // CHECK: [[EXIT]]:
+ // CHECK: br [[OUT]]
+
// CHECK: [[OUT]]:
// CHECK: return
}
@@ -475,10 +470,8 @@
func defer_test2(_ cond : Bool) {
// CHECK: [[C3:%.*]] = function_ref @{{.*}}callee3yyF
// CHECK: apply [[C3]]
- // CHECK: br [[LOOP:bb[0-9]+]]
callee3()
-// CHECK: [[LOOP]]:
// test the condition.
// CHECK: [[CONDTRUE:%.*]] = apply {{.*}}(%0)
// CHECK: cond_br [[CONDTRUE]], [[BODY:bb[0-9]+]], [[EXIT:bb[0-9]+]]
@@ -489,13 +482,16 @@
// CHECK: [[C1:%.*]] = function_ref @$s10statements11defer_test2yySbF6
// CHECK: apply [[C1]]
- // CHECK: br [[EXIT]]
+ // CHECK: br [[RETURN:bb[0-9]+]]
defer { callee1() }
callee2()
break
}
// CHECK: [[EXIT]]:
+// CHECK: br [[RETURN]]
+
+// CHECK: [[RETURN]]:
// CHECK: [[C3:%.*]] = function_ref @{{.*}}callee3yyF
// CHECK: apply [[C3]]
@@ -587,18 +583,12 @@
// CHECK-NEXT: switch_enum [[ARG]] : $Optional<Int>, case #Optional.some!enumelt.1: [[SOME:bb[0-9]+]], case #Optional.none!enumelt: [[NONE:bb[0-9]+]]
func testRequireOptional1(_ a : Int?) -> Int {
- // CHECK: [[NONE]]:
- // CHECK: br [[ABORT:bb[0-9]+]]
-
// CHECK: [[SOME]]([[PAYLOAD:%.*]] : @trivial $Int):
// CHECK-NEXT: debug_value [[PAYLOAD]] : $Int, let, name "t"
- // CHECK-NEXT: br [[EPILOG:bb[0-9]+]]
- //
- // CHECK: [[EPILOG]]:
// CHECK-NEXT: return [[PAYLOAD]] : $Int
guard let t = a else { abort() }
- // CHECK: [[ABORT]]:
+ // CHECK: [[NONE]]:
// CHECK-NEXT: // function_ref statements.abort() -> Swift.Never
// CHECK-NEXT: [[FUNC_REF:%.*]] = function_ref @$s10statements5aborts5NeverOyF
// CHECK-NEXT: apply [[FUNC_REF]]() : $@convention(thin) () -> Never
@@ -614,20 +604,15 @@
func testRequireOptional2(_ a : String?) -> String {
guard let t = a else { abort() }
- // CHECK: [[NONE_BB]]:
- // CHECK-NEXT: br [[ABORT_BB:bb[0-9]+]]
-
// CHECK: [[SOME_BB]]([[STR:%.*]] : @owned $String):
// CHECK-NEXT: debug_value [[STR]] : $String, let, name "t"
- // CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
- // CHECK: [[CONT_BB]]:
// CHECK-NEXT: [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
// CHECK-NEXT: [[RETURN:%.*]] = copy_value [[BORROWED_STR]]
// CHECK-NEXT: end_borrow [[BORROWED_STR]]
// CHECK-NEXT: destroy_value [[STR]] : $String
// CHECK-NEXT: return [[RETURN]] : $String
- // CHECK: [[ABORT_BB]]:
+ // CHECK: [[NONE_BB]]:
// CHECK-NEXT: // function_ref statements.abort() -> Swift.Never
// CHECK-NEXT: [[ABORT_FUNC:%.*]] = function_ref @$s10statements5aborts5NeverOyF
// CHECK-NEXT: [[NEVER:%.*]] = apply [[ABORT_FUNC]]()
@@ -665,8 +650,6 @@
// CHECK: bb{{.*}}([[PTR:%[0-9]+]] : @owned $DerivedClass):
// CHECK-NEXT: debug_value [[PTR]] : $DerivedClass, let, name "result"
- // CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
- // CHECK: [[CONT_BB]]:
// CHECK-NEXT: [[BORROWED_PTR:%.*]] = begin_borrow [[PTR]]
// CHECK-NEXT: [[RESULT:%.*]] = copy_value [[BORROWED_PTR]]
// CHECK-NEXT: end_borrow [[BORROWED_PTR]]
@@ -689,8 +672,6 @@
// CHECK-NEXT: ([[PAYLOAD_1:%.*]], [[PAYLOAD_2:%.*]]) = destructure_tuple [[PAYLOAD]]
// CHECK-NEXT: debug_value [[PAYLOAD_1]] : $Int, let, name "x"
// CHECK-NEXT: debug_value [[PAYLOAD_2]] : $Int, let, name "y"
- // CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
- // CHECK: [[CONT_BB]]:
// CHECK-NEXT: return [[PAYLOAD_1]] : $Int
}
diff --git a/test/SILGen/switch.swift b/test/SILGen/switch.swift
index b25814f..a6f8a93 100644
--- a/test/SILGen/switch.swift
+++ b/test/SILGen/switch.swift
@@ -31,10 +31,8 @@
// CHECK: function_ref @$s6switch3fooSiyF
case _:
// CHECK: function_ref @$s6switch1ayyF
- // CHECK: br [[CONT:bb[0-9]+]]
a()
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1byyF
b()
}
@@ -60,7 +58,7 @@
switch foo() {
// CHECK: function_ref @$s6switch3fooSiyF
// CHECK: function_ref @$s6switch6runcedSbyF
- // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[NO_CASE2:bb[0-9]+]]
+ // CHECK: cond_br {{%.*}}, [[CASE1:bb[0-9]+]], [[CASE2:bb[0-9]+]]
case _ where runced():
// CHECK: [[CASE1]]:
@@ -68,8 +66,6 @@
// CHECK: br [[CONT:bb[0-9]+]]
a()
- // CHECK: [[NO_CASE2]]:
- // CHECK: br [[CASE2:bb[0-9]+]]
case _:
// CHECK: [[CASE2]]:
// CHECK: function_ref @$s6switch1byyF
@@ -88,10 +84,8 @@
// CHECK: function_ref @$s6switch3barSiyF
case _:
// CHECK: function_ref @$s6switch1ayyF
- // CHECK: br [[CONT:bb[0-9]+]]
a()
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1byyF
b()
}
@@ -118,15 +112,11 @@
// CHECK: br [[CONT]]
b()
- // CHECK: [[NOT_CASE2]]:
- // CHECK: br [[CASE3:bb[0-9]+]]
case _:
- // CHECK: [[CASE3]]:
+ // CHECK: [[NOT_CASE2]]:
// CHECK: function_ref @$s6switch1cyyF
- // CHECK: br [[CONT]]
c()
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1dyyF
d()
}
@@ -161,16 +151,12 @@
// CHECK: br [[CONT:bb[0-9]+]]
a()
- // CHECK: [[NOT_CASE1]]:
- // CHECK: br [[CASE2:bb[0-9]+]]
case (_, _):
- // CHECK: [[CASE2]]:
+ // CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @$s6switch1byyF
- // CHECK: br [[CONT]]
b()
}
c()
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1cyyF
}
@@ -269,15 +255,11 @@
// CHECK: br [[CONT]]
b()
- // CHECK: [[NOT_CASE2]]:
- // CHECK: br [[CASE3:bb[0-9]+]]
case _:
- // CHECK: [[CASE3]]:
+ // CHECK: [[NOT_CASE2]]:
// CHECK: function_ref @$s6switch1cyyF
- // CHECK: br [[CONT]]
c()
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s6switch1dyyF
d()
}
@@ -294,10 +276,8 @@
// CHECK: br [[CONT:bb[0-9]+]]
a()
- // CHECK: [[NOT_CASE1]]:
- // CHECK: br [[CASE2:bb[0-9]+]]
case _:
- // CHECK: [[CASE2]]:
+ // CHECK: [[NOT_CASE1]]:
// CHECK: function_ref @$s6switch1byyF
// CHECK: br [[CONT]]
b()
@@ -457,7 +437,7 @@
// CHECK-NEXT: destroy_value [[CAST_D1_COPY]]
// CHECK-NEXT: end_borrow [[CAST_D1]]
// CHECK-NEXT: end_borrow [[BORROWED_X_COPY]]
- // CHECK-NEXT: br [[NEXT_CASE:bb5]]
+ // CHECK: br [[NEXT_CASE:bb[0-9]+]]
// CHECK: [[IS_NOT_D1]]([[CASTFAIL_D1:%.*]] : @guaranteed $B):
// CHECK-NEXT: end_borrow [[CASTFAIL_D1]]
@@ -479,9 +459,6 @@
// CHECK: [[IS_NOT_D2]]([[CASTFAIL_D2:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[CASTFAIL_D2]]
- // CHECK: br [[NEXT_CASE:bb8]]
-
- // CHECK: [[NEXT_CASE]]:
// CHECK: [[BORROWED_X_COPY:%.*]] = begin_borrow [[X_COPY]]
// CHECK: checked_cast_br [[BORROWED_X_COPY]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
case is E where funged():
@@ -502,7 +479,7 @@
// CHECK-NEXT: destroy_value [[CAST_E_COPY]]
// CHECK-NEXT: end_borrow
// CHECK-NEXT: end_borrow [[BORROWED_X_COPY]]
- // CHECK-NEXT: br [[NEXT_CASE:bb13]]
+ // CHECK: br [[NEXT_CASE:bb[0-9]+]]
// CHECK: [[IS_NOT_E]]([[NOTCAST_E:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOTCAST_E]]
@@ -524,9 +501,6 @@
// CHECK: [[IS_NOT_C]]([[NOCAST_C:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_C]]
- // CHECK: br [[NEXT_CASE:bb16]]
-
- // CHECK: [[NEXT_CASE]]:
default:
// CHECK: destroy_value [[X_COPY]]
// CHECK: function_ref @$s6switch1eyyF
@@ -595,9 +569,6 @@
// CHECK: [[IS_NOT_D2]]([[NOCAST_D2:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_D2]]
- // CHECK: br [[NEXT_CASE:bb8]]
-
- // CHECK: [[NEXT_CASE]]:
// CHECK: [[BORROWED_X_COPY:%.*]] = begin_borrow [[X_COPY]]
// CHECK: checked_cast_br [[BORROWED_X_COPY]] : $B to $E, [[IS_E:bb[0-9]+]], [[IS_NOT_E:bb[0-9]+]]
case let y as E where funged():
@@ -621,7 +592,7 @@
// CHECK: [[NO_CASE3]]:
// CHECK destroy_value [[CAST_E_COPY]]
- // CHECK: br [[NEXT_CASE:bb13]]
+ // CHECK: br [[NEXT_CASE:bb[0-9]+]]
// CHECK: [[IS_NOT_E]]([[NOCAST_E:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_E]]
@@ -647,9 +618,6 @@
// CHECK: [[IS_NOT_C]]([[NOCAST_C:%.*]] : @guaranteed $B):
// CHECK: end_borrow [[NOCAST_C]]
- // CHECK: br [[NEXT_CASE:bb16]]
-
- // CHECK: [[NEXT_CASE]]:
default:
// CHECK: destroy_value [[X_COPY]]
// CHECK: function_ref @$s6switch1eyyF
diff --git a/test/SILGen/switch_fallthrough.swift b/test/SILGen/switch_fallthrough.swift
index 73d1d7f..ed4e782 100644
--- a/test/SILGen/switch_fallthrough.swift
+++ b/test/SILGen/switch_fallthrough.swift
@@ -37,10 +37,8 @@
case _:
// CHECK: [[CASE3]]:
// CHECK: function_ref @$s18switch_fallthrough1cyyF
- // CHECK: br [[CONT:bb[0-9]+]]
c()
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s18switch_fallthrough1dyyF
d()
}
@@ -65,10 +63,8 @@
case _:
// CHECK: [[CASE3]]:
// CHECK: function_ref @$s18switch_fallthrough1cyyF
- // CHECK: br [[CONT:bb[0-9]+]]
c()
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s18switch_fallthrough1dyyF
d()
}
@@ -98,10 +94,8 @@
case (_, _):
// CHECK: [[CASE4]]:
// CHECK: function_ref @$s18switch_fallthrough1dyyF
- // CHECK: br [[CONT:bb[0-9]+]]
d()
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s18switch_fallthrough1eyyF
e()
}
diff --git a/test/SILGen/switch_multiple_entry_address_only.swift b/test/SILGen/switch_multiple_entry_address_only.swift
index cca9c21..b9673c4 100644
--- a/test/SILGen/switch_multiple_entry_address_only.swift
+++ b/test/SILGen/switch_multiple_entry_address_only.swift
@@ -42,17 +42,14 @@
// CHECK: [[FN:%.*]] = function_ref @$s34switch_multiple_entry_address_only8takesAnyyyypF
// CHECK-NEXT: apply [[FN]]([[X_PHI]]
// CHECK-NEXT: destroy_addr [[X_PHI]]
- // CHECK-NEXT: br bb6
+ // CHECK-NEXT: br bb5
// CHECK: bb4:
+ // CHECK-NEXT: destroy_addr [[E_COPY]]
+ // CHECK-NEXT: dealloc_stack [[E_COPY]]
// CHECK-NEXT: br bb5
// CHECK: bb5:
- // CHECK-NEXT: destroy_addr [[E_COPY]]
- // CHECK-NEXT: dealloc_stack [[E_COPY]]
- // CHECK-NEXT: br bb6
-
- // CHECK: bb6:
// CHECK-NEXT: dealloc_stack [[X_PHI]]
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
@@ -106,17 +103,14 @@
// CHECK-NEXT: destroy_addr [[ANY_STACK]]
// CHECK-NEXT: dealloc_stack [[ANY_STACK]]
// CHECK-NEXT: destroy_value [[ANY_BOX]]
- // CHECK-NEXT: br bb6
+ // CHECK-NEXT: br bb5
// CHECK: bb4:
+ // CHECK-NEXT: destroy_addr [[E_COPY]]
+ // CHECK-NEXT: dealloc_stack [[E_COPY]]
// CHECK-NEXT: br bb5
// CHECK: bb5:
- // CHECK-NEXT: destroy_addr [[E_COPY]]
- // CHECK-NEXT: dealloc_stack [[E_COPY]]
- // CHECK-NEXT: br bb6
-
- // CHECK: bb6:
// CHECK-NEXT: dealloc_stack [[X_PHI]]
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
@@ -163,17 +157,14 @@
// CHECK: [[FN2:%.*]] = function_ref @$s34switch_multiple_entry_address_only8takesAnyyyypF
// CHECK-NEXT: apply [[FN2]]([[X_PHI]]
// CHECK-NEXT: destroy_addr [[X_PHI]]
- // CHECK-NEXT: br bb6
+ // CHECK-NEXT: br bb5
// CHECK: bb4:
+ // CHECK-NEXT: destroy_addr [[E_COPY]]
+ // CHECK-NEXT: dealloc_stack [[E_COPY]]
// CHECK-NEXT: br bb5
// CHECK: bb5:
- // CHECK-NEXT: destroy_addr [[E_COPY]]
- // CHECK-NEXT: dealloc_stack [[E_COPY]]
- // CHECK-NEXT: br bb6
-
- // CHECK: bb6:
// CHECK-NEXT: dealloc_stack [[X_PHI]]
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
diff --git a/test/SILGen/switch_objc.swift b/test/SILGen/switch_objc.swift
index 77e323c..f78f0e4 100644
--- a/test/SILGen/switch_objc.swift
+++ b/test/SILGen/switch_objc.swift
@@ -20,9 +20,7 @@
return true
// CHECK: [[NOT_CASE2]]:
- // CHECK: br [[RET_FALSE:bb[0-9]+]]
default:
- // CHECK: [[RET_FALSE]]:
// CHECK: function_ref @$sSb2{{[_0-9a-zA-Z]*}}fC
return false
}
diff --git a/test/SILGen/switch_var.swift b/test/SILGen/switch_var.swift
index c2d9477..76531ff 100644
--- a/test/SILGen/switch_var.swift
+++ b/test/SILGen/switch_var.swift
@@ -54,10 +54,8 @@
// CHECK: load [trivial] [[READ]]
// CHECK: function_ref @$s10switch_var1a1xySi_tF
// CHECK: destroy_value [[XADDR]]
- // CHECK: br [[CONT:bb[0-9]+]]
a(x: x)
}
- // CHECK: [[CONT]]:
// CHECK: function_ref @$s10switch_var1byyF
b()
}
@@ -96,10 +94,8 @@
// CHECK: destroy_value [[YADDR]]
// CHECK: br [[CONT]]
b(x: y)
- // CHECK: [[NO_CASE2]]:
- // CHECK: br [[CASE3:bb[0-9]+]]
case var z:
- // CHECK: [[CASE3]]:
+ // CHECK: [[NO_CASE2]]:
// CHECK: [[ZADDR:%.*]] = alloc_box ${ var Int }
// CHECK: [[Z:%.*]] = project_box [[ZADDR]]
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[Z]]
@@ -133,10 +129,8 @@
// CHECK: destroy_value [[XADDR]]
// CHECK: br [[CONT:bb[0-9]+]]
aa(x: x)
- // CHECK: [[NO_CASE1]]:
- // CHECK: br [[NO_CASE1_TARGET:bb[0-9]+]]
- // CHECK: [[NO_CASE1_TARGET]]:
+ // CHECK: [[NO_CASE1]]:
// CHECK: [[YADDR:%.*]] = alloc_box ${ var Int }
// CHECK: [[Y:%.*]] = project_box [[YADDR]]
// CHECK: [[ZADDR:%.*]] = alloc_box ${ var Int }
@@ -174,9 +168,7 @@
bb(x: w)
// CHECK: [[NO_CASE3]]:
// CHECK: destroy_value [[WADDR]]
- // CHECK: br [[CASE4:bb[0-9]+]]
case var v:
- // CHECK: [[CASE4]]:
// CHECK: [[VADDR:%.*]] = alloc_box ${ var (Int, Int) }
// CHECK: [[V:%.*]] = project_box [[VADDR]]
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[V]]
@@ -289,9 +281,7 @@
// CHECK: [[DFLT_NO_CASE3]]:
// CHECK: destroy_value [[ZADDR]]
- // CHECK: br [[CASE4:bb[0-9]+]]
case (_, var w):
- // CHECK: [[CASE4]]:
// CHECK: [[PAIR_0:%.*]] = tuple_element_addr [[PAIR]] : $*(P, Int), 0
// CHECK: [[WADDR:%.*]] = alloc_box ${ var Int }
// CHECK: [[W:%.*]] = project_box [[WADDR]]
@@ -343,10 +333,8 @@
// CHECK: br [[CASE4:bb[0-9]+]]
case _:
// CHECK: [[CASE4]]:
- // CHECK: br [[CONT]]
d()
}
- // CHECK: [[CONT]]:
e()
}
@@ -417,8 +405,6 @@
a(x: x)
// CHECK: [[NO_CASE1]]:
// CHECK: destroy_value [[VAL_COPY]]
- // CHECK: br [[TRY_CASE2:bb[0-9]+]]
- // CHECK: [[TRY_CASE2]]:
// CHECK: [[BORROWED_VAL_2:%.*]] = begin_borrow [[VAL]]
// CHECK: [[VAL_COPY_2:%.*]] = copy_value [[BORROWED_VAL_2]]
// CHECK: function_ref @$s10switch_var6fungedSbyF
@@ -434,9 +420,6 @@
b(x: y)
// CHECK: [[NO_CASE2]]:
// CHECK: destroy_value [[VAL_COPY_2]]
- // CHECK: br [[NEXT_CASE:bb6]]
-
- // CHECK: [[NEXT_CASE]]:
// CHECK: [[BORROWED_VAL_3:%.*]] = begin_borrow [[VAL]]
// CHECK: [[VAL_COPY_3:%.*]] = copy_value [[BORROWED_VAL_3]]
// CHECK: function_ref @$s10switch_var4barsSSyF
@@ -454,9 +437,7 @@
c()
// CHECK: [[NO_CASE3]]:
// CHECK: destroy_value [[VAL_COPY_3]]
- // CHECK: br [[NEXT_CASE:bb9+]]
- // CHECK: [[NEXT_CASE]]:
case _:
// CHECK: destroy_value [[VAL]]
// CHECK: function_ref @$s10switch_var1dyyF
@@ -496,9 +477,7 @@
// CHECK: [[NOCASE1]]:
// CHECK: destroy_value [[BOX]]
- // CHECK: br [[NEXT_PATTERN:bb[0-9]+]]
- // CHECK: [[NEXT_PATTERN]]:
// CHECK: [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]]
// CHECK: [[VAL_COPY:%.*]] = copy_value [[BORROWED_VAL]]
// CHECK: cond_br {{.*}}, [[CASE2:bb[0-9]+]], [[NOCASE2:bb[0-9]+]]
@@ -516,9 +495,7 @@
// CHECK: [[NOCASE2]]:
// CHECK: destroy_value [[VAL_COPY]]
- // CHECK: br [[NEXT_CASE:bb[0-9]+]]
- // CHECK: [[NEXT_CASE]]
// CHECK: [[BORROWED_VAL:%.*]] = begin_borrow [[VAL]]
// CHECK: [[VAL_COPY:%.*]] = copy_value [[BORROWED_VAL]]
// CHECK: [[BORROWED_VAL_COPY:%.*]] = begin_borrow [[VAL_COPY]]
@@ -536,9 +513,7 @@
// CHECK: [[NOCASE3]]:
// CHECK: destroy_value [[VAL_COPY]]
- // CHECK: br [[NEXT_CASE:bb[0-9]+]]
- // CHECK: [[NEXT_CASE]]:
// CHECK: destroy_value [[VAL]]
// CHECK: [[D_FUNC:%.*]] = function_ref @$s10switch_var1dyyF : $@convention(thin) () -> ()
// CHECK: apply [[D_FUNC]]()
diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift
index 302d0fa..eeb8218 100644
--- a/test/SILOptimizer/access_marker_verify.swift
+++ b/test/SILOptimizer/access_marker_verify.swift
@@ -480,23 +480,9 @@
// ----- access the temporary array result of the getter
// CHECK: [[TEMPACCESS:%.*]] = begin_access [modify] [unsafe] [[TEMP]]
// CHECK: [[HAS_VALUE:%.*]] = select_enum_addr [[TEMPACCESS]]
-// CHECK: cond_br [[HAS_VALUE]], bb2, bb1
+// CHECK: cond_br [[HAS_VALUE]], [[TRUEBB:bb[0-9]+]], [[FALSEBB:bb[0-9]+]]
//
-// CHECK: bb1:
-// CHECK: [[TEMPARRAY:%.*]] = load [copy] [[TEMPACCESS]]
-// CHECK: [[WRITEBACK:%.*]] = alloc_stack $Optional<Array<Int>>
-// CHECK-NOT: begin_access
-// CHECK: store [[TEMPARRAY]] to [init] [[WRITEBACK]]
-// CHECK: [[TEMP3:%.*]] = alloc_stack $Int
-// CHECK-NOT: begin_access
-// CHECK: store %{{.*}} to [trivial] [[TEMP3]] : $*Int
-// Call MyDict.subscript.setter
-// CHECK: apply %{{.*}}<Int, [Int]>([[WRITEBACK]], [[TEMP3]], [[BOXACCESS]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_0, @inout MyDict<τ_0_0, τ_0_1>) -> ()
-// CHECK: end_access [[TEMPACCESS]] : $*Optional<Array<Int>>
-// CHECK: end_access [[BOXACCESS]] : $*MyDict<Int, Array<Int>>
-// CHECK: br
-//
-// CHECK: bb2:
+// CHECK: [[TRUEBB]]:
// CHECK-NOT: begin_access
// CHECK: [[TEMPARRAYADR:%.*]] = unchecked_take_enum_data_addr [[TEMPACCESS]] : $*Optional<Array<Int>>, #Optional.some!enumelt.1
// ----- call Array.append
@@ -511,6 +497,22 @@
// CHECK: store %{{.*}} to [trivial]
// ----- call MyDict.subscript.setter
// CHECK: apply %{{.*}}<Int, [Int]>([[ARRAYCOPY]], %{{.*}}, [[BOXACCESS]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_0, @inout MyDict<τ_0_0, τ_0_1>) -> ()
+// CHECK: br [[RETBB:bb[0-9]+]]
+//
+// CHECK: [[FALSEBB]]:
+// CHECK: [[TEMPARRAY:%.*]] = load [copy] [[TEMPACCESS]]
+// CHECK: [[WRITEBACK:%.*]] = alloc_stack $Optional<Array<Int>>
+// CHECK-NOT: begin_access
+// CHECK: store [[TEMPARRAY]] to [init] [[WRITEBACK]]
+// CHECK: [[TEMP3:%.*]] = alloc_stack $Int
+// CHECK-NOT: begin_access
+// CHECK: store %{{.*}} to [trivial] [[TEMP3]] : $*Int
+// Call MyDict.subscript.setter
+// CHECK: apply %{{.*}}<Int, [Int]>([[WRITEBACK]], [[TEMP3]], [[BOXACCESS]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_0, @inout MyDict<τ_0_0, τ_0_1>) -> ()
+// CHECK: end_access [[TEMPACCESS]] : $*Optional<Array<Int>>
+// CHECK: end_access [[BOXACCESS]] : $*MyDict<Int, Array<Int>>
+// CHECK: br [[RETBB]]
+//
// CHECK-LABEL: } // end sil function '$s20access_marker_verify0A13OptionalArrayyyAA6MyDictVySiSaySiGGF'
// --- Optional map.
diff --git a/test/SILOptimizer/definite-init-convert-to-escape.swift b/test/SILOptimizer/definite-init-convert-to-escape.swift
index 8ae073e..9953a1c 100644
--- a/test/SILOptimizer/definite-init-convert-to-escape.swift
+++ b/test/SILOptimizer/definite-init-convert-to-escape.swift
@@ -10,16 +10,16 @@
// CHECK: bb0
// CHECK: retain_value %0
// CHECK: retain_value %0
-// CHECK: bb2
+// CHECK: bb1
// CHECK: convert_escape_to_noescape %
// CHECK: strong_release
+// CHECK: bb5
+// CHECK: retain_value %1
+// CHECK: retain_value %1
// CHECK: bb6
-// CHECK: retain_value %1
-// CHECK: retain_value %1
-// CHECK: bb8
// CHECK: convert_escape_to_noescape %
// CHECK: strong_release
-// CHECK: bb12
+// CHECK: bb10
// CHECK: [[F:%.*]] = function_ref @noescapeBlock3
// CHECK: apply [[F]]
// CHECK: release_value {{.*}} : $Optional<NSString>
@@ -42,11 +42,11 @@
// CHECK: [[V0:%.*]] = function_ref @_returnOptionalEscape
// CHECK: [[V1:%.*]] = apply [[V0]]
// CHECK: retain_value [[V1]]
-// CHECK: switch_enum {{.*}}bb2
-// CHECK: bb2([[V2:%.*]]: $@callee_guaranteed () -> ()):
+// CHECK: switch_enum {{.*}}bb1
+// CHECK: bb1([[V2:%.*]]: $@callee_guaranteed () -> ()):
// CHECK: convert_escape_to_noescape %
// CHECK: strong_release [[V2]]
-// CHECK: bb6({{.*}} : $Optional<@convention(block) @noescape () -> ()>)
+// CHECK: bb5({{.*}} : $Optional<@convention(block) @noescape () -> ()>)
// CHECK: [[F:%.*]] = function_ref @noescapeBlock
// CHECK: apply [[F]]({{.*}})
// CHECK: release_value [[V1]] : $Optional<@callee_guaranteed () -> ()>
@@ -59,15 +59,15 @@
// NOPEEPHOLE: store [[NONE]] to [[SLOT]]
// NOPEEPHOLE: [[V0:%.*]] = function_ref @_returnOptionalEscape
// NOPEEPHOLE: [[V1:%.*]] = apply [[V0]]
-// NOPEEPHOLE: switch_enum {{.*}}bb2
-// NOPEEPHOLE: bb2([[V2:%.*]]: $@callee_guaranteed () -> ()):
+// NOPEEPHOLE: switch_enum {{.*}}bb1
+// NOPEEPHOLE: bb1([[V2:%.*]]: $@callee_guaranteed () -> ()):
// NOPEEPHOLE: destroy_addr [[SLOT]]
// NOPEEPHOLE: [[SOME:%.*]] = enum $Optional<@callee_guaranteed () -> ()>, #Optional.some!enumelt.1, [[V2]]
// NOPEEPHOLE: store [[SOME]] to [[SLOT]]
// NOPEEPHOLE: convert_escape_to_noescape %
// NOPEEPHOLE-NOT: strong_release
// NOPEEPHOLE: br
-// NOPEEPHOLE: bb6({{.*}} : $Optional<@convention(block) @noescape () -> ()>)
+// NOPEEPHOLE: bb5({{.*}} : $Optional<@convention(block) @noescape () -> ()>)
// NOPEEPHOLE: [[F:%.*]] = function_ref @noescapeBlock
// NOPEEPHOLE: apply [[F]]({{.*}})
// NOPEEPHOLE: destroy_addr [[SLOT]]
diff --git a/test/SILOptimizer/definite_init_diagnostics.swift b/test/SILOptimizer/definite_init_diagnostics.swift
index 1c1e287..2eed511 100644
--- a/test/SILOptimizer/definite_init_diagnostics.swift
+++ b/test/SILOptimizer/definite_init_diagnostics.swift
@@ -561,10 +561,10 @@
switch b {
default:
- PerpetualMotion().start()
+ PerpetualMotion().start() // expected-note {{a call to a never-returning function}}
}
- return a
+ return a // expected-warning {{will never be executed}}
}
func testNoReturn4(_ b : Bool) -> Any {
@@ -572,10 +572,10 @@
switch b {
default:
- PerpetualMotion.stop()
+ PerpetualMotion.stop() // expected-note {{a call to a never-returning function}}
}
- return a
+ return a // expected-warning {{will never be executed}}
}
diff --git a/test/SILOptimizer/definite_init_failable_initializers_objc.swift b/test/SILOptimizer/definite_init_failable_initializers_objc.swift
index f926c98..04abe6b 100644
--- a/test/SILOptimizer/definite_init_failable_initializers_objc.swift
+++ b/test/SILOptimizer/definite_init_failable_initializers_objc.swift
@@ -39,9 +39,12 @@
// CHECK-NEXT: cond_br [[COND]], bb1, bb2
// CHECK: bb1:
- // CHECK-NEXT: br bb3
+ // CHECK-NEXT: br bb4
// CHECK: bb2:
+ // ChECK-NEXT br bb3
+
+ // CHECK: bb3:
// CHECK-NEXT: [[SUPER:%.*]] = upcast %2 : $Cat to $FakeNSObject
// CHECK-NEXT: [[SUB:%.*]] = unchecked_ref_cast [[SUPER]] : $FakeNSObject to $Cat
// CHECK-NEXT: [[SUPER_FN:%.*]] = objc_super_method [[SUB]] : $Cat, #FakeNSObject.init!initializer.1.foreign : (FakeNSObject.Type) -> () -> FakeNSObject, $@convention(objc_method) (@owned FakeNSObject) -> @owned FakeNSObject
@@ -53,18 +56,18 @@
// CHECK-NEXT: [[RESULT:%.*]] = enum $Optional<Cat>, #Optional.some!enumelt.1, [[NEW_SELF]] : $Cat
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
// CHECK-NEXT: dealloc_stack [[SELF_BOX]] : $*Cat
- // CHECK-NEXT: br bb4([[RESULT]] : $Optional<Cat>)
+ // CHECK-NEXT: br bb5([[RESULT]] : $Optional<Cat>)
- // CHECK: bb3:
+ // CHECK: bb4:
// CHECK-NEXT: [[FIELD_ADDR:%.*]] = ref_element_addr %2 : $Cat, #Cat.x
// CHECK-NEXT: destroy_addr [[FIELD_ADDR]] : $*LifetimeTracked
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thick Cat.Type
// CHECK-NEXT: dealloc_partial_ref %2 : $Cat, [[METATYPE]] : $@thick Cat.Type
// CHECK-NEXT: dealloc_stack [[SELF_BOX]] : $*Cat
// CHECK-NEXT: [[RESULT:%.*]] = enum $Optional<Cat>, #Optional.none!enumelt
- // CHECK-NEXT: br bb4([[RESULT]] : $Optional<Cat>)
+ // CHECK-NEXT: br bb5([[RESULT]] : $Optional<Cat>)
- // CHECK: bb4([[RESULT:%.*]] : $Optional<Cat>):
+ // CHECK: bb5([[RESULT:%.*]] : $Optional<Cat>):
// CHECK-NEXT: return [[RESULT]] : $Optional<Cat>
init?(n: Int, after: Bool) {
diff --git a/test/SILOptimizer/definite_init_value_types.swift b/test/SILOptimizer/definite_init_value_types.swift
index ac8d8af..71bd780 100644
--- a/test/SILOptimizer/definite_init_value_types.swift
+++ b/test/SILOptimizer/definite_init_value_types.swift
@@ -33,10 +33,8 @@
// CHECK-NEXT: [[INIT_STATE:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK-NEXT: store [[INIT_STATE]] to [[STATE]]
// CHECK: [[BOOL:%.*]] = struct_extract %0 : $Bool, #Bool._value
- // CHECK-NEXT: cond_br [[BOOL]], bb2, bb1
+ // CHECK-NEXT: cond_br [[BOOL]], bb1, bb2
// CHECK: bb1:
- // CHECK-NEXT: br bb3
- // CHECK: bb2:
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin ValueEnum.Type
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $ValueEnum, #ValueEnum.b!enumelt
// CHECK-NEXT: [[SELF_ACCESS:%.*]] = begin_access [modify] [static] [[SELF_BOX]]
@@ -45,6 +43,8 @@
// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_ACCESS]]
// CHECK-NEXT: end_access [[SELF_ACCESS]]
// CHECK-NEXT: br bb3
+ // CHECK: bb2:
+ // CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin ValueEnum.Type
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $ValueEnum, #ValueEnum.c!enumelt
diff --git a/test/SILOptimizer/pointer_conversion_linux.swift b/test/SILOptimizer/pointer_conversion_linux.swift
index b307d44..94a1080 100644
--- a/test/SILOptimizer/pointer_conversion_linux.swift
+++ b/test/SILOptimizer/pointer_conversion_linux.swift
@@ -26,17 +26,12 @@
// CHECK: bb0:
// CHECK: switch_enum {{.*}}, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
- // CHECK: [[NONE_BB]]:
- // CHECK-NEXT: [[NO_POINTER:%.+]] = enum $Optional<UnsafeRawPointer>, #Optional.none!enumelt
- // CHECK-NEXT: [[NO_OWNER:%.+]] = enum $Optional<AnyObject>, #Optional.none!enumelt
- // CHECK-NEXT: br [[CALL_BRANCH:bb[0-9]+]]([[NO_POINTER]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
-
// CHECK: [[SOME_BB]](
// CHECK: [[OWNER:%.+]] = enum $Optional<AnyObject>, #Optional.some!enumelt.1,
// CHECK-NEXT: [[POINTER:%.+]] = struct $UnsafeRawPointer (
// CHECK-NEXT: [[DEP_POINTER:%.+]] = mark_dependence [[POINTER]] : $UnsafeRawPointer on [[OWNER]] : $Optional<AnyObject>
// CHECK-NEXT: [[OPT_POINTER:%.+]] = enum $Optional<UnsafeRawPointer>, #Optional.some!enumelt.1, [[DEP_POINTER]]
- // CHECK-NEXT: br [[CALL_BRANCH]]([[OPT_POINTER]] : $Optional<UnsafeRawPointer>, [[OWNER]] : $Optional<AnyObject>)
+ // CHECK-NEXT: br [[CALL_BRANCH:bb[0-9]+]]([[OPT_POINTER]] : $Optional<UnsafeRawPointer>, [[OWNER]] : $Optional<AnyObject>)
// CHECK: [[CALL_BRANCH]]([[OPT_POINTER:%.+]] : $Optional<UnsafeRawPointer>, [[OWNER:%.+]] : $Optional<AnyObject>):
// CHECK-NOT: release
@@ -49,4 +44,9 @@
// CHECK-NEXT: [[EMPTY:%.+]] = tuple ()
// CHECK-NEXT: return [[EMPTY]]
+ // CHECK: [[NONE_BB]]:
+ // CHECK-NEXT: [[NO_POINTER:%.+]] = enum $Optional<UnsafeRawPointer>, #Optional.none!enumelt
+ // CHECK-NEXT: [[NO_OWNER:%.+]] = enum $Optional<AnyObject>, #Optional.none!enumelt
+ // CHECK-NEXT: br [[CALL_BRANCH]]([[NO_POINTER]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
+
} // CHECK: end sil function '$s18pointer_conversion17testOptionalArrayyyF'
diff --git a/test/SILOptimizer/pointer_conversion_objc.swift b/test/SILOptimizer/pointer_conversion_objc.swift
index 8c36d9c..9787788 100644
--- a/test/SILOptimizer/pointer_conversion_objc.swift
+++ b/test/SILOptimizer/pointer_conversion_objc.swift
@@ -28,11 +28,6 @@
// CHECK: bb0:
// CHECK: switch_enum {{.*}}, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
- // CHECK: [[NONE_BB]]:
- // CHECK-NEXT: [[NO_POINTER:%.+]] = enum $Optional<UnsafeRawPointer>, #Optional.none!enumelt
- // CHECK-NEXT: [[NO_OWNER:%.+]] = enum $Optional<AnyObject>, #Optional.none!enumelt
- // CHECK-NEXT: br [[CALL_BRANCH:bb[0-9]+]]([[NO_POINTER]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
-
// CHECK: [[SOME_BB]](
// CHECK: cond_br {{%.*}}, {{bb[0-9]+}}, [[CHECK_BB:bb[0-9]+]]
@@ -44,7 +39,7 @@
// CHECK-NEXT: [[POINTER:%.+]] = struct $UnsafeRawPointer (
// CHECK-NEXT: [[DEP_POINTER:%.+]] = mark_dependence [[POINTER]] : $UnsafeRawPointer on [[OWNER]] : $Optional<AnyObject>
// CHECK-NEXT: [[OPT_POINTER:%.+]] = enum $Optional<UnsafeRawPointer>, #Optional.some!enumelt.1, [[DEP_POINTER]]
- // CHECK-NEXT: br [[CALL_BRANCH]]([[OPT_POINTER]] : $Optional<UnsafeRawPointer>, [[OWNER]] : $Optional<AnyObject>)
+ // CHECK-NEXT: br [[CALL_BRANCH:bb[0-9]+]]([[OPT_POINTER]] : $Optional<UnsafeRawPointer>, [[OWNER]] : $Optional<AnyObject>)
// CHECK: [[CALL_BRANCH]]([[OPT_POINTER:%.+]] : $Optional<UnsafeRawPointer>, [[OWNER:%.+]] : $Optional<AnyObject>):
// CHECK-NOT: release
@@ -57,4 +52,9 @@
// CHECK-NEXT: [[EMPTY:%.+]] = tuple ()
// CHECK-NEXT: return [[EMPTY]]
+ // CHECK: [[NONE_BB]]:
+ // CHECK-NEXT: [[NO_POINTER:%.+]] = enum $Optional<UnsafeRawPointer>, #Optional.none!enumelt
+ // CHECK-NEXT: [[NO_OWNER:%.+]] = enum $Optional<AnyObject>, #Optional.none!enumelt
+ // CHECK-NEXT: br [[CALL_BRANCH]]([[NO_POINTER]] : $Optional<UnsafeRawPointer>, [[NO_OWNER]] : $Optional<AnyObject>)
+
} // CHECK-LABEL: end sil function '$s18pointer_conversion17testOptionalArrayyyF'
diff --git a/test/SILOptimizer/switch_enum_objc.swift b/test/SILOptimizer/switch_enum_objc.swift
index 2582a1c..9829e9a 100644
--- a/test/SILOptimizer/switch_enum_objc.swift
+++ b/test/SILOptimizer/switch_enum_objc.swift
@@ -184,11 +184,11 @@
// CHECK-LABEL: sil hidden @$s16switch_enum_objc19testImperativeHeadsyySo4CoinVF
func testImperativeHeads(_ coin: Coin) {
- // CHECK: switch_enum %0 : $Coin, case #Coin.heads!enumelt: bb2, default bb1
+ // CHECK: switch_enum %0 : $Coin, case #Coin.heads!enumelt: bb1, default bb2
// CHECK: bb1:
- // CHECK: function_ref @$s16switch_enum_objc7action1
- // CHECK: bb2:
// CHECK: function_ref @$s16switch_enum_objc7action0
+ // CHECK: bb2:
+ // CHECK: function_ref @$s16switch_enum_objc7action1
if case .heads = coin {
action0()
} else {
@@ -198,11 +198,11 @@
// CHECK-LABEL: sil hidden @$s16switch_enum_objc19testImperativeTailsyySo4CoinVF
func testImperativeTails(_ coin: Coin) {
- // CHECK: switch_enum %0 : $Coin, case #Coin.tails!enumelt: bb2, default bb1
+ // CHECK: switch_enum %0 : $Coin, case #Coin.tails!enumelt: bb1, default bb2
// CHECK: bb1:
- // CHECK: function_ref @$s16switch_enum_objc7action1
- // CHECK: bb2:
// CHECK: function_ref @$s16switch_enum_objc7action0
+ // CHECK: bb2:
+ // CHECK: function_ref @$s16switch_enum_objc7action1
if case .tails = coin {
action0()
} else {
diff --git a/test/SILOptimizer/switch_enum_resilient.swift b/test/SILOptimizer/switch_enum_resilient.swift
index 5311165..55a3edf 100644
--- a/test/SILOptimizer/switch_enum_resilient.swift
+++ b/test/SILOptimizer/switch_enum_resilient.swift
@@ -210,7 +210,7 @@
// CHECK-NOINLINE-LABEL: sil{{.*}} @$s21switch_enum_resilient19testImperativeHeadsyyAA4CoinOF
public func testImperativeHeads(_ coin: Coin) {
- // CHECK-NOINLINE: switch_enum{{_addr %.+ : [$][*]Coin| %0 : [$]Coin}}, case #Coin.heads!enumelt: bb2, case #Coin.tails!enumelt: bb1 //
+ // CHECK-NOINLINE: switch_enum{{_addr %.+ : [$][*]Coin| %0 : [$]Coin}}, case #Coin.heads!enumelt: bb1, case #Coin.tails!enumelt: bb2 //
if case .heads = coin {
action0()
} else {
@@ -220,7 +220,7 @@
// CHECK-NOINLINE-LABEL: sil{{.*}} @$s21switch_enum_resilient19testImperativeTailsyyAA4CoinOF
public func testImperativeTails(_ coin: Coin) {
- // CHECK-NOINLINE: switch_enum{{_addr %.+ : [$][*]Coin| %0 : [$]Coin}}, case #Coin.tails!enumelt: bb2, case #Coin.heads!enumelt: bb1 //
+ // CHECK-NOINLINE: switch_enum{{_addr %.+ : [$][*]Coin| %0 : [$]Coin}}, case #Coin.tails!enumelt: bb1, case #Coin.heads!enumelt: bb2 //
if case .tails = coin {
action0()
} else {
@@ -233,7 +233,7 @@
// CHECK-FRAGILE-NOINLINE: [[FIVE:%.+]] = integer_literal ${{.+}}, 5000
// CHECK-FRAGILE-NOINLINE: [[NINE:%.+]] = integer_literal ${{.+}}, 9001
// CHECK-FRAGILE-NOINLINE: = select_enum %0 : $Coin, case #Coin.heads!enumelt: [[FIVE]], case #Coin.tails!enumelt: [[NINE]] :
- // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb2, case #Coin.tails!enumelt: bb1
+ // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb1, case #Coin.tails!enumelt: bb2
if case .heads = coin {
return 5000
} else {
@@ -246,7 +246,7 @@
// CHECK-FRAGILE-NOINLINE: [[FIVE:%.+]] = integer_literal ${{.+}}, 5000
// CHECK-FRAGILE-NOINLINE: [[NINE:%.+]] = integer_literal ${{.+}}, 9001
// CHECK-FRAGILE-NOINLINE: = select_enum %0 : $Coin, case #Coin.tails!enumelt: [[FIVE]], case #Coin.heads!enumelt: [[NINE]] :
- // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb2, case #Coin.heads!enumelt: bb1
+ // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb1, case #Coin.heads!enumelt: bb2
if case .tails = coin {
return 5000
} else {
@@ -306,7 +306,7 @@
// CHECK-FRAGILE: [[FIVE:%.+]] = integer_literal ${{.+}}, 5000
// CHECK-FRAGILE: [[NINE:%.+]] = integer_literal ${{.+}}, 9001
// CHECK-FRAGILE: = select_enum %0 : $Coin, case #Coin.heads!enumelt: [[FIVE]], case #Coin.tails!enumelt: [[NINE]] :
- // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb2, case #Coin.tails!enumelt: bb1 //
+ // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb{{[0-9]+}}, case #Coin.tails!enumelt: bb{{[0-9]+}} //
// CHECK-RESILIENT-INLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb2, default bb1
if case .heads = coin {
return 5000
@@ -320,7 +320,7 @@
// CHECK-FRAGILE: [[FIVE:%.+]] = integer_literal ${{.+}}, 5000
// CHECK-FRAGILE: [[NINE:%.+]] = integer_literal ${{.+}}, 9001
// CHECK-FRAGILE: = select_enum %0 : $Coin, case #Coin.tails!enumelt: [[FIVE]], case #Coin.heads!enumelt: [[NINE]] :
- // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb2, case #Coin.heads!enumelt: bb1 //
+ // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb{{[0-9]+}}, case #Coin.heads!enumelt: bb{{[0-9]+}} //
// CHECK-RESILIENT-INLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb2, default bb1
if case .tails = coin {
return 5000
@@ -332,8 +332,8 @@
// CHECK-ALL-LABEL: sil{{.*}} @$s21switch_enum_resilient21inlineImperativeHeadsyyAA4CoinOF
@inlinable public func inlineImperativeHeads(_ coin: Coin) {
- // CHECK-FRAGILE: switch_enum %0 : $Coin, case #Coin.heads!enumelt: bb2, case #Coin.tails!enumelt: bb1 //
- // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb2, case #Coin.tails!enumelt: bb1 //
+ // CHECK-FRAGILE: switch_enum %0 : $Coin, case #Coin.heads!enumelt: bb{{[0-9]+}}, case #Coin.tails!enumelt: bb{{[0-9]+}} //
+ // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb{{[0-9]+}}, case #Coin.tails!enumelt: bb{{[0-9]+}} //
// CHECK-RESILIENT-INLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.heads!enumelt: bb2, default bb1
if case .heads = coin {
action0()
@@ -344,8 +344,8 @@
// CHECK-ALL-LABEL: sil{{.*}} @$s21switch_enum_resilient21inlineImperativeTailsyyAA4CoinOF
@inlinable public func inlineImperativeTails(_ coin: Coin) {
- // CHECK-FRAGILE: switch_enum %0 : $Coin, case #Coin.tails!enumelt: bb2, case #Coin.heads!enumelt: bb1 //
- // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb2, case #Coin.heads!enumelt: bb1 //
+ // CHECK-FRAGILE: switch_enum %0 : $Coin, case #Coin.tails!enumelt: bb{{[0-9]+}}, case #Coin.heads!enumelt: bb{{[0-9]+}} //
+ // CHECK-RESILIENT-NOINLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb{{[0-9]+}}, case #Coin.heads!enumelt: bb{{[0-9]+}} //
// CHECK-RESILIENT-INLINE: switch_enum_addr {{%.+}} : $*Coin, case #Coin.tails!enumelt: bb2, default bb1
if case .tails = coin {
action0()