Skip to content

Commit 54b0070

Browse files
authored
Merge pull request #81497 from eeckstein/fix-fso-6.2
[6.2] FunctionSignatureOptimization: don't convert indirect `@in` to `@in_guaranteed` if the argument is mutated
2 parents 2853f62 + 881351b commit 54b0070

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))) {
@@ -841,9 +848,7 @@ struct ImmutableAddressUseVerifier {
841848
}
842849
break;
843850
}
844-
llvm::errs() << "Unhandled, unexpected instruction: " << *inst;
845-
llvm_unreachable("invoking standard assertion failure");
846-
break;
851+
return true;
847852
}
848853
case SILInstructionKind::TuplePackElementAddrInst: {
849854
if (&cast<TuplePackElementAddrInst>(inst)->getOperandRef(
@@ -865,8 +870,8 @@ struct ImmutableAddressUseVerifier {
865870
return false;
866871
}
867872
default:
868-
llvm::errs() << "Unhandled, unexpected instruction: " << *inst;
869-
llvm_unreachable("invoking standard assertion failure");
873+
if (defaultIsMutating)
874+
return true;
870875
break;
871876
}
872877
}
@@ -7385,6 +7390,11 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
73857390
#undef require
73867391
#undef requireObjectType
73877392

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

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)