@@ -66,11 +66,6 @@ llvm::Value *irgen::emitDistributedActorInitializeRemote(
66
66
67
67
namespace {
68
68
69
- struct AllocationInfo {
70
- unsigned ArgumentIdx;
71
- StackAddress Addr;
72
- };
73
-
74
69
struct ArgumentDecoderInfo {
75
70
CanSILFunctionType Type;
76
71
FunctionPointer Fn;
@@ -97,7 +92,7 @@ class DistributedAccessor {
97
92
ArgumentDecoderInfo ArgumentDecoder;
98
93
99
94
// / The list of all arguments that were allocated on the stack.
100
- SmallVector<AllocationInfo , 4 > AllocatedArguments;
95
+ SmallVector<StackAddress , 4 > AllocatedArguments;
101
96
102
97
public:
103
98
DistributedAccessor (IRGenFunction &IGF, SILFunction *target,
@@ -106,33 +101,17 @@ class DistributedAccessor {
106
101
void emit ();
107
102
108
103
private:
109
- void computeArguments (llvm::Value *argumentBuffer,
110
- llvm::Value *argumentTypes,
111
- Explosion &arguments);
104
+ void decodeArguments (llvm::Value *decoder, llvm::Value *argumentTypes,
105
+ Explosion &arguments);
112
106
113
- // / Load an argument value from the given buffer \c argumentSlot
114
- // / to the given explosion \c arguments. Type of the argument is
115
- // / the same as parameter type.
116
- // /
117
- // / Returns a pair of aligned offset and value size.
118
- std::pair<llvm::Value *, llvm::Value *>
119
- loadArgument (unsigned argumentIdx,
120
- llvm::Value *argumentSlot,
121
- SILType paramType,
122
- ParameterConvention convention,
123
- Explosion &arguments);
124
-
125
- // / Load an argument value from the given buffer \c argumentSlot
107
+ // / Load an argument value from the given decoder \c decoder
126
108
// / to the given explosion \c arguments. Information describing
127
109
// / the type of argument comes from runtime metadata.
128
110
// /
129
111
// / Returns a pair of aligned offset and value size.
130
- std::pair<llvm::Value *, llvm::Value *>
131
- loadArgument (unsigned argumentIdx,
132
- llvm::Value *argumentSlot,
133
- llvm::Value *argumentType,
134
- const SILParameterInfo ¶m,
135
- Explosion &arguments);
112
+ void decodeArgument (unsigned argumentIdx, llvm::Value *decoder,
113
+ llvm::Value *argumentType, const SILParameterInfo ¶m,
114
+ Explosion &arguments);
136
115
137
116
// / Load witness table addresses (if any) from the given buffer
138
117
// / into the given argument explosion.
@@ -261,9 +240,9 @@ DistributedAccessor::DistributedAccessor(IRGenFunction &IGF,
261
240
FunctionPointer::BasicKind::AsyncFunctionPointer))),
262
241
ArgumentDecoder(findArgumentDecoder(IGM, target)) {}
263
242
264
- void DistributedAccessor::computeArguments (llvm::Value *argumentBuffer ,
265
- llvm::Value *argumentTypes,
266
- Explosion &arguments) {
243
+ void DistributedAccessor::decodeArguments (llvm::Value *decoder ,
244
+ llvm::Value *argumentTypes,
245
+ Explosion &arguments) {
267
246
auto fnType = Target->getLoweredFunctionType ();
268
247
269
248
// Cover all of the arguments except to `self` of the actor.
@@ -273,13 +252,6 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer,
273
252
if (parameters.empty ())
274
253
return ;
275
254
276
- auto offset =
277
- IGF.createAlloca (IGM.Int8PtrTy , IGM.getPointerAlignment (), " offset" );
278
- IGF.Builder .CreateLifetimeStart (offset, IGM.getPointerSize ());
279
-
280
- // Initialize "offset" with the address of the base of the argument buffer.
281
- IGF.Builder .CreateStore (argumentBuffer, offset);
282
-
283
255
// Cast type buffer to `swift.type**`
284
256
argumentTypes =
285
257
IGF.Builder .CreateBitCast (argumentTypes, IGM.TypeMetadataPtrPtrTy );
@@ -288,75 +260,78 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer,
288
260
const auto ¶m = parameters[i];
289
261
auto paramTy = param.getSILStorageInterfaceType ();
290
262
291
- // The size of the loaded argument value
292
- llvm::Value *valueSize;
263
+ // Check whether the native representation is empty e.g.
264
+ // this happens for empty enums, and if so - continue to
265
+ // the next argument.
266
+ if (paramTy.isObject ()) {
267
+ auto &typeInfo = IGM.getTypeInfo (paramTy);
268
+ auto &nativeSchema = typeInfo.nativeParameterValueSchema (IGM);
293
269
294
- // Load current offset
295
- llvm::Value *currentOffset = IGF.Builder .CreateLoad (offset, " elt_offset" );
296
-
297
- if (paramTy.hasTypeParameter ()) {
298
- auto offset =
299
- Size (i * IGM.DataLayout .getTypeAllocSize (IGM.TypeMetadataPtrTy ));
300
- auto alignment =
301
- IGM.DataLayout .getABITypeAlignment (IGM.TypeMetadataPtrTy );
270
+ if (nativeSchema.empty ())
271
+ continue ;
272
+ }
302
273
303
- // Load metadata describing argument value from argument types buffer.
304
- auto typeLoc = IGF.emitAddressAtOffset (
305
- argumentTypes, Offset (offset), IGM.TypeMetadataPtrTy ,
306
- Alignment (alignment), " arg_type_loc" );
274
+ auto offset =
275
+ Size (i * IGM.DataLayout .getTypeAllocSize (IGM.TypeMetadataPtrTy ));
276
+ auto alignment = IGM.DataLayout .getABITypeAlignment (IGM.TypeMetadataPtrTy );
307
277
308
- auto *argumentTy = IGF.Builder .CreateLoad (typeLoc, " arg_type" );
278
+ // Load metadata describing argument value from argument types buffer.
279
+ auto typeLoc = IGF.emitAddressAtOffset (
280
+ argumentTypes, Offset (offset), IGM.TypeMetadataPtrTy ,
281
+ Alignment (alignment), " arg_type_loc" );
309
282
310
- // Load argument value based using loaded type metadata.
311
- std::tie (currentOffset, valueSize) =
312
- loadArgument (i, currentOffset, argumentTy, param, arguments);
313
- } else {
314
- std::tie (currentOffset, valueSize) = loadArgument (
315
- i, currentOffset, paramTy, param.getConvention (), arguments);
316
- }
283
+ auto *argumentTy = IGF.Builder .CreateLoad (typeLoc, " arg_type" );
317
284
318
- // Move the offset to the beginning of the next element, unless
319
- // this is the last element
320
- if (param != parameters.back ()) {
321
- llvm::Value *addr = IGF.Builder .CreatePtrToInt (currentOffset, IGM.IntPtrTy );
322
- llvm::Value *nextOffset = IGF.Builder .CreateIntToPtr (
323
- IGF.Builder .CreateAdd (addr, valueSize), IGM.Int8PtrTy );
324
- IGF.Builder .CreateStore (nextOffset, offset);
325
- }
285
+ // Decode and load argument value using loaded type metadata.
286
+ decodeArgument (i, decoder, argumentTy, param, arguments);
326
287
}
327
-
328
- IGF.Builder .CreateLifetimeEnd (offset, IGM.getPointerSize ());
329
288
}
330
289
331
- std::pair<llvm::Value *, llvm::Value *>
332
- DistributedAccessor::loadArgument ( unsigned argumentIdx ,
333
- llvm::Value *argumentSlot ,
334
- llvm::Value *argumentType ,
335
- const SILParameterInfo ¶m,
336
- Explosion &arguments) {
290
+ void DistributedAccessor::decodeArgument ( unsigned argumentIdx,
291
+ llvm::Value *decoder ,
292
+ llvm::Value *argumentType ,
293
+ const SILParameterInfo ¶m ,
294
+ Explosion &arguments) {
295
+ auto ¶mInfo = IGM. getTypeInfo (param. getSILStorageInterfaceType ());
337
296
// TODO: `emitLoad*` would actually load value witness table every
338
297
// time it's called, which is sub-optimal but all of the APIs that
339
298
// deal with value witness tables are currently hidden in GenOpaque.cpp
340
299
llvm::Value *valueSize = emitLoadOfSize (IGF, argumentType);
341
300
342
- llvm::Value *isInline, *flags;
343
- std::tie (isInline, flags) = emitLoadOfIsInline (IGF, argumentType);
301
+ Callee callee = ArgumentDecoder.getCallee (decoder);
302
+
303
+ std::unique_ptr<CallEmission> emission =
304
+ getCallEmission (IGF, callee.getSwiftContext (), std::move (callee));
344
305
345
- llvm::Value *alignmentMask = emitAlignMaskFromFlags (IGF, flags);
306
+ StackAddress resultValue = IGF.emitDynamicAlloca (
307
+ IGM.Int8Ty , valueSize, paramInfo.getBestKnownAlignment ());
346
308
347
- // Align argument value offset as required by its type metadata.
348
- llvm::Value *alignedSlot =
349
- IGF.Builder .CreatePtrToInt (argumentSlot, IGM.IntPtrTy );
309
+ llvm::Value *resultAddr = resultValue.getAddress ().getAddress ();
310
+
311
+ resultAddr = IGF.Builder .CreateBitCast (resultAddr, IGM.OpaquePtrTy );
312
+
313
+ Explosion decodeArgs;
314
+ // indirect result buffer as `swift.opaque*`
315
+ decodeArgs.add (resultAddr);
316
+ // substitution Argument -> <argument metadata>
317
+ decodeArgs.add (argumentType);
318
+
319
+ emission->begin ();
350
320
{
351
- alignedSlot = IGF.Builder .CreateNUWAdd (alignedSlot, alignmentMask);
321
+ emission->setArgs (decodeArgs, /* isOutlined=*/ false ,
322
+ /* witnessMetadata=*/ nullptr );
352
323
353
- llvm::Value *invertedMask = IGF.Builder .CreateNot (alignmentMask);
354
- alignedSlot = IGF.Builder .CreateAnd (alignedSlot, invertedMask);
355
- alignedSlot =
356
- IGF.Builder .CreateIntToPtr (alignedSlot, IGM.OpaquePtrTy );
324
+ Explosion result;
325
+ emission->emitToExplosion (result, /* isOutlined=*/ false );
326
+ assert (result.empty ());
327
+
328
+ // TODO: Add error handling a new block that uses `emitAsyncReturn`
329
+ // if error slot is non-null.
357
330
}
331
+ emission->end ();
358
332
359
- Address argumentAddr (alignedSlot, IGM.getPointerAlignment ());
333
+ // Remember to deallocate later.
334
+ AllocatedArguments.push_back (resultValue);
360
335
361
336
switch (param.getConvention ()) {
362
337
case ParameterConvention::Indirect_In:
@@ -367,22 +342,19 @@ DistributedAccessor::loadArgument(unsigned argumentIdx,
367
342
368
343
auto stackAddr =
369
344
IGF.emitDynamicAlloca (IGM.Int8Ty , valueSize, Alignment (16 ));
370
- auto argPtr = stackAddr.getAddress ().getAddress ();
371
345
372
346
emitInitializeWithCopyCall (IGF, argumentType, stackAddr.getAddress (),
373
- argumentAddr);
374
-
375
- arguments.add (argPtr);
347
+ resultValue.getAddress ());
376
348
377
- // Remember to deallocate later .
378
- AllocatedArguments.push_back ({argumentIdx, stackAddr} );
349
+ // Remember to deallocate a copy .
350
+ AllocatedArguments.push_back (stackAddr);
379
351
break ;
380
352
}
381
353
382
354
case ParameterConvention::Indirect_In_Guaranteed: {
383
355
// The argument is +0, so we can use the address of the param in
384
356
// the context directly.
385
- arguments.add (alignedSlot );
357
+ arguments.add (resultAddr );
386
358
break ;
387
359
}
388
360
@@ -393,95 +365,20 @@ DistributedAccessor::loadArgument(unsigned argumentIdx,
393
365
case ParameterConvention::Direct_Guaranteed:
394
366
case ParameterConvention::Direct_Unowned: {
395
367
auto paramTy = param.getSILStorageInterfaceType ();
396
- auto &typeInfo = IGM.getTypeInfo (paramTy);
397
368
Address eltPtr = IGF.Builder .CreateBitCast (
398
- argumentAddr , IGM.getStoragePointerType (paramTy));
369
+ resultValue. getAddress () , IGM.getStoragePointerType (paramTy));
399
370
400
- cast<LoadableTypeInfo>(typeInfo ).loadAsTake (IGF, eltPtr, arguments);
371
+ cast<LoadableTypeInfo>(paramInfo ).loadAsTake (IGF, eltPtr, arguments);
401
372
break ;
402
373
}
403
374
404
375
case ParameterConvention::Direct_Owned: {
405
- auto &typeInfo = IGM.getTypeInfo (param.getSILStorageInterfaceType ());
406
376
// Copy the value out at +1.
407
- cast<LoadableTypeInfo>(typeInfo).loadAsCopy (IGF, argumentAddr, arguments);
377
+ cast<LoadableTypeInfo>(paramInfo).loadAsCopy (IGF, resultValue.getAddress (),
378
+ arguments);
408
379
break ;
409
380
}
410
381
}
411
-
412
- return {alignedSlot, valueSize};
413
- }
414
-
415
- std::pair<llvm::Value *, llvm::Value *>
416
- DistributedAccessor::loadArgument (unsigned argumentIdx,
417
- llvm::Value *argumentSlot,
418
- SILType paramTy,
419
- ParameterConvention convention,
420
- Explosion &arguments) {
421
- const TypeInfo &typeInfo = IGF.getTypeInfo (paramTy);
422
-
423
- // 1. Check whether the native representation is empty e.g.
424
- // this happens for empty enums.
425
- if (paramTy.isObject ()) {
426
- auto &nativeSchema = typeInfo.nativeParameterValueSchema (IGM);
427
- // If schema is empty, skip to the next argument.
428
- if (nativeSchema.empty ())
429
- return {argumentSlot, typeInfo.getSize (IGF, paramTy)};
430
- }
431
-
432
- // 2. Cast the pointer to the type of the element.
433
- Address eltPtr = IGF.Builder .CreateBitCast (
434
- Address (argumentSlot, IGM.getPointerAlignment ()),
435
- IGM.getStoragePointerType (paramTy));
436
-
437
- // 3. Adjust typed pointer to the alignment of the type.
438
- auto alignedOffset = typeInfo.roundUpToTypeAlignment (IGF, eltPtr, paramTy);
439
-
440
- // 4. Create an exploded version of the type to pass as an
441
- // argument to distributed method.
442
-
443
- switch (convention) {
444
- case ParameterConvention::Indirect_In:
445
- case ParameterConvention::Indirect_In_Constant: {
446
- // The +1 argument is passed indirectly, so we need to copy it into
447
- // a temporary.
448
-
449
- auto stackAddr = typeInfo.allocateStack (IGF, paramTy, " arg.temp" );
450
- auto argPtr = stackAddr.getAddress ().getAddress ();
451
-
452
- typeInfo.initializeWithCopy (IGF, stackAddr.getAddress (), alignedOffset,
453
- paramTy, /* isOutlined=*/ false );
454
- arguments.add (argPtr);
455
-
456
- // Remember to deallocate later.
457
- AllocatedArguments.push_back ({argumentIdx, stackAddr});
458
- break ;
459
- }
460
-
461
- case ParameterConvention::Indirect_In_Guaranteed: {
462
- // The argument is +0, so we can use the address of the param in
463
- // the context directly.
464
- arguments.add (alignedOffset.getAddress ());
465
- break ;
466
- }
467
-
468
- case ParameterConvention::Indirect_Inout:
469
- case ParameterConvention::Indirect_InoutAliasable:
470
- llvm_unreachable (" indirect 'inout' parameters are not supported" );
471
-
472
- case ParameterConvention::Direct_Guaranteed:
473
- case ParameterConvention::Direct_Unowned: {
474
- cast<LoadableTypeInfo>(typeInfo).loadAsTake (IGF, alignedOffset, arguments);
475
- break ;
476
- }
477
-
478
- case ParameterConvention::Direct_Owned:
479
- // Copy the value out at +1.
480
- cast<LoadableTypeInfo>(typeInfo).loadAsCopy (IGF, alignedOffset, arguments);
481
- break ;
482
- }
483
-
484
- return {alignedOffset.getAddress (), typeInfo.getSize (IGF, paramTy)};
485
382
}
486
383
487
384
void DistributedAccessor::emitLoadOfWitnessTables (llvm::Value *witnessTables,
@@ -575,7 +472,7 @@ void DistributedAccessor::emit() {
575
472
576
473
// Step one is to load all of the data from argument buffer,
577
474
// so it could be forwarded to the distributed method.
578
- computeArguments (argBuffer , argTypes, arguments);
475
+ decodeArguments (argDecoder , argTypes, arguments);
579
476
580
477
// Add all of the substitutions to the explosion
581
478
if (auto *genericEnvironment = Target->getGenericEnvironment ()) {
@@ -647,19 +544,12 @@ void DistributedAccessor::emit() {
647
544
648
545
emission->end ();
649
546
650
- // Deallocate all of the copied arguments.
547
+ // Deallocate all of the copied arguments. Since allocations happened
548
+ // on stack they have to be deallocated in reverse order.
651
549
{
652
- auto targetType = Target->getLoweredFunctionType ();
653
- for (auto &alloca : AllocatedArguments) {
654
- const auto ¶m = targetType->getParameters ()[alloca.ArgumentIdx ];
655
- auto paramTy = param.getSILStorageInterfaceType ();
656
-
657
- if (paramTy.hasTypeParameter ()) {
658
- IGF.emitDeallocateDynamicAlloca (alloca.Addr );
659
- } else {
660
- auto &typeInfo = IGF.getTypeInfo (paramTy);
661
- typeInfo.deallocateStack (IGF, alloca.Addr , paramTy);
662
- }
550
+ while (!AllocatedArguments.empty ()) {
551
+ auto argument = AllocatedArguments.pop_back_val ();
552
+ IGF.emitDeallocateDynamicAlloca (argument);
663
553
}
664
554
}
665
555
0 commit comments