@@ -408,6 +408,8 @@ class PatternMatchEmission {
408
408
CleanupsDepth PatternMatchStmtDepth;
409
409
llvm::MapVector<CaseStmt*, std::pair<SILBasicBlock*, bool >> SharedCases;
410
410
411
+ llvm::DenseMap<VarDecl*, SILValue> Temporaries;
412
+
411
413
using CompletionHandlerTy =
412
414
llvm::function_ref<void (PatternMatchEmission &, ArgArray, ClauseRow &)>;
413
415
CompletionHandlerTy CompletionHandler;
@@ -416,13 +418,19 @@ class PatternMatchEmission {
416
418
PatternMatchEmission (SILGenFunction &SGF, Stmt *S,
417
419
CompletionHandlerTy completionHandler)
418
420
: SGF(SGF), PatternMatchStmt(S),
419
- PatternMatchStmtDepth (SGF.getCleanupsDepth()),
420
421
CompletionHandler (completionHandler) {}
421
422
422
423
void emitDispatch (ClauseMatrix &matrix, ArgArray args,
423
424
const FailureHandler &failure);
424
425
425
- JumpDest getSharedCaseBlockDest (CaseStmt *caseStmt, bool hasFallthroughTo);
426
+ void initSharedCaseBlockDest (CaseStmt *caseBlock, bool hasFallthroughTo);
427
+
428
+ void emitAddressOnlyAllocations ();
429
+
430
+ void emitAddressOnlyInitialization (VarDecl *dest, SILValue value);
431
+
432
+ JumpDest getSharedCaseBlockDest (CaseStmt *caseStmt);
433
+
426
434
void emitSharedCaseBlocks ();
427
435
428
436
void emitCaseBody (CaseStmt *caseBlock);
@@ -1759,9 +1767,8 @@ void PatternMatchEmission::emitEnumElementDispatchWithOwnership(
1759
1767
enumDecl = SGF.getASTContext ().getOptionalDecl ();
1760
1768
}
1761
1769
1762
- // FIXME: Get expansion from SILFunction
1763
1770
if (!enumDecl->isResilient (SGF.SGM .M .getSwiftModule (),
1764
- ResilienceExpansion::Maximal )) {
1771
+ SGF. F . getResilienceExpansion () )) {
1765
1772
exhaustive = true ;
1766
1773
1767
1774
for (auto elt : enumDecl->getAllElements ()) {
@@ -1988,7 +1995,6 @@ void PatternMatchEmission::emitEnumElementDispatch(
1988
1995
enumDecl = SGF.getASTContext ().getOptionalDecl ();
1989
1996
}
1990
1997
1991
- // FIXME: Get expansion from SILFunction
1992
1998
if (!enumDecl->isResilient (SGF.SGM .M .getSwiftModule (),
1993
1999
SGF.F .getResilienceExpansion ())) {
1994
2000
exhaustive = true ;
@@ -2326,43 +2332,77 @@ void PatternMatchEmission::emitCaseBody(CaseStmt *caseBlock) {
2326
2332
}
2327
2333
}
2328
2334
2329
- // / Retrieve the jump destination for a shared case block.
2330
- JumpDest PatternMatchEmission::getSharedCaseBlockDest (CaseStmt *caseBlock,
2331
- bool hasFallthroughTo) {
2335
+ void PatternMatchEmission::initSharedCaseBlockDest (CaseStmt *caseBlock,
2336
+ bool hasFallthroughTo) {
2332
2337
auto result = SharedCases.insert ({caseBlock, {nullptr , hasFallthroughTo}});
2338
+ assert (result.second );
2333
2339
2334
- // If there's already an entry, use that.
2335
- SILBasicBlock *block;
2336
- if (!result.second ) {
2337
- block = result.first ->second .first ;
2338
- assert (block);
2339
- } else {
2340
- // Create the shared destination at the first place that might
2341
- // have needed it.
2342
- block = SGF.createBasicBlock ();
2343
- result.first ->second .first = block;
2340
+ auto *block = SGF.createBasicBlock ();
2341
+ result.first ->second .first = block;
2344
2342
2345
- // Add args for any pattern variables
2343
+ // Add args for any pattern variables
2344
+ if (caseBlock->hasBoundDecls ()) {
2345
+ auto pattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
2346
+ pattern->forEachVariable ([&](VarDecl *V) {
2347
+ if (!V->hasName ())
2348
+ return ;
2349
+
2350
+ // We don't pass address-only values in basic block arguments.
2351
+ SILType ty = SGF.getLoweredType (V->getType ());
2352
+ if (ty.isAddressOnly (SGF.F .getModule ()))
2353
+ return ;
2354
+ block->createPHIArgument (ty, ValueOwnershipKind::Owned, V);
2355
+ });
2356
+ }
2357
+ }
2358
+
2359
+ // / Retrieve the jump destination for a shared case block.
2360
+ JumpDest PatternMatchEmission::getSharedCaseBlockDest (CaseStmt *caseBlock) {
2361
+ auto result = SharedCases.find (caseBlock);
2362
+ assert (result != SharedCases.end ());
2363
+
2364
+ auto *block = result->second .first ;
2365
+ assert (block);
2366
+
2367
+ return JumpDest (block, PatternMatchStmtDepth,
2368
+ CleanupLocation (PatternMatchStmt));
2369
+ }
2370
+
2371
+ void PatternMatchEmission::emitAddressOnlyAllocations () {
2372
+ for (auto &entry: SharedCases) {
2373
+ CaseStmt *caseBlock = entry.first ;
2374
+
2375
+ // If we have a shared case with bound decls, then the 0th pattern has the
2376
+ // order of variables that are the incoming BB arguments. Setup the VarLocs
2377
+ // to point to the incoming args and setup initialization so any args needing
2378
+ // cleanup will get that as well.
2346
2379
if (caseBlock->hasBoundDecls ()) {
2347
2380
auto pattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
2348
2381
pattern->forEachVariable ([&](VarDecl *V) {
2349
2382
if (!V->hasName ())
2350
2383
return ;
2351
- // We should never PHI addresses. To eliminate that possibility, we:
2352
- //
2353
- // 1. Load all loadable types and pass them as objects to the block.
2354
- // 2. We do not emit arguments for address only types. We instead just
2355
- // assign SILUndef to the VarLoc.
2384
+
2356
2385
SILType ty = SGF.getLoweredType (V->getType ());
2357
- if (ty.isAddressOnly (SGF.F .getModule ()))
2386
+
2387
+ if (ty.isAddressOnly (SGF.F .getModule ())) {
2388
+ assert (!Temporaries[V]);
2389
+ Temporaries[V] = SGF.emitTemporaryAllocation (V, ty);
2358
2390
return ;
2359
- block-> createPHIArgument (ty, ValueOwnershipKind::Owned, V);
2391
+ }
2360
2392
});
2361
2393
}
2362
2394
}
2363
2395
2364
- return JumpDest (block, PatternMatchStmtDepth,
2365
- CleanupLocation (PatternMatchStmt));
2396
+ // Now we have all of our cleanups entered, so we can record the
2397
+ // depth.
2398
+ PatternMatchStmtDepth = SGF.getCleanupsDepth ();
2399
+ }
2400
+
2401
+ void PatternMatchEmission::
2402
+ emitAddressOnlyInitialization (VarDecl *dest, SILValue value) {
2403
+ auto found = Temporaries.find (dest);
2404
+ assert (found != Temporaries.end ());
2405
+ SGF.B .createCopyAddr (dest, value, found->second , IsNotTake, IsInitialization);
2366
2406
}
2367
2407
2368
2408
// / Emit all the shared case statements.
@@ -2388,8 +2428,13 @@ void PatternMatchEmission::emitSharedCaseBlocks() {
2388
2428
SGF.B .setInsertionPoint (predBB);
2389
2429
2390
2430
} else {
2431
+ // FIXME: Figure out why this is necessary.
2432
+ if (caseBB->pred_empty ()) {
2433
+ SGF.eraseBasicBlock (caseBB);
2434
+ continue ;
2435
+ }
2436
+
2391
2437
// Otherwise, move the block to after the first predecessor.
2392
- assert (!caseBB->pred_empty () && " Emitted an unused shared block?" );
2393
2438
auto predBB = *caseBB->pred_begin ();
2394
2439
caseBB->moveAfter (predBB);
2395
2440
@@ -2412,27 +2457,37 @@ void PatternMatchEmission::emitSharedCaseBlocks() {
2412
2457
return ;
2413
2458
2414
2459
SILType ty = SGF.getLoweredType (V->getType ());
2460
+
2461
+ SILValue value;
2415
2462
if (ty.isAddressOnly (SGF.F .getModule ())) {
2416
- // Just assign SILUndef as a value for address only values.
2417
- SGF.VarLocs [V].value = SILUndef::get (ty, SGF.F .getModule ());
2418
- return ;
2463
+ // There's no basic block argument, since we don't allow basic blocks
2464
+ // to have address arguments.
2465
+ //
2466
+ // Instead, we map the variable to a temporary alloc_stack in
2467
+ // emitAddressOnlyAllocations(), and store into it at each
2468
+ // predecessor block.
2469
+ //
2470
+ // There's nothing to do here, since the value should already have
2471
+ // been initialized on entry.
2472
+ auto found = Temporaries.find (V);
2473
+ assert (found != Temporaries.end ());
2474
+ value = found->second ;
2475
+ } else {
2476
+ value = caseBB->getArgument (argIndex++);
2419
2477
}
2420
2478
2421
2479
if (V->isLet ()) {
2422
2480
// Just emit a let with cleanup.
2423
- SGF.VarLocs [V].value = caseBB->getArgument (argIndex++);
2424
- SGF.emitInitializationForVarDecl (V, V->isLet ())
2425
- ->finishInitialization (SGF);
2481
+ SGF.VarLocs [V].value = value;
2482
+ SGF.enterDestroyCleanup (value);
2426
2483
} else {
2427
2484
// The pattern variables were all emitted as lets and one got passed in,
2428
2485
// now we finally alloc a box for the var and forward in the chosen value.
2429
2486
SGF.VarLocs .erase (V);
2430
2487
auto newVar = SGF.emitInitializationForVarDecl (V, V->isLet ());
2431
- auto loc = SGF.CurrentSILLoc ;
2432
- auto value =
2433
- ManagedValue::forUnmanaged (caseBB->getArgument (argIndex++));
2434
- auto formalType = V->getType ()->getCanonicalType ();
2435
- RValue (SGF, loc, formalType, value).forwardInto (SGF, loc, newVar.get ());
2488
+ auto mv = ManagedValue::forUnmanaged (value);
2489
+ newVar->copyOrInitValueInto (SGF, V, mv, /* isInit*/ true );
2490
+ newVar->finishInitialization (SGF);
2436
2491
}
2437
2492
});
2438
2493
emitCaseBody (caseBlock);
@@ -2531,35 +2586,6 @@ void SILGenFunction::usingImplicitVariablesForPattern(Pattern *pattern, CaseStmt
2531
2586
variableSwapper ();
2532
2587
}
2533
2588
2534
- static void diagnoseMultiPatternCaseAddressOnlyBinding (SILGenFunction &SGF,
2535
- ValueDecl *decl,
2536
- SILValue value) {
2537
- SILLocation loc (decl);
2538
-
2539
- // Try to figure out why this is an address only type. This is just an
2540
- // approximation. The targets of interest are:
2541
- //
2542
- // 1. existentials.
2543
- // 2. generics.
2544
- //
2545
- // If we are unable to show that we have an existential or generic, we use the
2546
- // more general unknown_addressonly_type_used_in_multipattern_case diagnostic.
2547
- unsigned errorPatternIndex = 0 ;
2548
- CanType ty = value->getType ().getSwiftRValueType ();
2549
-
2550
- if (ty.findIf ([&](Type ty) -> bool {
2551
- return ty->is <ProtocolType>() || ty->is <ProtocolCompositionType>();
2552
- })) {
2553
- errorPatternIndex = 1 ;
2554
- } else if (ty.findIf (
2555
- [&](Type ty) -> bool { return ty->is <ArchetypeType>(); })) {
2556
- errorPatternIndex = 2 ;
2557
- }
2558
-
2559
- SGF.SGM .diagnose (loc, diag::addressonly_type_used_in_multipattern_case,
2560
- errorPatternIndex, ty);
2561
- }
2562
-
2563
2589
void SILGenFunction::emitSwitchStmt (SwitchStmt *S) {
2564
2590
DEBUG (llvm::dbgs () << " emitting switch stmt\n " ;
2565
2591
S->print (llvm::dbgs ());
@@ -2576,12 +2602,6 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2576
2602
emitIgnoredExpr (S->getSubjectExpr ());
2577
2603
return failure (SILLocation (S));
2578
2604
}
2579
-
2580
- SILBasicBlock *contBB = createBasicBlock ();
2581
- emitProfilerIncrement (S);
2582
- JumpDest contDest (contBB, Cleanups.getCleanupsDepth (), CleanupLocation (S));
2583
-
2584
- bool diagnosedError = false ;
2585
2605
2586
2606
auto completionHandler = [&](PatternMatchEmission &emission,
2587
2607
ArgArray argArray,
@@ -2595,23 +2615,18 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2595
2615
if (!caseBlock->hasBoundDecls ()) {
2596
2616
// Don't emit anything yet, we emit it at the cleanup level of the switch
2597
2617
// statement.
2598
- JumpDest sharedDest = emission.getSharedCaseBlockDest (caseBlock,
2599
- row.hasFallthroughTo ());
2618
+ JumpDest sharedDest = emission.getSharedCaseBlockDest (caseBlock);
2600
2619
Cleanups.emitBranchAndCleanups (sharedDest, caseBlock);
2601
2620
} else if (caseBlock->getCaseLabelItems ().size () > 1 ) {
2602
2621
JumpDest sharedDest =
2603
- emission.getSharedCaseBlockDest (caseBlock, row. hasFallthroughTo () );
2622
+ emission.getSharedCaseBlockDest (caseBlock);
2604
2623
2605
- // Generate the arguments from this row's pattern in the case block's expected order,
2606
- // and keep those arguments from being cleaned up, as we're passing the +1 along to
2607
- // the shared case block dest. (The cleanups still happen, as they are threaded through
2608
- // here messily, but the explicit retains here counteract them, and then the
2624
+ // Generate the arguments from this row's pattern in the case block's
2625
+ // expected order, and keep those arguments from being cleaned up, as
2626
+ // we're passing the +1 along to the shared case block dest. (The
2627
+ // cleanups still happen, as they are threaded through here messily,
2628
+ // but the explicit retains here counteract them, and then the
2609
2629
// retain/release pair gets optimized out.)
2610
- //
2611
- // *NOTE*. We assume that all values are passed as objects for
2612
- // simplicity. This is ok to do since any time we diagnose an error, we
2613
- // pass SILUndef to the shared case block. This is to maintain the CFG
2614
- // structure and thus prevent spurious 'dead code' warnings.
2615
2630
ArrayRef<CaseLabelItem> labelItems = caseBlock->getCaseLabelItems ();
2616
2631
SmallVector<SILValue, 4 > args;
2617
2632
SmallVector<VarDecl *, 4 > expectedVarOrder;
@@ -2627,10 +2642,12 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2627
2642
if (var->hasName () && var->getName () == expected->getName ()) {
2628
2643
SILValue value = VarLocs[var].value ;
2629
2644
SILType type = value->getType ();
2645
+
2646
+ // If we have an address-only type, initialize the temporary
2647
+ // allocation. We're not going to pass the address as a block
2648
+ // argument.
2630
2649
if (type.isAddressOnly (M)) {
2631
- if (!diagnosedError)
2632
- diagnoseMultiPatternCaseAddressOnlyBinding (*this , var, value);
2633
- diagnosedError = true ;
2650
+ emission.emitAddressOnlyInitialization (expected, value);
2634
2651
break ;
2635
2652
}
2636
2653
@@ -2659,19 +2676,6 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2659
2676
};
2660
2677
2661
2678
PatternMatchEmission emission (*this , S, completionHandler);
2662
-
2663
- Scope switchScope (Cleanups, CleanupLocation (S));
2664
-
2665
- // Enter a break/continue scope. If we wanted a continue
2666
- // destination, it would probably be out here.
2667
- BreakContinueDestStack.push_back ({S, contDest, JumpDest (S)});
2668
-
2669
- PatternMatchContext switchContext = { emission };
2670
- SwitchStack.push_back (&switchContext);
2671
-
2672
- // Emit the subject value. Dispatching will consume it.
2673
- ManagedValue subjectMV = emitRValueAsSingleValue (S->getSubjectExpr ());
2674
- auto subject = ConsumableManagedValue::forOwned (subjectMV);
2675
2679
2676
2680
// Add a row for each label of each case.
2677
2681
//
@@ -2681,6 +2685,12 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2681
2685
clauseRows.reserve (S->getRawCases ().size ());
2682
2686
bool hasFallthrough = false ;
2683
2687
for (auto caseBlock : S->getCases ()) {
2688
+ if (!caseBlock->hasBoundDecls () ||
2689
+ caseBlock->getCaseLabelItems ().size () > 1 ||
2690
+ hasFallthrough) {
2691
+ emission.initSharedCaseBlockDest (caseBlock, hasFallthrough);
2692
+ }
2693
+
2684
2694
for (auto &labelItem : caseBlock->getCaseLabelItems ()) {
2685
2695
clauseRows.emplace_back (caseBlock,
2686
2696
const_cast <Pattern*>(labelItem.getPattern ()),
@@ -2691,6 +2701,27 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2691
2701
hasFallthrough = containsFallthrough (caseBlock->getBody ());
2692
2702
}
2693
2703
2704
+ // Emit alloc_stacks for address-only variables appearing in
2705
+ // multiple-entry case blocks.
2706
+ emission.emitAddressOnlyAllocations ();
2707
+
2708
+ SILBasicBlock *contBB = createBasicBlock ();
2709
+ emitProfilerIncrement (S);
2710
+ JumpDest contDest (contBB, Cleanups.getCleanupsDepth (), CleanupLocation (S));
2711
+
2712
+ Scope switchScope (Cleanups, CleanupLocation (S));
2713
+
2714
+ // Enter a break/continue scope. If we wanted a continue
2715
+ // destination, it would probably be out here.
2716
+ BreakContinueDestStack.push_back ({S, contDest, JumpDest (S)});
2717
+
2718
+ PatternMatchContext switchContext = { emission };
2719
+ SwitchStack.push_back (&switchContext);
2720
+
2721
+ // Emit the subject value. Dispatching will consume it.
2722
+ ManagedValue subjectMV = emitRValueAsSingleValue (S->getSubjectExpr ());
2723
+ auto subject = ConsumableManagedValue::forOwned (subjectMV);
2724
+
2694
2725
// Set up an initial clause matrix.
2695
2726
ClauseMatrix clauses (clauseRows);
2696
2727
@@ -2723,7 +2754,7 @@ void SILGenFunction::emitSwitchFallthrough(FallthroughStmt *S) {
2723
2754
// Get the destination block.
2724
2755
CaseStmt *caseStmt = S->getFallthroughDest ();
2725
2756
JumpDest sharedDest =
2726
- context->Emission .getSharedCaseBlockDest (caseStmt, true );
2757
+ context->Emission .getSharedCaseBlockDest (caseStmt);
2727
2758
Cleanups.emitBranchAndCleanups (sharedDest, S);
2728
2759
}
2729
2760
0 commit comments