Skip to content

Commit c871197

Browse files
committed
Swift SIL: fix ApplySite.callerArgIndex
It needs to return nil in case the callee argument is not really applied by the ApplySite. This fixes a crash in EscapeInfo when handling "escaping-to" effects: If the callee operand of an apply instruction is a `partial_apply` of a `function_ref`, the callee-analysis looks through the `partial_apply` and we get the referenced function as a callee. In this case there are less apply arguments than callee arguments, because the `partial_apply` already "applies" some of the callee arguments. rdar://96830171
1 parent 872d4ff commit c871197

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

SwiftCompilerSources/Sources/SIL/ApplySite.swift

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,46 @@ public protocol ApplySite : Instruction {
2121
var operands: OperandArray { get }
2222
var numArguments: Int { get }
2323
var substitutionMap: SubstitutionMap { get }
24+
25+
/// Converts an argument index of the apply to the corresponding argument index of the callee.
26+
///
27+
/// For a FullApplySite this is always a 1-to-1 mapping.
28+
/// For a `partial_apply` the callee index can be higher than the caller's argument index
29+
/// because the arguments to `partial_apply` are a suffix of the callee.
30+
///
31+
/// Example:
32+
/// ```
33+
/// func callee(a, b, c, d, e) { }
34+
///
35+
/// %pa = partial_apply @callee(c, d, e)
36+
/// // caller indices: 0, 1, 2
37+
/// // callee indices: 2, 3, 4
38+
///
39+
/// %a = apply %pa (a, b)
40+
/// // caller indices: 0, 1
41+
/// // callee indices: 0, 1
42+
/// ```
2443
func calleeArgIndex(callerArgIndex: Int) -> Int
44+
45+
/// Converts an argument index of a callee to the corresponding argument index of the apply.
46+
///
47+
/// If the apply does not actually apply that argument, it returns nil.
48+
/// Otherwise, for a FullApplySite this is always a 1-to-1 mapping.
49+
/// For a `partial_apply` the caller index can be lower than the callee's argument index
50+
/// because the arguments to `partial_apply` are a suffix of the callee.
51+
///
52+
/// Example:
53+
/// ```
54+
/// func callee(a, b, c, d, e) { }
55+
/// // callee indices: 0, 1, 2, 3, 4
56+
/// // caller indices in %pa: -, -, 0, 1, 2 ("-" == nil)
57+
/// // caller indices in %a: 0, 1, -, -, -
58+
///
59+
/// %pa = partial_apply @callee(c, d, e)
60+
/// %a = apply %pa (a, b)
61+
/// ```
2562
func callerArgIndex(calleeArgIndex: Int) -> Int?
63+
2664
func getArgumentConvention(calleeArgIndex: Int) -> ArgumentConvention
2765
}
2866

@@ -66,6 +104,15 @@ public protocol FullApplySite : ApplySite {
66104
}
67105

68106
extension FullApplySite {
69-
public func calleeArgIndex(callerArgIndex: Int) -> Int { callerArgIndex }
70-
public func callerArgIndex(calleeArgIndex: Int) -> Int? { calleeArgIndex }
107+
public func calleeArgIndex(callerArgIndex: Int) -> Int {
108+
assert(callerArgIndex >= 0 && callerArgIndex < numArguments)
109+
return callerArgIndex
110+
}
111+
112+
public func callerArgIndex(calleeArgIndex: Int) -> Int? {
113+
if calleeArgIndex < numArguments {
114+
return calleeArgIndex
115+
}
116+
return nil
117+
}
71118
}

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,10 @@ final public class PartialApplyInst : SingleValueInstruction, ApplySite {
514514
public func callerArgIndex(calleeArgIndex: Int) -> Int? {
515515
let firstIdx = PartialApply_getCalleeArgIndexOfFirstAppliedArg(bridged)
516516
if calleeArgIndex >= firstIdx {
517-
return calleeArgIndex - firstIdx
517+
let callerIdx = calleeArgIndex - firstIdx
518+
if callerIdx < numArguments {
519+
return callerIdx
520+
}
518521
}
519522
return nil
520523
}

test/SILOptimizer/escape_info.sil

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,8 @@ bb0(%0 : @owned $Z):
968968
sil [ossa] [escapes !%1] @closure1 : $@convention(thin) (@guaranteed Y, @guaranteed Y) -> ()
969969
sil [ossa] [escapes !%0] @closure2 : $@convention(thin) (@guaranteed Y, @guaranteed Y) -> ()
970970
sil [escapes !%0.**] @closure3 : $@convention(thin) (@guaranteed Z) -> ()
971+
sil [ossa] [escapes %0 => %1, !%1] @closure4 : $@convention(thin) (@guaranteed X, @guaranteed Y) -> ()
972+
sil [ossa] [escapes %1 => %0, !%1] @closure5 : $@convention(thin) (@guaranteed Y, @guaranteed X) -> ()
971973

972974
// CHECK-LABEL: Escape information for callClosure1:
973975
// CHECK: - : %0 = alloc_ref $Y
@@ -1019,6 +1021,40 @@ bb0:
10191021
return %6 : $()
10201022
}
10211023

1024+
// CHECK-LABEL: Escape information for callClosureWithEscapesToEffect1:
1025+
// CHECK: - : %0 = alloc_ref $Y
1026+
// CHECK: global: %1 = alloc_ref $X
1027+
// CHECK: End function callClosureWithEscapesToEffect1
1028+
sil [ossa] @callClosureWithEscapesToEffect1 : $@convention(thin) () -> () {
1029+
bb0:
1030+
%0 = alloc_ref $Y
1031+
%1 = alloc_ref $X
1032+
%2 = function_ref @closure4 : $@convention(thin) (@guaranteed X, @guaranteed Y) -> ()
1033+
%3 = partial_apply [callee_guaranteed] %2(%0) : $@convention(thin) (@guaranteed X, @guaranteed Y) -> ()
1034+
%8 = apply %3(%1) : $@callee_guaranteed (@guaranteed X) -> ()
1035+
destroy_value %3 : $@callee_guaranteed (@guaranteed X) -> ()
1036+
destroy_value %1 : $X
1037+
%11 = tuple ()
1038+
return %11 : $()
1039+
}
1040+
1041+
// CHECK-LABEL: Escape information for callClosureWithEscapesToEffect2:
1042+
// CHECK: global: %0 = alloc_ref $Y
1043+
// CHECK: - : %1 = alloc_ref $X
1044+
// CHECK: End function callClosureWithEscapesToEffect2
1045+
sil [ossa] @callClosureWithEscapesToEffect2 : $@convention(thin) () -> () {
1046+
bb0:
1047+
%0 = alloc_ref $Y
1048+
%1 = alloc_ref $X
1049+
%2 = function_ref @closure5 : $@convention(thin) (@guaranteed Y, @guaranteed X) -> ()
1050+
%3 = partial_apply [callee_guaranteed] %2(%1) : $@convention(thin) (@guaranteed Y, @guaranteed X) -> ()
1051+
%8 = apply %3(%0) : $@callee_guaranteed (@guaranteed Y) -> ()
1052+
destroy_value %3 : $@callee_guaranteed (@guaranteed Y) -> ()
1053+
destroy_value %0 : $Y
1054+
%11 = tuple ()
1055+
return %11 : $()
1056+
}
1057+
10221058
// CHECK-LABEL: Escape information for escape_via_destroy_of_closure:
10231059
// CHECK: - : %0 = alloc_ref $Z
10241060
// CHECK: global: %1 = alloc_ref $Y

0 commit comments

Comments
 (0)