Skip to content

Commit 72bc593

Browse files
Merge pull request #11173 from aschwaighofer/swift-4.0-branch-irgen_fix_partial_apply_generic_class_capture_empty_type
[4.0] IRGen: Fix partial applies of generic functions capturing the generic parameters in an argument
2 parents c0edaee + 79159f5 commit 72bc593

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)