Skip to content

Commit b0bb19c

Browse files
authored
Merge pull request #78524 from eeckstein/fix-codemotion
Fix two bugs which cause SIL verification errors
2 parents ce3cc37 + b80a08e commit b0bb19c

File tree

5 files changed

+83
-5
lines changed

5 files changed

+83
-5
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/Verifier.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,11 @@ private struct MutatingUsesWalker : AddressDefUseWalker {
164164

165165
for use in startInst.uses {
166166
if let phi = Phi(using: use) {
167-
linearLiveranges.pushIfNotVisited(phi.borrowedFrom!)
167+
if let bf = phi.borrowedFrom {
168+
linearLiveranges.pushIfNotVisited(bf)
169+
} else {
170+
require(false, "missing borrowed-from for \(phi.value)")
171+
}
168172
}
169173
}
170174
}

lib/SILOptimizer/Transforms/SILCodeMotion.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,16 @@ static bool sinkArgument(EnumCaseDataflowContext &Context, SILBasicBlock *BB, un
11841184
if (hasOwnershipOperandsOrResults(FSI))
11851185
return false;
11861186

1187+
// Even if the incoming instruction has no ownership, the argument may have.
1188+
// This can happen with enums which are constructed with a non-payload case:
1189+
//
1190+
// %1 = enum $Optional<C>, #Optional.none!enumelt
1191+
// br bb3(%1)
1192+
// bb1(%3 : @owned $Optional<C>):
1193+
//
1194+
if (BB->getArgument(ArgNum)->getOwnershipKind() != OwnershipKind::None)
1195+
return false;
1196+
11871197
// The list of identical instructions.
11881198
SmallVector<SingleValueInstruction *, 8> Clones;
11891199
Clones.push_back(FSI);

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3850,11 +3850,21 @@ static void tryToReplaceArgWithIncomingValue(SILBasicBlock *BB, unsigned i,
38503850
// An argument has one result value. We need to replace this with the *value*
38513851
// of the incoming block(s).
38523852
LLVM_DEBUG(llvm::dbgs() << "replace arg with incoming value:" << *A);
3853-
if (auto *bfi = getBorrowedFromUser(A)) {
3854-
bfi->replaceAllUsesWith(A);
3855-
bfi->eraseFromParent();
3853+
while (!A->use_empty()) {
3854+
Operand *op = *A->use_begin();
3855+
if (auto *bfi = dyn_cast<BorrowedFromInst>(op->getUser())) {
3856+
if (op->getOperandNumber() == 0) {
3857+
bfi->replaceAllUsesWith(V);
3858+
bfi->eraseFromParent();
3859+
continue;
3860+
}
3861+
if (auto *prevBfi = dyn_cast<BorrowedFromInst>(V)) {
3862+
op->set(prevBfi->getBorrowedValue());
3863+
continue;
3864+
}
3865+
}
3866+
op->set(V);
38563867
}
3857-
A->replaceAllUsesWith(V);
38583868
}
38593869

38603870
bool SimplifyCFG::simplifyArgs(SILBasicBlock *BB) {

test/SILOptimizer/earlycodemotion.sil

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,28 @@ bb3(%12 : $Bool):
552552
return %12 : $Bool
553553
}
554554

555+
// CHECK-LABEL: sil [ossa] @dont_sink_owned_trivial_enum :
556+
// CHECK: bb1:
557+
// CHECK-NEXT: enum
558+
// CHECK: bb2:
559+
// CHECK-NEXT: enum
560+
// CHECK: bb3([[A:%.*]] : @owned $Optional<C>):
561+
// CHECK-NEXT: return [[A]]
562+
// CHECK: } // end sil function 'dont_sink_owned_trivial_enum'
563+
sil [ossa] @dont_sink_owned_trivial_enum : $@convention(thin) () -> @owned Optional<C> {
564+
bb0:
565+
cond_br undef, bb1, bb2
566+
bb1:
567+
%2 = enum $Optional<C>, #Optional.none!enumelt
568+
br bb3(%2)
569+
bb2:
570+
%4 = enum $Optional<C>, #Optional.none!enumelt
571+
br bb3(%4)
572+
bb3(%6 : @owned $Optional<C>):
573+
return %6
574+
}
575+
576+
555577
// Sink retain down the successors so we can pair up retain with release on the
556578
// fast path.
557579
class Test {

test/SILOptimizer/simplify_cfg_ossa.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,3 +1939,35 @@ bb3:
19391939
return %t : $()
19401940
}
19411941

1942+
// CHECK-LABEL: sil [ossa] @replace_phi_arg_with_borrowed_from_use :
1943+
// CHECK: bb3([[R:%.*]] : @reborrow $B):
1944+
// CHECK: bb6([[G:%.*]] : @guaranteed $E):
1945+
// CHECK-NEXT: [[X:%.*]] = borrowed [[G]] : $E from ([[R]] : $B)
1946+
// CHECK-NEXT: fix_lifetime [[X]]
1947+
// CHECK: } // end sil function 'replace_phi_arg_with_borrowed_from_use'
1948+
sil [ossa] @replace_phi_arg_with_borrowed_from_use : $@convention(thin) (@in_guaranteed B) -> () {
1949+
bb0(%0 : $*B):
1950+
cond_br undef, bb1, bb2
1951+
bb1:
1952+
%4 = load_borrow %0
1953+
br bb3(%4)
1954+
bb2:
1955+
%6 = load_borrow %0
1956+
br bb3(%6)
1957+
bb3(%8 : @reborrow $B):
1958+
%9 = borrowed %8 from ()
1959+
cond_br undef, bb4, bb5
1960+
bb4:
1961+
%11 = unchecked_ref_cast %9 to $E
1962+
br bb6(%11, %9)
1963+
bb5:
1964+
%13 = unchecked_ref_cast %9 to $E
1965+
br bb6(%13, %9)
1966+
bb6(%15: @guaranteed $E, %16 : @reborrow $B):
1967+
%17 = borrowed %15 from (%16)
1968+
%18 = borrowed %16 from ()
1969+
fix_lifetime %17
1970+
end_borrow %18
1971+
%r = tuple()
1972+
return %r
1973+
}

0 commit comments

Comments
 (0)