Skip to content

Commit 79c4d5d

Browse files
committed
[SILOptimzer] Fix a crash caused by SILCombine mishandling inlined variables
This showed up on and off again on the source-compatibility testsuite project hummingbird. The gist of the problem is that transformations may may not rewrite the type of an inlined instance of a variable without also createing a deep copy of the inlined function with a different name (and e.g., a specialization suffix). Otherwise the modified inlined variable will cause an inconsistency when later compiler passes try to create the abstract declaration of that inlined function as there would be conflicting declarations for that variable. Since SILDebugScope isn't yet available in the SwiftCompilerSources this fix just drop these variables, but it would be absolutely possible to preserve them by using the same mechanism that SILCloner uses to create a deep copy of the inlined function scopes. rdar://163167975
1 parent 7e8d8b6 commit 79c4d5d

File tree

4 files changed

+75
-5
lines changed

4 files changed

+75
-5
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,17 @@ private extension AllocStackInst {
225225
source: newAlloc, sourceFormalType: concreteFormalType,
226226
destination: ucca.destination, targetFormalType: ucca.targetFormalType)
227227
context.erase(instruction: ucca)
228+
case let dv as DebugValueInst:
229+
if dv.location.isInlined {
230+
// We cannot change the type of an inlined instance of a variable
231+
// without renaming the inlined function to get a unique
232+
// specialization suffix (prior art exists in
233+
// SILCloner::remapFunction()).
234+
// For now, just remove affected inlined variables.
235+
use.set(to: Undef.get(type: type, context), context)
236+
} else {
237+
use.set(to: newAlloc, context)
238+
}
228239
default:
229240
use.set(to: newAlloc, context)
230241
}

include/swift/SIL/TypeSubstCloner.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,14 +423,15 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
423423
// and types. We check if the function is called with non-identity substitutions
424424
// to decide whether it's necessary to clone a unique copy of the function
425425
// declaration with the substitutions applied for the debug info.
426-
if (SubsMap.isIdentity())
426+
if (SubsMap.isIdentity() &&
427+
!SubsMap.getRecursiveProperties().hasTypeParameter())
427428
return ParentFunction;
428429

429430
// Note that mapReplacementTypesOutOfContext() can't do anything for
430431
// opened existentials, and since archetypes can't be mangled, ignore
431432
// this case for now.
432433
if (SubsMap.getRecursiveProperties().hasLocalArchetype())
433-
return ParentFunction;
434+
SubsMap = {};
434435

435436
// Clone the function with the substituted type for the debug info.
436437
Mangle::GenericSpecializationMangler Mangler(M.getASTContext(), ParentFunction,

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,12 +1658,48 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
16581658
require(lhs == rhs ||
16591659
(lhs.isAddress() && lhs.getObjectType() == rhs) ||
16601660
(DebugVarTy.isAddress() && lhs == rhs.getObjectType()) ||
1661-
16621661
// When cloning SIL (e.g. in LoopUnroll) local archetypes are uniqued
16631662
// and therefore distinct in cloned instructions.
16641663
(lhs.hasLocalArchetype() && rhs.hasLocalArchetype()),
1665-
"Two variables with different type but same scope!");
1666-
}
1664+
"Two variables with different type but same scope");
1665+
}
1666+
1667+
// Check that all inlined function arguments agree on their types.
1668+
#ifdef EXPENSIVE_VERIFIER_CHECKS
1669+
if (unsigned ArgNo = varInfo->ArgNo)
1670+
if (varInfo->Scope)
1671+
if (SILFunction *Fn = varInfo->Scope->getInlinedFunction()) {
1672+
using ArgMap = llvm::StringMap<llvm::SmallVector<SILType, 8>>;
1673+
static ArgMap DebugArgs;
1674+
llvm::StringRef Key = Fn->getName();
1675+
if (!Key.empty()) {
1676+
auto [It, Inserted] = DebugArgs.insert({Key, {}});
1677+
auto &CachedArgs = It->second;
1678+
if (Inserted || (!Inserted && (CachedArgs.size() < ArgNo)) ||
1679+
(!Inserted && !CachedArgs[ArgNo - 1])) {
1680+
if (CachedArgs.size() < ArgNo)
1681+
CachedArgs.resize(ArgNo);
1682+
CachedArgs[ArgNo - 1] = DebugVarTy;
1683+
} else {
1684+
SILType CachedArg = CachedArgs[ArgNo - 1];
1685+
auto lhs = CachedArg.removingMoveOnlyWrapper();
1686+
auto rhs = DebugVarTy.removingMoveOnlyWrapper();
1687+
if (lhs != rhs) {
1688+
llvm::errs() << "***** " << varInfo->Name << "\n";
1689+
lhs.dump();
1690+
rhs.dump();
1691+
Fn->dump();
1692+
}
1693+
require(
1694+
lhs == rhs ||
1695+
(lhs.isAddress() && lhs.getObjectType() == rhs) ||
1696+
(DebugVarTy.isAddress() && lhs == rhs.getObjectType()) ||
1697+
(lhs.hasLocalArchetype() && rhs.hasLocalArchetype()),
1698+
"Conflicting types for function argument!");
1699+
}
1700+
}
1701+
}
1702+
#endif
16671703

16681704
// Check debug info expression
16691705
if (const auto &DIExpr = varInfo->DIExpr) {

test/SILOptimizer/simplify_alloc_stack.sil

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,28 @@ bb0(%0 : $*T, %1 : @owned $T):
312312
return %r
313313
}
314314

315+
// CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type3 :
316+
// CHECK: [[S:%.*]] = alloc_stack $T
317+
// CHECK-NOT: init_existential_addr
318+
// CHECK-NOT: open_existential_addr
319+
// CHECK: debug_value undef : $*any P, let, name "value1"
320+
// CHECK: destroy_addr [[S]]
321+
// CHECK: } // end sil function 'replace_existential_with_concrete_type3'
322+
sil_scope 1 { loc "a.swift":1:1 parent @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () }
323+
sil_scope 2 { loc "inlined.swift":1:1 parent @$inlined : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () inlined_at 1 }
324+
sil [ossa] @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () {
325+
bb0(%0 : @owned $T):
326+
%5 = alloc_stack $any P
327+
debug_value %5, let, name "value1", loc "inlined.swift":1:1, scope 2
328+
%6 = init_existential_addr %5, $T
329+
store %0 to [init] %6
330+
%8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self
331+
destroy_addr %8
332+
dealloc_stack %5
333+
%r = tuple ()
334+
return %r
335+
}
336+
315337
// CHECK-LABEL: sil [ossa] @replace_existential_with_archetype :
316338
// CHECK: [[S:%.*]] = alloc_stack $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", any P) Self
317339
// CHECK-NOT: init_existential_addr

0 commit comments

Comments
 (0)