mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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 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
This commit is contained in:
@@ -225,6 +225,17 @@ private extension AllocStackInst {
|
||||
source: newAlloc, sourceFormalType: concreteFormalType,
|
||||
destination: ucca.destination, targetFormalType: ucca.targetFormalType)
|
||||
context.erase(instruction: ucca)
|
||||
case let dv as DebugValueInst:
|
||||
if dv.location.isInlined {
|
||||
// We cannot change the type of an inlined instance of a variable
|
||||
// without renaming the inlined function to get a unique
|
||||
// specialization suffix (prior art exists in
|
||||
// SILCloner::remapFunction()).
|
||||
// For now, just remove affected inlined variables.
|
||||
use.set(to: Undef.get(type: type, context), context)
|
||||
} else {
|
||||
use.set(to: newAlloc, context)
|
||||
}
|
||||
default:
|
||||
use.set(to: newAlloc, context)
|
||||
}
|
||||
|
||||
@@ -423,14 +423,15 @@ protected:
|
||||
// and types. We check if the function is called with non-identity substitutions
|
||||
// to decide whether it's necessary to clone a unique copy of the function
|
||||
// declaration with the substitutions applied for the debug info.
|
||||
if (SubsMap.isIdentity())
|
||||
if (SubsMap.isIdentity() &&
|
||||
!SubsMap.getRecursiveProperties().hasTypeParameter())
|
||||
return ParentFunction;
|
||||
|
||||
// Note that mapReplacementTypesOutOfContext() can't do anything for
|
||||
// opened existentials, and since archetypes can't be mangled, ignore
|
||||
// this case for now.
|
||||
if (SubsMap.getRecursiveProperties().hasLocalArchetype())
|
||||
return ParentFunction;
|
||||
SubsMap = {};
|
||||
|
||||
// Clone the function with the substituted type for the debug info.
|
||||
Mangle::GenericSpecializationMangler Mangler(M.getASTContext(), ParentFunction,
|
||||
|
||||
@@ -1658,13 +1658,49 @@ public:
|
||||
require(lhs == rhs ||
|
||||
(lhs.isAddress() && lhs.getObjectType() == rhs) ||
|
||||
(DebugVarTy.isAddress() && lhs == rhs.getObjectType()) ||
|
||||
|
||||
// When cloning SIL (e.g. in LoopUnroll) local archetypes are uniqued
|
||||
// and therefore distinct in cloned instructions.
|
||||
(lhs.hasLocalArchetype() && rhs.hasLocalArchetype()),
|
||||
"Two variables with different type but same scope!");
|
||||
"Two variables with different type but same scope");
|
||||
}
|
||||
|
||||
// Check that all inlined function arguments agree on their types.
|
||||
#ifdef EXPENSIVE_VERIFIER_CHECKS
|
||||
if (unsigned ArgNo = varInfo->ArgNo)
|
||||
if (varInfo->Scope)
|
||||
if (SILFunction *Fn = varInfo->Scope->getInlinedFunction()) {
|
||||
using ArgMap = llvm::StringMap<llvm::SmallVector<SILType, 8>>;
|
||||
static ArgMap DebugArgs;
|
||||
llvm::StringRef Key = Fn->getName();
|
||||
if (!Key.empty()) {
|
||||
auto [It, Inserted] = DebugArgs.insert({Key, {}});
|
||||
auto &CachedArgs = It->second;
|
||||
if (Inserted || (!Inserted && (CachedArgs.size() < ArgNo)) ||
|
||||
(!Inserted && !CachedArgs[ArgNo - 1])) {
|
||||
if (CachedArgs.size() < ArgNo)
|
||||
CachedArgs.resize(ArgNo);
|
||||
CachedArgs[ArgNo - 1] = DebugVarTy;
|
||||
} else {
|
||||
SILType CachedArg = CachedArgs[ArgNo - 1];
|
||||
auto lhs = CachedArg.removingMoveOnlyWrapper();
|
||||
auto rhs = DebugVarTy.removingMoveOnlyWrapper();
|
||||
if (lhs != rhs) {
|
||||
llvm::errs() << "***** " << varInfo->Name << "\n";
|
||||
lhs.dump();
|
||||
rhs.dump();
|
||||
Fn->dump();
|
||||
}
|
||||
require(
|
||||
lhs == rhs ||
|
||||
(lhs.isAddress() && lhs.getObjectType() == rhs) ||
|
||||
(DebugVarTy.isAddress() && lhs == rhs.getObjectType()) ||
|
||||
(lhs.hasLocalArchetype() && rhs.hasLocalArchetype()),
|
||||
"Conflicting types for function argument!");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check debug info expression
|
||||
if (const auto &DIExpr = varInfo->DIExpr) {
|
||||
bool HasFragment = false;
|
||||
|
||||
@@ -102,7 +102,7 @@ public class C<R> {
|
||||
// IR-DAG: ![[GRS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GRS_T:[0-9]+]], {{.*}}type: ![[LET_TUPLE:[0-9]+]]
|
||||
// IR-DAG: ![[SP_GRS_T]] = {{.*}}linkageName: "$s1A1gyyxlFx_qd__t_Ti5"
|
||||
// IR-DAG: ![[GRS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GRS_U:[0-9]+]], {{.*}}type: ![[LET_TUPLE:[0-9]+]]
|
||||
// IR-DAG: ![[SP_GRS_U]] = {{.*}}linkageName: "$s1A1hyyxlFx_qd__t_Ti5"
|
||||
// IR-DAG: ![[SP_GRS_U]] = {{.*}}linkageName: "$s1A1hyyxlFx_Ti5x_qd__t_Ti5"
|
||||
// IR-DAG: ![[LET_TUPLE]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[TUPLE:[0-9]+]])
|
||||
// IR-DAG: ![[TUPLE]] = {{.*}}DW_TAG_structure_type, name: "$sx_qd__tD"
|
||||
// IR-DAG: ![[S]] = !DILocalVariable(name: "s", {{.*}} type: ![[LET_TAU_1_0:[0-9]+]]
|
||||
@@ -110,7 +110,7 @@ public class C<R> {
|
||||
// IR-DAG: ![[GS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GS_T:[0-9]+]], {{.*}} type: ![[LET_TAU_1_0]])
|
||||
// IR-DAG: ![[SP_GS_T]] = {{.*}}linkageName: "$s1A1gyyxlFqd___Ti5"
|
||||
// IR-DAG: ![[GS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GS_U:[0-9]+]], {{.*}} type: ![[LET_TAU_1_0]])
|
||||
// IR-DAG: ![[SP_GS_U]] = {{.*}}linkageName: "$s1A1hyyxlFqd___Ti5"
|
||||
// IR-DAG: ![[SP_GS_U]] = {{.*}}linkageName: "$s1A1hyyxlFx_Ti5qd___Ti5"
|
||||
|
||||
// Debug info for this variable is removed. See the note above the call to g(r).
|
||||
// ![[GR_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GR_T:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]])
|
||||
@@ -118,12 +118,12 @@ public class C<R> {
|
||||
// ![[SP_GR_T]] = {{.*}}linkageName: "$s1A1gyyxlF"
|
||||
|
||||
// IR-DAG: ![[GR_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GR_U:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]])
|
||||
// IR-DAG: ![[SP_GR_U]] = {{.*}}linkageName: "$s1A1hyyxlF"
|
||||
// IR-DAG: ![[SP_GR_U]] = {{.*}}linkageName: "$s1A1hyyxlFx_Ti5x_Ti5"
|
||||
// IR-DAG: ![[GI_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GI_G:[0-9]+]], {{.*}}type: ![[LET_INT]])
|
||||
// IR-DAG: ![[SP_GI_G]] = {{.*}}linkageName: "$s1A1gyyxlFSi_Tg5"
|
||||
// IR-DAG: ![[GI_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GI_U:[0-9]+]], {{.*}}type: ![[LET_INT]])
|
||||
// IR-DAG: ![[SP_GI_U]] = {{.*}}linkageName: "$s1A1hyyxlFSi_TG5"
|
||||
// IR-DAG: ![[SP_GI_U]] = {{.*}}linkageName: "$s1A1hyyxlFx_Ti5Si_TG5"
|
||||
// IR-DAG: ![[GB_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GB_G:[0-9]+]], {{.*}}type: ![[LET_BOOL]])
|
||||
// IR-DAG: ![[SP_GB_G]] = {{.*}}linkageName: "$s1A1gyyxlFSb_Tg5"
|
||||
// IR-DAG: ![[GB_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GB_U:[0-9]+]], {{.*}}type: ![[LET_BOOL]])
|
||||
// IR-DAG: ![[SP_GB_U]] = {{.*}}linkageName: "$s1A1hyyxlFSb_TG5"
|
||||
// IR-DAG: ![[SP_GB_U]] = {{.*}}linkageName: "$s1A1hyyxlFx_Ti5Sb_TG5"
|
||||
|
||||
@@ -415,9 +415,10 @@ func test13_2() -> Bool {
|
||||
|
||||
// CHECK-LABEL: sil hidden [noinline] @$s12cast_folding8test13_3SbyF : $@convention(thin) () -> Bool
|
||||
// CHECK: bb0
|
||||
// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %1 = struct $Bool
|
||||
// CHECK-NEXT: return %1
|
||||
// CHECK-NEXT: debug_value
|
||||
// CHECK-NEXT: %1 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %2 = struct $Bool
|
||||
// CHECK-NEXT: return %2
|
||||
@inline(never)
|
||||
func test13_3() -> Bool {
|
||||
return cast13(A() as P)
|
||||
@@ -456,9 +457,10 @@ func test15_1() -> Bool {
|
||||
|
||||
// CHECK-LABEL: sil hidden [noinline] @$s12cast_folding8test15_2SbyF : $@convention(thin) () -> Bool
|
||||
// CHECK: bb0
|
||||
// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %1 = struct $Bool
|
||||
// CHECK-NEXT: return %1
|
||||
// CHECK-NEXT: debug_value
|
||||
// CHECK-NEXT: %1 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %2 = struct $Bool
|
||||
// CHECK-NEXT: return %2
|
||||
@inline(never)
|
||||
func test15_2() -> Bool {
|
||||
return cast15(A() as P)
|
||||
@@ -476,9 +478,10 @@ func test16_1() -> Bool {
|
||||
|
||||
// CHECK-LABEL: sil hidden [noinline] @$s12cast_folding8test16_2SbyF : $@convention(thin) () -> Bool
|
||||
// CHECK: bb0
|
||||
// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %1 = struct $Bool
|
||||
// CHECK-NEXT: return %1
|
||||
// CHECK-NEXT: debug_value
|
||||
// CHECK-NEXT: %1 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %2 = struct $Bool
|
||||
// CHECK-NEXT: return %2
|
||||
@inline(never)
|
||||
func test16_2() -> Bool {
|
||||
return cast16(A() as P)
|
||||
@@ -566,9 +569,10 @@ func test21_1() -> Bool {
|
||||
|
||||
// CHECK-LABEL: sil hidden [noinline] @$s12cast_folding8test21_2SbyF : $@convention(thin) () -> Bool
|
||||
// CHECK: bb0
|
||||
// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %1 = struct $Bool
|
||||
// CHECK-NEXT: return %1
|
||||
// CHECK-NEXT: debug_value
|
||||
// CHECK-NEXT: %1 = integer_literal $Builtin.Int1, -1
|
||||
// CHECK-NEXT: %2 = struct $Bool
|
||||
// CHECK-NEXT: return %2
|
||||
@inline(never)
|
||||
func test21_2() -> Bool {
|
||||
return cast21(A() as P)
|
||||
|
||||
@@ -312,6 +312,28 @@ bb0(%0 : $*T, %1 : @owned $T):
|
||||
return %r
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @replace_existential_with_concrete_type3 :
|
||||
// CHECK: [[S:%.*]] = alloc_stack $T
|
||||
// CHECK-NOT: init_existential_addr
|
||||
// CHECK-NOT: open_existential_addr
|
||||
// CHECK: debug_value undef : $*any P, let, name "value1"
|
||||
// CHECK: destroy_addr [[S]]
|
||||
// CHECK: } // end sil function 'replace_existential_with_concrete_type3'
|
||||
sil_scope 1 { loc "a.swift":1:1 parent @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () }
|
||||
sil_scope 2 { loc "inlined.swift":1:1 parent @$inlined : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () inlined_at 1 }
|
||||
sil [ossa] @replace_existential_with_concrete_type3 : $@convention(thin) (@owned T) -> () {
|
||||
bb0(%0 : @owned $T):
|
||||
%5 = alloc_stack $any P
|
||||
debug_value %5, let, name "value1", loc "inlined.swift":1:1, scope 2
|
||||
%6 = init_existential_addr %5, $T
|
||||
store %0 to [init] %6
|
||||
%8 = open_existential_addr mutable_access %5 to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", P) Self
|
||||
destroy_addr %8
|
||||
dealloc_stack %5
|
||||
%r = tuple ()
|
||||
return %r
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @replace_existential_with_archetype :
|
||||
// CHECK: [[S:%.*]] = alloc_stack $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", any P) Self
|
||||
// CHECK-NOT: init_existential_addr
|
||||
|
||||
@@ -35,7 +35,7 @@ public func fooCaller<T: AdditiveArithmetic>(_ x: T, _ y : T) -> T {
|
||||
// BEGIN Main.swift
|
||||
import MyModule
|
||||
// sil_scope should refer to the specialized version of foo
|
||||
//CHECK: sil_scope {{.*}} { loc "{{.*}}MyModule.swift":13:6 parent @$s8MyModule3fooyxx_xts18AdditiveArithmeticRzlFSi_TG5 {{.*}} inlined_at {{.*}} }
|
||||
//CHECK: sil_scope {{.*}} { loc "{{.*}}MyModule.swift":13:6 parent @$s8MyModule3fooyxx_xts18AdditiveArithmeticRzlFx_Ti5Si_TG5 {{.*}} inlined_at {{.*}} }
|
||||
let _ = fooCaller(1, 2)
|
||||
|
||||
func test() {
|
||||
|
||||
Reference in New Issue
Block a user