Skip to content

Commit a15eff3

Browse files
committed
IRGen: Fix partial applies of generic functions capturing the generic parameters in an argument
The code assumed if there is no context object but rather the captured argument is reused as the context object that the parameter index for this argument is going to be the last one. This is not true if there are empty types in the parameter list. rdar://33502272
1 parent aca4cae commit a15eff3

File tree

2 files changed

+73
-12
lines changed

2 files changed

+73
-12
lines changed

lib/IRGen/GenFunc.cpp

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,41 @@ static CanType getArgumentLoweringType(CanType type,
705705
}
706706
}
707707

708+
static bool isABIIgnoredParameterWithoutStorage(IRGenModule &IGM,
709+
IRGenFunction &IGF,
710+
CanSILFunctionType substType,
711+
unsigned paramIdx) {
712+
auto param = substType->getParameters()[paramIdx];
713+
SILType argType = IGM.silConv.getSILType(param);
714+
auto argLoweringTy =
715+
getArgumentLoweringType(argType.getSwiftRValueType(), param);
716+
auto &ti = IGF.getTypeInfoForLowered(argLoweringTy);
717+
// Empty values don't matter.
718+
return ti.getSchema().size() == 0 && !param.isFormalIndirect();
719+
}
720+
721+
/// Find the parameter index for the one (assuming there was only one) partially
722+
/// applied argument ignoring empty types that are not passed as part of the
723+
/// ABI.
724+
static unsigned findSinglePartiallyAppliedParameterIndexIgnoringEmptyTypes(
725+
IRGenFunction &IGF, CanSILFunctionType substType,
726+
CanSILFunctionType outType) {
727+
auto substParameters = substType->getParameters();
728+
auto outParamters = outType->getParameters();
729+
unsigned firstNonEmpty = -1U;
730+
for (unsigned paramIdx = outParamters.size() ; paramIdx != substParameters.size(); ++paramIdx) {
731+
bool isEmpty =
732+
isABIIgnoredParameterWithoutStorage(IGF.IGM, IGF, substType, paramIdx);
733+
assert((isEmpty || firstNonEmpty == -1U) && "Expect at most one partially "
734+
"applied that is passed as an "
735+
"ABI argument");
736+
if (!isEmpty)
737+
firstNonEmpty = paramIdx;
738+
}
739+
assert(firstNonEmpty != -1U);
740+
return firstNonEmpty;
741+
}
742+
708743
/// Emit the forwarding stub function for a partial application.
709744
///
710745
/// If 'layout' is null, there is a single captured value of
@@ -924,11 +959,9 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
924959
// care for the former for the purpose of reconstructing polymorphic
925960
// parameters from regular arguments.
926961
if (!calleeHasContext) {
927-
unsigned paramI = substType->getParameters().size() - 1;
928-
assert(substType->getParameters().size() -
929-
outType->getParameters().size() ==
930-
1 &&
931-
"Expect one partially applied argument");
962+
unsigned paramI =
963+
findSinglePartiallyAppliedParameterIndexIgnoringEmptyTypes(
964+
subIGF, substType, outType);
932965
auto paramInfo = substType->getParameters()[paramI];
933966
auto &ti = IGM.getTypeInfoForLowered(paramInfo.getType());
934967
Explosion param;
@@ -1097,13 +1130,8 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
10971130

10981131
// Skip empty parameters.
10991132
while (origParamI < origType->getParameters().size()) {
1100-
auto param = substType->getParameters()[origParamI];
1101-
SILType argType = IGM.silConv.getSILType(param);
1102-
auto argLoweringTy =
1103-
getArgumentLoweringType(argType.getSwiftRValueType(), param);
1104-
auto &ti = subIGF.getTypeInfoForLowered(argLoweringTy);
1105-
// Empty values don't matter.
1106-
if (ti.getSchema().size() != 0 || param.isFormalIndirect())
1133+
if (!isABIIgnoredParameterWithoutStorage(IGM, subIGF, substType,
1134+
origParamI))
11071135
break;
11081136
origParamI++;
11091137
}

test/IRGen/partial_apply_forwarder.sil

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ public struct BaseProducer<T> : Q {
7070

7171
public class WeakBox<T> {}
7272

73+
public struct EmptyType {}
74+
7375
sil hidden_external @takingQ : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@owned WeakBox<τ_0_0>) -> ()
76+
sil hidden_external @takingQAndEmpty : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@owned WeakBox<τ_0_0>, EmptyType) -> ()
77+
sil hidden_external @takingEmptyAndQ : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (EmptyType, @owned WeakBox<τ_0_0>) -> ()
7478

