Skip to content

Commit 7ff1066

Browse files
authored
Merge pull request #81480 from eeckstein/fix-fso
FunctionSignatureOptimization: don't convert indirect `@in` to `@in_guaranteed` if the argument is mutated
2 parents 01107f1 + 8cab792 commit 7ff1066

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed

include/swift/SIL/InstructionUtils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ lookUpFunctionInWitnessTable(WitnessMethodInst *wmi, SILModule::LinkingMode link
247247
/// struct-with-deinit drops the deinit.
248248
bool shouldExpand(SILModule &module, SILType ty);
249249

250+
/// Returns true if `arg` is mutated.
251+
/// if `ignoreDestroys` is true, `destroy_addr` instructions are ignored.
252+
/// `defaultIsMutating` specifies the state of instructions which are not explicitly handled.
253+
/// For historical reasons this utility is implemented in SILVerifier.cpp.
254+
bool isIndirectArgumentMutated(SILFunctionArgument *arg, bool ignoreDestroys = false,
255+
bool defaultIsMutating = false);
256+
250257
} // end namespace swift
251258

252259
#endif

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "swift/SIL/DebugUtils.h"
3636
#include "swift/SIL/Dominance.h"
3737
#include "swift/SIL/DynamicCasts.h"
38+
#include "swift/SIL/InstructionUtils.h"
3839
#include "swift/SIL/MemAccessUtils.h"
3940
#include "swift/SIL/OwnershipLiveness.h"
4041
#include "swift/SIL/OwnershipUtils.h"
@@ -572,6 +573,11 @@ void verifyKeyPathComponent(SILModule &M,
572573
/// open_existential_addr. We should expand it as needed.
573574
struct ImmutableAddressUseVerifier {
574575
SmallVector<Operand *, 32> worklist;
576+
bool ignoreDestroys;
577+
bool defaultIsMutating;
578+
579+
ImmutableAddressUseVerifier(bool ignoreDestroys = false, bool defaultIsMutating = false)
580+
: ignoreDestroys(ignoreDestroys), defaultIsMutating(defaultIsMutating) {}
575581

576582
bool isConsumingOrMutatingArgumentConvention(SILArgumentConvention conv) {
577583
switch (conv) {
@@ -704,10 +710,9 @@ struct ImmutableAddressUseVerifier {
704710
}
705711
}
706712

707-
// Otherwise this is a builtin that we are not expecting to see, so bail
708-
// and assert.
709-
llvm::errs() << "Unhandled, unexpected builtin instruction: " << *inst;
710-
llvm_unreachable("invoking standard assertion failure");
713+
// Otherwise this is a builtin that we are not expecting to see.
714+
if (defaultIsMutating)
715+
return true;
711716
break;
712717
}
713718
case SILInstructionKind::MarkDependenceInst:
@@ -775,7 +780,9 @@ struct ImmutableAddressUseVerifier {
775780
else
776781
break;
777782
case SILInstructionKind::DestroyAddrInst:
778-
return true;
783+
if (!ignoreDestroys)
784+
return true;
785+
break;
779786
case SILInstructionKind::UpcastInst:
780787
case SILInstructionKind::UncheckedAddrCastInst: {
781788
if (isAddrCastToNonConsuming(cast<SingleValueInstruction>(inst))) {
@@ -842,9 +849,7 @@ struct ImmutableAddressUseVerifier {
842849
}
843850
break;
844851
}
845-
llvm::errs() << "Unhandled, unexpected instruction: " << *inst;
846-
llvm_unreachable("invoking standard assertion failure");
847-
break;
852+
return true;
848853
}
849854
case SILInstructionKind::TuplePackElementAddrInst: {
850855
if (&cast<TuplePackElementAddrInst>(inst)->getOperandRef(
@@ -866,8 +871,8 @@ struct ImmutableAddressUseVerifier {
866871
return false;
867872
}
868873
default:
869-
llvm::errs() << "Unhandled, unexpected instruction: " << *inst;
870-
llvm_unreachable("invoking standard assertion failure");
874+
if (defaultIsMutating)
875+
return true;
871876
break;
872877
}
873878
}
@@ -7386,6 +7391,11 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
73867391
#undef require
73877392
#undef requireObjectType
73887393

7394+
bool swift::isIndirectArgumentMutated(SILFunctionArgument *arg, bool ignoreDestroys,
7395+
bool defaultIsMutating) {
7396+
return ImmutableAddressUseVerifier(ignoreDestroys, defaultIsMutating).isMutatingOrConsuming(arg);
7397+
}
7398+
73897399
//===----------------------------------------------------------------------===//
73907400
// Out of Line Verifier Run Functions
73917401
//===----------------------------------------------------------------------===//

lib/SILOptimizer/FunctionSignatureTransforms/OwnedToGuaranteedTransform.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ bool FunctionSignatureTransform::OwnedToGuaranteedAnalyzeParameters() {
8888
continue;
8989
}
9090

91+
// Make sure that an @in argument is not mutated otherwise than destroyed,
92+
// because an @in_guaranteed argument must not be mutated.
93+
if (A.hasConvention(SILArgumentConvention::Indirect_In) &&
94+
// With opaque values, @in arguments can have non-address types.
95+
A.Arg->getType().isAddress() &&
96+
isIndirectArgumentMutated(A.Arg, /*ignoreDestroys=*/ true, /*defaultIsMutating=*/true)) {
97+
continue;
98+
}
99+
91100
// See if we can find a ref count equivalent strong_release or release_value
92101
// at the end of this function if our argument is an @owned parameter.
93102
// See if we can find a destroy_addr at the end of this function if our

test/SILOptimizer/functionsigopts_crash.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,21 @@ func testit(_ p: P) {
3535
public func callit(s: S) {
3636
testit(s)
3737
}
38+
39+
// Check that FSO does not trigger a verifier error caused by a mutated @in argument which is
40+
// converted to an @in_guaranteed argument (which must not be mutated).
41+
42+
public protocol IP<Element> {
43+
associatedtype Element
44+
45+
init<Iterator>(iterator: consuming Iterator) where Iterator: IteratorProtocol, Iterator.Element == Element
46+
}
47+
48+
extension Array: IP {
49+
public init<Iterator>(iterator: consuming Iterator) where Iterator: IteratorProtocol, Iterator.Element == Element {
50+
self.init()
51+
while let next = iterator.next() {
52+
append(next)
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)