Skip to content

Commit 79159f5

Browse files
committed
[4.0] 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 f511dd1 commit 79159f5

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
@@ -698,6 +698,41 @@ static CanType getArgumentLoweringType(CanType type,
698698
}
699699
}
700700

701+
static bool isABIIgnoredParameterWithoutStorage(IRGenModule &IGM,
702+
IRGenFunction &IGF,
703+
CanSILFunctionType substType,
704+
unsigned paramIdx) {
705+
auto param = substType->getParameters()[paramIdx];
706+
SILType argType = IGM.silConv.getSILType(param);
707+
auto argLoweringTy =
708+
getArgumentLoweringType(argType.getSwiftRValueType(), param);
709+
auto &ti = IGF.getTypeInfoForLowered(argLoweringTy);
710+
// Empty values don't matter.
711+
return ti.getSchema().size() == 0 && !param.isFormalIndirect();
712+
}
713+
714+
/// Find the parameter index for the one (assuming there was only one) partially
715+
/// applied argument ignoring empty types that are not passed as part of the
716+
/// ABI.
717+
static unsigned findSinglePartiallyAppliedParameterIndexIgnoringEmptyTypes(
718+
IRGenFunction &IGF, CanSILFunctionType substType,
719+
CanSILFunctionType outType) {
720+
auto substParameters = substType->getParameters();
721+
auto outParamters = outType->getParameters();
722+
unsigned firstNonEmpty = -1U;
723+
for (unsigned paramIdx = outParamters.size() ; paramIdx != substParameters.size(); ++paramIdx) {
724+
bool isEmpty =
725+
isABIIgnoredParameterWithoutStorage(IGF.IGM, IGF, substType, paramIdx);
726+
assert((isEmpty || firstNonEmpty == -1U) && "Expect at most one partially "
727+
"applied that is passed as an "
728+
"ABI argument");
729+
if (!isEmpty)
730+
firstNonEmpty = paramIdx;
731+
}
732+
assert(firstNonEmpty != -1U);
733+
return firstNonEmpty;
734+
}
735+
701736
/// Emit the forwarding stub function for a partial application.
702737
///
703738
/// If 'layout' is null, there is a single captured value of
@@ -919,11 +954,9 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
919954
// care for the former for the purpose of reconstructing polymorphic
920955
// parameters from regular arguments.
921956
if (!calleeHasContext) {
922-
unsigned paramI = substType->getParameters().size() - 1;
923-
assert(substType->getParameters().size() -
924-
outType->getParameters().size() ==
925-
1 &&
926-
"Expect one partially applied argument");
957+
unsigned paramI =
958+
findSinglePartiallyAppliedParameterIndexIgnoringEmptyTypes(
959+
subIGF, substType, outType);
927960
auto paramInfo = substType->getParameters()[paramI];
928961
auto &ti = IGM.getTypeInfoForLowered(paramInfo.getType());
929962
Explosion param;
@@ -1095,13 +1128,8 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
10951128

10961129
// Skip empty parameters.
10971130
while (origParamI < origType->getParameters().size()) {
1098-
auto param = substType->getParameters()[origParamI];
1099-
SILType argType = IGM.silConv.getSILType(param);
1100-
auto argLoweringTy =
1101-
getArgumentLoweringType(argType.getSwiftRValueType(), param);
1102-
auto &ti = subIGF.getTypeInfoForLowered(argLoweringTy);
1103-
// Empty values don't matter.
1104-
if (ti.getSchema().size() != 0 || param.isFormalIndirect())
1131+
if (!isABIIgnoredParameterWithoutStorage(IGM, subIGF, substType,
1132+
origParamI))
11051133
break;
11061134
origParamI++;
11071135
}

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)