@@ -812,6 +812,14 @@ namespace {
812
812
return false ;
813
813
return singleton->isSingleRetainablePointer (expansion, rc);
814
814
}
815
+
816
+ bool canValueWitnessExtraInhabitantsUpTo (IRGenModule &IGM,
817
+ unsigned index) const override {
818
+ auto singleton = getSingleton ();
819
+ if (!singleton)
820
+ return false ;
821
+ return singleton->canValueWitnessExtraInhabitantsUpTo (IGM, index);
822
+ }
815
823
};
816
824
817
825
// / Implementation strategy for no-payload enums, in other words, 'C-like'
@@ -1674,6 +1682,9 @@ namespace {
1674
1682
// / copy and destroy can pass through to retain and release entry
1675
1683
// / points.
1676
1684
NullableRefcounted,
1685
+ // / The payload's value witnesses can handle the extra inhabitants we use
1686
+ // / for no-payload tags, so we can forward all our calls to them.
1687
+ ForwardToPayload,
1677
1688
};
1678
1689
1679
1690
CopyDestroyStrategy CopyDestroyKind;
@@ -1802,6 +1813,26 @@ namespace {
1802
1813
&& cast<FixedTypeInfo>(payloadTI)
1803
1814
.getFixedExtraInhabitantCount (IGM) > 0 ) {
1804
1815
CopyDestroyKind = NullableRefcounted;
1816
+ // If the payload's value witnesses can accept the extra inhabitants we
1817
+ // use, then we can forward to them instead of checking for empty tags.
1818
+ // TODO: Do this for all types, not just loadable types.
1819
+ } else if (tik >= TypeInfoKind::Loadable) {
1820
+ ReferenceCounting refCounting;
1821
+ (void )refCounting;
1822
+ // Ensure that asking `canValueWitnessExtraInhabitantsUpTo` doesn't
1823
+ // regress any places we were previously able to ask
1824
+ // `isSingleRetainablePointer`.
1825
+ assert (
1826
+ (!payloadTI.isSingleRetainablePointer (ResilienceExpansion::Maximal,
1827
+ &refCounting)
1828
+ || payloadTI.canValueWitnessExtraInhabitantsUpTo (IGM, 0 ))
1829
+ && " single-refcounted thing should be able to value-witness "
1830
+ " extra inhabitant zero" );
1831
+
1832
+ unsigned numTags = ElementsWithNoPayload.size ();
1833
+ if (payloadTI.canValueWitnessExtraInhabitantsUpTo (IGM, numTags-1 )) {
1834
+ CopyDestroyKind = ForwardToPayload;
1835
+ }
1805
1836
}
1806
1837
}
1807
1838
@@ -1811,6 +1842,12 @@ namespace {
1811
1842
assert (NumExtraInhabitantTagValues != ~0U );
1812
1843
return NumExtraInhabitantTagValues;
1813
1844
}
1845
+
1846
+ bool canValueWitnessExtraInhabitantsUpTo (IRGenModule &IGM,
1847
+ unsigned index) const override {
1848
+ return getPayloadTypeInfo ().canValueWitnessExtraInhabitantsUpTo (IGM,
1849
+ index + NumExtraInhabitantTagValues);
1850
+ }
1814
1851
1815
1852
// / Emit a call into the runtime to get the current enum payload tag.
1816
1853
// / This returns a tag index in the range [0..NumElements-1].
@@ -2412,6 +2449,7 @@ namespace {
2412
2449
switch (CopyDestroyKind) {
2413
2450
case NullableRefcounted:
2414
2451
return IGM.getReferenceType (Refcounting);
2452
+ case ForwardToPayload:
2415
2453
case POD:
2416
2454
case Normal:
2417
2455
case ABIInaccessible:
@@ -2427,6 +2465,7 @@ namespace {
2427
2465
case NullableRefcounted:
2428
2466
IGF.emitStrongRetain (ptr, Refcounting, IGF.getDefaultAtomicity ());
2429
2467
return ;
2468
+ case ForwardToPayload:
2430
2469
case POD:
2431
2470
case Normal:
2432
2471
case ABIInaccessible:
@@ -2440,6 +2479,7 @@ namespace {
2440
2479
case NullableRefcounted:
2441
2480
IGF.emitFixLifetime (ptr);
2442
2481
return ;
2482
+ case ForwardToPayload:
2443
2483
case POD:
2444
2484
case Normal:
2445
2485
case ABIInaccessible:
@@ -2453,6 +2493,7 @@ namespace {
2453
2493
case NullableRefcounted:
2454
2494
IGF.emitStrongRelease (ptr, Refcounting, IGF.getDefaultAtomicity ());
2455
2495
return ;
2496
+ case ForwardToPayload:
2456
2497
case POD:
2457
2498
case Normal:
2458
2499
case ABIInaccessible:
@@ -2471,6 +2512,25 @@ namespace {
2471
2512
if (extraTag)
2472
2513
out.add (extraTag);
2473
2514
}
2515
+
2516
+ void unpackIntoPayloadExplosion (IRGenFunction &IGF,
2517
+ Explosion &asEnumIn,
2518
+ Explosion &asPayloadOut) const {
2519
+ auto &payloadTI = getLoadablePayloadTypeInfo ();
2520
+ // Unpack as an instance of the payload type and use its copy operation.
2521
+ auto srcBits = EnumPayload::fromExplosion (IGF.IGM , asEnumIn,
2522
+ PayloadSchema);
2523
+ payloadTI.unpackFromEnumPayload (IGF, srcBits, asPayloadOut, 0 );
2524
+ }
2525
+
2526
+ void packFromPayloadExplosion (IRGenFunction &IGF,
2527
+ Explosion &asPayloadIn,
2528
+ Explosion &asEnumOut) const {
2529
+ auto &payloadTI = getLoadablePayloadTypeInfo ();
2530
+ auto payload = EnumPayload::zero (IGF.IGM , PayloadSchema);
2531
+ payloadTI.packIntoEnumPayload (IGF, payload, asPayloadIn, 0 );
2532
+ payload.explode (IGF.IGM , asEnumOut);
2533
+ }
2474
2534
2475
2535
public:
2476
2536
void copy (IRGenFunction &IGF, Explosion &src, Explosion &dest,
@@ -2530,6 +2590,15 @@ namespace {
2530
2590
dest.add (val);
2531
2591
return ;
2532
2592
}
2593
+
2594
+ case ForwardToPayload: {
2595
+ auto &payloadTI = getLoadablePayloadTypeInfo ();
2596
+ Explosion srcAsPayload, destAsPayload;
2597
+ unpackIntoPayloadExplosion (IGF, src, srcAsPayload);
2598
+ payloadTI.copy (IGF, srcAsPayload, destAsPayload, atomicity);
2599
+ packFromPayloadExplosion (IGF, destAsPayload, dest);
2600
+ return ;
2601
+ }
2533
2602
}
2534
2603
}
2535
2604
@@ -2585,6 +2654,16 @@ namespace {
2585
2654
releaseRefcountedPayload (IGF, ptr);
2586
2655
return ;
2587
2656
}
2657
+
2658
+ case ForwardToPayload: {
2659
+ auto &payloadTI = getLoadablePayloadTypeInfo ();
2660
+ // Unpack as an instance of the payload type and use its consume
2661
+ // operation.
2662
+ Explosion srcAsPayload;
2663
+ unpackIntoPayloadExplosion (IGF, src, srcAsPayload);
2664
+ payloadTI.consume (IGF, srcAsPayload, atomicity);
2665
+ return ;
2666
+ }
2588
2667
}
2589
2668
}
2590
2669
@@ -2630,6 +2709,16 @@ namespace {
2630
2709
fixLifetimeOfRefcountedPayload (IGF, ptr);
2631
2710
return ;
2632
2711
}
2712
+
2713
+ case ForwardToPayload: {
2714
+ auto &payloadTI = getLoadablePayloadTypeInfo ();
2715
+ // Unpack as an instance of the payload type and use its fixLifetime
2716
+ // operation.
2717
+ Explosion srcAsPayload;
2718
+ unpackIntoPayloadExplosion (IGF, srcAsPayload, srcAsPayload);
2719
+ payloadTI.fixLifetime (IGF, src);
2720
+ return ;
2721
+ }
2633
2722
}
2634
2723
2635
2724
}
@@ -2667,13 +2756,22 @@ namespace {
2667
2756
}
2668
2757
2669
2758
case NullableRefcounted: {
2670
- // Load the value as swift.refcounted, then hand to swift_release .
2759
+ // Apply the payload's operation .
2671
2760
addr = IGF.Builder .CreateBitCast (
2672
2761
addr, getRefcountedPtrType (IGM)->getPointerTo ());
2673
2762
llvm::Value *ptr = IGF.Builder .CreateLoad (addr);
2674
2763
releaseRefcountedPayload (IGF, ptr);
2675
2764
return ;
2676
2765
}
2766
+
2767
+ case ForwardToPayload: {
2768
+ auto &payloadTI = getPayloadTypeInfo ();
2769
+ // Apply the payload's operation.
2770
+ addr = IGF.Builder .CreateBitCast (
2771
+ addr, payloadTI.getStorageType ()->getPointerTo ());
2772
+ payloadTI.destroy (IGF, addr, getPayloadType (IGF.IGM , T), isOutlined);
2773
+ return ;
2774
+ }
2677
2775
}
2678
2776
} else {
2679
2777
if (!IGF.IGM .getOptions ().UseTypeLayoutValueHandling ) {
@@ -2702,8 +2800,9 @@ namespace {
2702
2800
Address addr) const override {
2703
2801
// There is no need to bitcast from the enum address. Loading from the
2704
2802
// reference type emits a bitcast to the proper reference type first.
2705
- return cast<LoadableTypeInfo>(getPayloadTypeInfo ()).loadRefcountedPtr (
2706
- IGF, loc, addr).getValue ();
2803
+ return getLoadablePayloadTypeInfo ()
2804
+ .loadRefcountedPtr (IGF, loc, addr)
2805
+ .getValue ();
2707
2806
}
2708
2807
private:
2709
2808
llvm::ConstantInt *getZeroExtraTagConstant (IRGenModule &IGM) const {
@@ -2843,6 +2942,18 @@ namespace {
2843
2942
releaseRefcountedPayload (IGF, oldPtr);
2844
2943
return ;
2845
2944
}
2945
+
2946
+ case ForwardToPayload: {
2947
+ auto &payloadTI = getPayloadTypeInfo ();
2948
+ // Apply the payload's operation.
2949
+ dest = IGF.Builder .CreateBitCast (dest,
2950
+ payloadTI.getStorageType ()->getPointerTo ());
2951
+ src = IGF.Builder .CreateBitCast (src,
2952
+ payloadTI.getStorageType ()->getPointerTo ());
2953
+ payloadTI.assign (IGF, dest, src, isTake,
2954
+ getPayloadType (IGF.IGM , T), isOutlined);
2955
+ return ;
2956
+ }
2846
2957
}
2847
2958
2848
2959
}
@@ -2911,6 +3022,18 @@ namespace {
2911
3022
IGF.Builder .CreateStore (srcPtr, destAddr);
2912
3023
return ;
2913
3024
}
3025
+
3026
+ case ForwardToPayload: {
3027
+ auto &payloadTI = getPayloadTypeInfo ();
3028
+ // Apply the payload's operation.
3029
+ dest = IGF.Builder .CreateBitCast (dest,
3030
+ payloadTI.getStorageType ()->getPointerTo ());
3031
+ src = IGF.Builder .CreateBitCast (src,
3032
+ payloadTI.getStorageType ()->getPointerTo ());
3033
+ payloadTI.initialize (IGF, dest, src, isTake,
3034
+ getPayloadType (IGF.IGM , T), isOutlined);
3035
+ return ;
3036
+ }
2914
3037
}
2915
3038
}
2916
3039
@@ -6093,6 +6216,10 @@ namespace {
6093
6216
SILType ty) const override {
6094
6217
return Strategy.buildTypeLayoutEntry (IGM, ty);
6095
6218
}
6219
+ bool canValueWitnessExtraInhabitantsUpTo (IRGenModule &IGM,
6220
+ unsigned index) const override {
6221
+ return Strategy.canValueWitnessExtraInhabitantsUpTo (IGM, index);
6222
+ }
6096
6223
};
6097
6224
6098
6225
template <class Base >
0 commit comments