7579
// CHECK-LABEL: define{{( protected)?}} swiftcc { i8*, %swift.refcounted* } @bind_polymorphic_param_from_context(%swift.opaque* noalias nocapture, %swift.type* %"\CF\84_0_1")
7680
// CHECK: entry:
@@ -103,6 +107,35 @@ bb0(%0 : $*τ_0_1):
103107
return %9 : $@callee_owned () -> ()
104108
}
105109

110+
// CHECK-LABEL: define{{( protected)?}} swiftcc { i8*, %swift.refcounted* } @bind_polymorphic_param_from_context_2(%swift.opaque* noalias nocapture, %swift.type* %"\CF\84_0_1")
111+
// CHECK: [[OBJ:%.*]] = call {{.*}} @swift_rt_swift_allocObject
112+
// CHECK: [[WB:%.*]] = bitcast %swift.refcounted* [[OBJ]]
113+
// CHECK: [[REF:%.*]] = bitcast {{.*}}* [[WB]] to %swift.refcounted*
114+
// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*)* @_T015takingQAndEmptyTA to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1
115+
// CHECK: }
116+
sil public @bind_polymorphic_param_from_context_2 : $@convention(thin) <τ_0_1>(@in τ_0_1, EmptyType) -> @owned @callee_owned () -> () {
117+
bb0(%0 : $*τ_0_1, %2: $EmptyType):
118+
%1 = alloc_ref $WeakBox<BaseProducer<τ_0_1>>
119+
%8 = function_ref @takingQAndEmpty : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@owned WeakBox<τ_0_0>, EmptyType) -> ()
120+
%9 = partial_apply %8<BaseProducer<τ_0_1>>(%1, %2) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@owned WeakBox<τ_0_0>, EmptyType) -> ()
121+
return %9 : $@callee_owned () -> ()
122+
}
123+
124+
// CHECK-LABEL: define{{( protected)?}} swiftcc { i8*, %swift.refcounted* } @bind_polymorphic_param_from_context_3(%swift.opaque* noalias nocapture, %swift.type* %"\CF\84_0_1")
125+
// CHECK: [[OBJ:%.*]] = call {{.*}} @swift_rt_swift_allocObject
126+
// CHECK: [[WB:%.*]] = bitcast %swift.refcounted* [[OBJ]]
127+
// CHECK: [[REF:%.*]] = bitcast {{.*}}* [[WB]] to %swift.refcounted*
128+
// CHECK: [[CLOSURE:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (%swift.refcounted*)* @_T015takingEmptyAndQTA to i8*), %swift.refcounted* undef }, %swift.refcounted* [[REF]], 1
129+
// CHECK: }
130+
131+
sil public @bind_polymorphic_param_from_context_3 : $@convention(thin) <τ_0_1>(@in τ_0_1, EmptyType) -> @owned @callee_owned () -> () {
132+
bb0(%0 : $*τ_0_1, %2: $EmptyType):
133+
%1 = alloc_ref $WeakBox<BaseProducer<τ_0_1>>
134+
%8 = function_ref @takingEmptyAndQ : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (EmptyType, @owned WeakBox<τ_0_0>) -> ()
135+
%9 = partial_apply %8<BaseProducer<τ_0_1>>(%2, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (EmptyType, @owned WeakBox<τ_0_0>) -> ()
136+
return %9 : $@callee_owned () -> ()
137+
}
138+
106139
// CHECK-LABEL: define{{( protected)?}} swiftcc void @bind_polymorphic_param_from_forwarder_parameter(%swift.opaque* noalias nocapture, %swift.type* %"\CF\84_0_1")
107140
// CHECK: entry:
108141
// CHECK: [[BPTY:%.*]] = call %swift.type* @_T023partial_apply_forwarder12BaseProducerVMa(%swift.type* %"\CF\84_0_1")

0 commit comments

Comments
 (0)