@@ -368,6 +368,214 @@ irgen::emitTypeMetadataPackRef(IRGenFunction &IGF, CanPackType packType,
368
368
return response;
369
369
}
370
370
371
+ llvm::Value *
372
+ irgen::emitTypeMetadataPackElementRef (IRGenFunction &IGF, CanPackType packType,
373
+ llvm::Value *index,
374
+ DynamicMetadataRequest request) {
375
+ // If the pack has already been materialized, just gep into it.
376
+ if (auto pack = tryGetLocalPackTypeMetadata (IGF, packType, request)) {
377
+ auto *gep = IGF.Builder .CreateInBoundsGEP (IGF.IGM .TypeMetadataPtrTy ,
378
+ pack.getMetadata (), index );
379
+ auto addr =
380
+ Address (gep, IGF.IGM .TypeMetadataPtrTy , IGF.IGM .getPointerAlignment ());
381
+ auto *metadata = IGF.Builder .CreateLoad (addr);
382
+ return metadata;
383
+ }
384
+
385
+ // Otherwise, in general, there's no already available array of metadata
386
+ // which can be indexed into.
387
+ auto *shape = IGF.emitPackShapeExpression (packType);
388
+
389
+ // If the shape and the index are both constant, the type for which metadata
390
+ // will be emitted is statically available.
391
+ auto *constantShape = dyn_cast<llvm::ConstantInt>(shape);
392
+ auto *constantIndex = dyn_cast<llvm::ConstantInt>(index );
393
+ if (constantShape && constantIndex) {
394
+ assert (packType->getNumElements () == constantShape->getValue ());
395
+ auto index = constantIndex->getValue ().getZExtValue ();
396
+ assert (packType->getNumElements () > index );
397
+ auto ty = packType.getElementType (index );
398
+ auto response = IGF.emitTypeMetadataRef (ty, request);
399
+ auto *metadata = response.getMetadata ();
400
+ return metadata;
401
+ }
402
+
403
+ // A pack consists of types and pack expansion types. An example:
404
+ // {repeat each T, Int, repeat each T, repeat each U, String},
405
+ // The above type has length 5. The type "repeat each U" is at index 3.
406
+ //
407
+ // A pack _explosion_ is notionally obtained by flat-mapping the pack by the
408
+ // the operation of "listing elements" in pack expansion types.
409
+ //
410
+ // The explosion of the example pack looks like
411
+ // {T_0, T_1, ..., Int, T_0, T_1, ..., U_0, U_1, ..., String}
412
+ // ^^^^^^^^^^^^^
413
+ // the runtime components of "each T"
414
+ //
415
+ // We have an index into the explosion,
416
+ //
417
+ // {T_0, T_1, ..., Int, T_0, T_1, ..., U_0, U_1, ... String}
418
+ // ------------%index------------>
419
+ //
420
+ // and we need to obtain the element in the explosion corresponding to it.
421
+ //
422
+ // {T_0, T_1, ..., Int, T_0, T_1, ..., T_k, ..., U_0, U_1, ... String}
423
+ // ------------%index---------------> ^^^
424
+ //
425
+ // Unfortunately, the explosion has not (the first check in this function)
426
+ // been materialized--and doing so is likely wasteful--so we can't simply
427
+ // index into some array.
428
+ //
429
+ // Instead, _notionally_, we will "compute"
430
+ // (1) the index into the _pack_ and
431
+ // {repeat each T, Int, repeat each T, repeat each U, String}
432
+ // ------%outer------> ^^^^^^^^^^^^^
433
+ // (2) the index within the elements of the pack expansion type
434
+ // {T_0, T_2, ..., T_k, ...}
435
+ // ----%inner---> ^^^
436
+ //
437
+ // In fact, we won't ever materialize %outer into any register. Instead, we
438
+ // can just brach to materializing the metadata once we've determined which
439
+ // outer element's range contains %index.
440
+ //
441
+ // As for %inner, it will only be materialized in those blocks corresponding
442
+ // to pack expansions.
443
+ //
444
+ // Create the following control flow:
445
+ //
446
+ // +-------+ t_0 is not t_N _is_ an
447
+ // |entry: | an expansion expansion
448
+ // |... | +----------+ +----------+ +----------+
449
+ // |... | --> |check_0: | -> ... -> |check_N: | -> |trap: |
450
+ // | | | %i == %u0| | %i < %uN | | llvm.trap|
451
+ // +-------+ +----------+ +----------+ +----------+
452
+ // %outer = 0 %outer = N
453
+ // | |
454
+ // V V
455
+ // +----------+ +-----------------------+
456
+ // |emit_1: | |emit_N: |
457
+ // | %inner=0 | | %inner = %index - %lN |
458
+ // | %m_1 = | | %m_N = |
459
+ // +----------+ +-----------------------+
460
+ // | |
461
+ // V V
462
+ // +-------------------------------------------
463
+ // |exit:
464
+ // | %m = phi [ %m_1, %emit_1 ],
465
+ // | ...
466
+ // | [ %m_N, %emit_N ]
467
+ auto *current = IGF.Builder .GetInsertBlock ();
468
+
469
+ // Terminate the block that branches to continue checking or metadata emission
470
+ // depending on whether the index is in the pack expansion's bounds.
471
+ auto emitCheckBranch = [&IGF](llvm::Value *condition,
472
+ llvm::BasicBlock *inBounds,
473
+ llvm::BasicBlock *outOfBounds) {
474
+ if (condition) {
475
+ IGF.Builder .CreateCondBr (condition, inBounds, outOfBounds);
476
+ } else {
477
+ assert (!inBounds &&
478
+ " no condition to check but a metadata materialization block!?" );
479
+ IGF.Builder .CreateBr (outOfBounds);
480
+ }
481
+ };
482
+
483
+ // The block which emission will continue in after we finish emitting metadata
484
+ // for this element.
485
+ auto *exit = IGF.createBasicBlock (" pack-index-element-exit" );
486
+ IGF.Builder .emitBlock (exit );
487
+ auto *metadataPhi = IGF.Builder .CreatePHI (IGF.IGM .TypeMetadataPtrTy ,
488
+ packType.getElementTypes ().size ());
489
+
490
+ IGF.Builder .SetInsertPoint (current);
491
+ // The previous checkBounds' block's comparision of %index. Use it to emit a
492
+ // branch to the current block or the previous block's metadata emission
493
+ // block.
494
+ llvm::Value *previousCondition = nullptr ;
495
+ // The previous type's materializeMetadata block. Use it as the inBounds
496
+ // target when branching from the previous block.
497
+ llvm::BasicBlock *previousInBounds = nullptr ;
498
+ // The lower bound of indices for the current pack expansion. Inclusive.
499
+ llvm::Value *lowerBound = llvm::ConstantInt::get (IGF.IGM .SizeTy , 0 );
500
+ for (auto elementTy : packType.getElementTypes ()) {
501
+ // The block within which it will be checked whether %index corresponds to
502
+ // an element of the pack expansion elementTy.
503
+ auto *checkBounds = IGF.createBasicBlock (" pack-index-element-bounds" );
504
+ // Finish emitting the previous block, either entry or check_i-1.
505
+ //
506
+ // Branch from the previous bounds-check block either to this bounds-check
507
+ // block or to the previous metadata-emission block.
508
+ emitCheckBranch (previousCondition, previousInBounds, checkBounds);
509
+
510
+ // (1) Emit check_i {{
511
+ IGF.Builder .emitBlock (checkBounds);
512
+
513
+ // The upper bound for the current pack expansion. Exclusive.
514
+ llvm::Value *upperBound = nullptr ;
515
+ llvm::Value *condition = nullptr ;
516
+ if (auto expansionTy = dyn_cast<PackExpansionType>(elementTy)) {
517
+ auto reducedShape = expansionTy.getCountType ();
518
+ auto *length = IGF.emitPackShapeExpression (reducedShape);
519
+ upperBound = IGF.Builder .CreateAdd (lowerBound, length);
520
+ // %index < %upperBound
521
+ //
522
+ // It's not necessary to check that %index >= %lowerBound. Either
523
+ // elementTy is the first element type in packType or we branched here
524
+ // from some series of checkBounds blocks in each of which it was
525
+ // determined that %index is greater than the indices of the
526
+ // corresponding element type.
527
+ condition = IGF.Builder .CreateICmpULT (index , upperBound);
528
+ } else {
529
+ upperBound = IGF.Builder .CreateAdd (
530
+ lowerBound, llvm::ConstantInt::get (IGF.IGM .SizeTy , 1 ));
531
+ // %index == %lowerBound
532
+ condition = IGF.Builder .CreateICmpEQ (lowerBound, index );
533
+ }
534
+ // }} Finished emitting check_i, except for the terminator which will be
535
+ // emitted in the next iteration once the new outOfBounds block is
536
+ // available.
537
+
538
+ // (2) Emit emit_i {{
539
+ // The block within which the metadata corresponding to %inner will be
540
+ // materialized.
541
+ auto *materializeMetadata =
542
+ IGF.createBasicBlock (" pack-index-element-metadata" );
543
+ IGF.Builder .emitBlock (materializeMetadata);
544
+
545
+ llvm::Value *metadata = nullptr ;
546
+ if (auto expansionTy = dyn_cast<PackExpansionType>(elementTy)) {
547
+ // Actually materialize %inner. Then use it to get the metadata from the
548
+ // pack expansion at that index.
549
+ auto *relativeIndex = IGF.Builder .CreateSub (index , lowerBound);
550
+ metadata = emitPackExpansionElementMetadata (IGF, expansionTy,
551
+ relativeIndex, request);
552
+ } else {
553
+ metadata = IGF.emitTypeMetadataRef (elementTy, request).getMetadata ();
554
+ }
555
+ metadataPhi->addIncoming (metadata, materializeMetadata);
556
+ IGF.Builder .CreateBr (exit );
557
+ // }} Finished emitting emit_i.
558
+
559
+ // Switch back to emitting check_i. The next iteration will emit its
560
+ // terminator.
561
+ IGF.Builder .SetInsertPoint (checkBounds);
562
+
563
+ // Set up the values for the next iteration.
564
+ previousInBounds = materializeMetadata;
565
+ previousCondition = condition;
566
+ lowerBound = upperBound;
567
+ }
568
+ auto *trap = IGF.createBasicBlock (" pack-index-element-trap" );
569
+ emitCheckBranch (previousCondition, previousInBounds, trap);
570
+
571
+ IGF.Builder .emitBlock (trap);
572
+ IGF.emitTrap (" Variadic generic index out of bounds" ,
573
+ /* EmitUnreachable=*/ true );
574
+
575
+ IGF.Builder .SetInsertPoint (exit );
576
+ return metadataPhi;
577
+ }
578
+
371
579
void irgen::cleanupTypeMetadataPack (IRGenFunction &IGF,
372
580
StackAddress pack,
373
581
Optional<unsigned > elementCount) {
0 commit comments