@@ -121,6 +121,12 @@ bool ExplosionSchema::requiresIndirectResult(IRGenModule &IGM) const {
121
121
size () > IGM.TargetInfo .MaxScalarsForDirectResult ;
122
122
}
123
123
124
+ bool ExplosionSchema::requiresIndirectParameter (IRGenModule &IGM) const {
125
+ // For now, use the same condition as requiresIndirectSchema. We may want
126
+ // to diverge at some point.
127
+ return requiresIndirectResult (IGM);
128
+ }
129
+
124
130
llvm::Type *ExplosionSchema::getScalarResultType (IRGenModule &IGM) const {
125
131
if (size () == 0 ) {
126
132
return IGM.VoidTy ;
@@ -134,7 +140,14 @@ llvm::Type *ExplosionSchema::getScalarResultType(IRGenModule &IGM) const {
134
140
}
135
141
136
142
void ExplosionSchema::addToArgTypes (IRGenModule &IGM,
143
+ const TypeInfo &TI,
144
+ llvm::AttributeSet &Attrs,
137
145
SmallVectorImpl<llvm::Type*> &types) const {
146
+ // Pass indirect arguments as byvals.
147
+ if (requiresIndirectParameter (IGM)) {
148
+ types.push_back (TI.getStorageType ()->getPointerTo ());
149
+ return ;
150
+ }
138
151
for (auto &elt : *this ) {
139
152
if (elt.isAggregate ())
140
153
types.push_back (elt.getAggregateType ()->getPointerTo ());
@@ -1271,8 +1284,9 @@ void SignatureExpansion::expand(SILParameterInfo param) {
1271
1284
return ;
1272
1285
}
1273
1286
case SILFunctionLanguage::Swift: {
1274
- auto schema = IGM.getSchema (param.getSILType ());
1275
- schema.addToArgTypes (IGM, ParamIRTypes);
1287
+ auto &ti = IGM.getTypeInfo (param.getSILType ());
1288
+ auto schema = ti.getSchema ();
1289
+ schema.addToArgTypes (IGM, ti, Attrs, ParamIRTypes);
1276
1290
return ;
1277
1291
}
1278
1292
}
@@ -2824,17 +2838,54 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
2824
2838
}
2825
2839
}
2826
2840
2841
+ namespace {
2842
+ enum IsIndirectValueArgument_t: bool {
2843
+ IsNotIndirectValueArgument = false ,
2844
+ IsIndirectValueArgument = true ,
2845
+ };
2846
+ }
2847
+
2848
+ static IsIndirectValueArgument_t addNativeArgument (IRGenFunction &IGF,
2849
+ Explosion &in,
2850
+ const TypeInfo &ti,
2851
+ ParameterConvention convention,
2852
+ Explosion &out) {
2853
+ // Addresses consist of a single pointer argument.
2854
+ if (isIndirectParameter (convention)) {
2855
+ out.add (in.claimNext ());
2856
+ return IsNotIndirectValueArgument;
2857
+ }
2858
+
2859
+ auto &loadableTI = cast<LoadableTypeInfo>(ti);
2860
+ auto schema = ti.getSchema ();
2861
+
2862
+ if (schema.requiresIndirectParameter (IGF.IGM )) {
2863
+ // Pass the argument indirectly.
2864
+ auto buf = IGF.createAlloca (ti.getStorageType (),
2865
+ loadableTI.getFixedAlignment (), " " );
2866
+ loadableTI.initialize (IGF, in, buf);
2867
+ out.add (buf.getAddress ());
2868
+ return IsIndirectValueArgument;
2869
+ } else {
2870
+ // Pass the argument explosion directly.
2871
+ loadableTI.reexplode (IGF, in, out);
2872
+ return IsNotIndirectValueArgument;
2873
+ }
2874
+ }
2875
+
2827
2876
// / Add a new set of arguments to the function.
2828
- void CallEmission::setArgs (Explosion &arg, WitnessMetadata *witnessMetadata) {
2877
+ void CallEmission::setArgs (Explosion &arg,
2878
+ ArrayRef<SILParameterInfo> params,
2879
+ WitnessMetadata *witnessMetadata) {
2829
2880
// Convert arguments to a representation appropriate to the calling
2830
2881
// convention.
2882
+ Explosion adjustedArg;
2883
+
2831
2884
switch (getCallee ().getRepresentation ()) {
2832
2885
case SILFunctionTypeRepresentation::CFunctionPointer:
2833
2886
case SILFunctionTypeRepresentation::ObjCMethod:
2834
2887
case SILFunctionTypeRepresentation::Block: {
2835
- Explosion externalized;
2836
- externalizeArguments (IGF, getCallee (), arg, externalized);
2837
- arg = std::move (externalized);
2888
+ externalizeArguments (IGF, getCallee (), arg, adjustedArg);
2838
2889
break ;
2839
2890
}
2840
2891
@@ -2848,19 +2899,26 @@ void CallEmission::setArgs(Explosion &arg, WitnessMetadata *witnessMetadata) {
2848
2899
case SILFunctionTypeRepresentation::Method:
2849
2900
case SILFunctionTypeRepresentation::Thin:
2850
2901
case SILFunctionTypeRepresentation::Thick:
2851
- // Nothing to do.
2902
+ // Check for value arguments that need to be passed indirectly.
2903
+ for (auto param : params) {
2904
+ addNativeArgument (IGF, arg,
2905
+ IGF.getTypeInfoForLowered (param.getType ()),
2906
+ param.getConvention (),
2907
+ adjustedArg);
2908
+ }
2909
+ adjustedArg.add (arg.claimAll ());
2852
2910
break ;
2853
2911
}
2854
2912
2855
2913
// Add the given number of arguments.
2856
- assert (LastArgWritten >= arg .size ());
2914
+ assert (LastArgWritten >= adjustedArg .size ());
2857
2915
2858
- size_t targetIndex = LastArgWritten - arg .size ();
2916
+ size_t targetIndex = LastArgWritten - adjustedArg .size ();
2859
2917
assert (targetIndex <= 1 );
2860
2918
LastArgWritten = targetIndex;
2861
2919
2862
2920
auto argIterator = Args.begin () + targetIndex;
2863
- for (auto value : arg .claimAll ()) {
2921
+ for (auto value : adjustedArg .claimAll ()) {
2864
2922
*argIterator++ = value;
2865
2923
}
2866
2924
}
@@ -3180,7 +3238,23 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
3180
3238
3181
3239
// Reemit the parameters as unsubstituted.
3182
3240
for (unsigned i = 0 ; i < outType->getParameters ().size (); ++i) {
3183
- emitApplyArgument (subIGF, origType->getParameters ()[i],
3241
+ Explosion arg;
3242
+ auto origParamInfo = origType->getParameters ()[i];
3243
+ auto &ti = IGM.getTypeInfoForLowered (origParamInfo.getType ());
3244
+ auto schema = ti.getSchema ();
3245
+
3246
+ // Forward the address of indirect value params.
3247
+ if (!isIndirectParameter (origParamInfo.getConvention ())
3248
+ && schema.requiresIndirectParameter (IGM)) {
3249
+ auto addr = origParams.claimNext ();
3250
+ if (addr->getType () != ti.getStorageType ()->getPointerTo ())
3251
+ addr = subIGF.Builder .CreateBitCast (addr,
3252
+ ti.getStorageType ()->getPointerTo ());
3253
+ args.add (addr);
3254
+ continue ;
3255
+ }
3256
+
3257
+ emitApplyArgument (subIGF, origParamInfo,
3184
3258
outType->getParameters ()[i],
3185
3259
origParams, args);
3186
3260
}
@@ -3195,6 +3269,7 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
3195
3269
3196
3270
bool dependsOnContextLifetime = false ;
3197
3271
bool consumesContext;
3272
+ bool needsAllocas = false ;
3198
3273
3199
3274
switch (outType->getCalleeConvention ()) {
3200
3275
case ParameterConvention::Direct_Owned:
@@ -3260,12 +3335,14 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
3260
3335
auto fieldConvention = conventions[nextCapturedField];
3261
3336
Address fieldAddr = fieldLayout.project (subIGF, data, offsets);
3262
3337
auto &fieldTI = fieldLayout.getType ();
3338
+ auto fieldSchema = fieldTI.getSchema ();
3263
3339
3264
3340
Explosion param;
3265
3341
switch (fieldConvention) {
3266
3342
case ParameterConvention::Indirect_In: {
3267
3343
// The +1 argument is passed indirectly, so we need to copy into a
3268
3344
// temporary.
3345
+ needsAllocas = true ;
3269
3346
auto caddr = fieldTI.allocateStack (subIGF, fieldTy, " arg.temp" );
3270
3347
fieldTI.initializeWithCopy (subIGF, caddr.getAddress (), fieldAddr,
3271
3348
fieldTy);
@@ -3314,14 +3391,21 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
3314
3391
3315
3392
// Reemit the capture params as unsubstituted.
3316
3393
if (origParamI < origType->getParameters ().size ()) {
3317
- emitApplyArgument (subIGF,
3318
- origType->getParameters ()[origParamI],
3394
+ Explosion origParam;
3395
+ auto origParamInfo = origType->getParameters ()[origParamI];
3396
+ emitApplyArgument (subIGF, origParamInfo,
3319
3397
substType->getParameters ()[origParamI],
3320
- param, args);
3398
+ param, origParam);
3399
+
3400
+ needsAllocas |= addNativeArgument (subIGF, origParam,
3401
+ IGM.getTypeInfoForLowered (origParamInfo.getType ()),
3402
+ origParamInfo.getConvention (),
3403
+ args);
3321
3404
++origParamI;
3322
3405
} else {
3323
3406
args.add (param.claimAll ());
3324
3407
}
3408
+
3325
3409
}
3326
3410
3327
3411
// If the parameters can live independent of the context, release it now
@@ -3407,7 +3491,8 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
3407
3491
// "C" calling convention, but that may change.
3408
3492
call->setAttributes (origAttrs);
3409
3493
}
3410
- if (!consumesContext || !dependsOnContextLifetime)
3494
+ if (addressesToDeallocate.empty () && !needsAllocas &&
3495
+ (!consumesContext || !dependsOnContextLifetime))
3411
3496
call->setTailCall ();
3412
3497
3413
3498
// Deallocate everything we allocated above.
0 commit comments