@@ -337,12 +337,53 @@ SILCombiner::visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *URCI) {
337
337
return eraseInstFromFunction (*URCI);
338
338
}
339
339
340
+ template <class CastInst >
341
+ static bool canBeUsedAsCastDestination (SILValue value, CastInst *castInst,
342
+ DominanceAnalysis *DA) {
343
+ return value &&
344
+ value->getType () == castInst->getTargetLoweredType ().getObjectType () &&
345
+ DA->get (castInst->getFunction ())->properlyDominates (value, castInst);
346
+ }
347
+
348
+
340
349
SILInstruction *
341
350
SILCombiner::
342
351
visitUnconditionalCheckedCastAddrInst (UnconditionalCheckedCastAddrInst *UCCAI) {
343
352
if (UCCAI->getFunction ()->hasOwnership ())
344
353
return nullptr ;
345
354
355
+ // Optimize the unconditional_checked_cast_addr in this pattern:
356
+ //
357
+ // %box = alloc_existential_box $Error, $ConcreteError
358
+ // %a = project_existential_box $ConcreteError in %b : $Error
359
+ // store %value to %a : $*ConcreteError
360
+ // %err = alloc_stack $Error
361
+ // store %box to %err : $*Error
362
+ // %dest = alloc_stack $ConcreteError
363
+ // unconditional_checked_cast_addr Error in %err : $*Error to
364
+ // ConcreteError in %dest : $*ConcreteError
365
+ //
366
+ // to:
367
+ // ...
368
+ // retain_value %value : $ConcreteError
369
+ // destroy_addr %err : $*Error
370
+ // store %value to %dest $*ConcreteError
371
+ //
372
+ // This lets the alloc_existential_box become dead and it can be removed in
373
+ // following optimizations.
374
+ SILValue val = getConcreteValueOfExistentialBoxAddr (UCCAI->getSrc (), UCCAI);
375
+ if (canBeUsedAsCastDestination (val, UCCAI, DA)) {
376
+ SILBuilderContext builderCtx (Builder.getModule (), Builder.getTrackingList ());
377
+ SILBuilderWithScope builder (UCCAI, builderCtx);
378
+ SILLocation loc = UCCAI->getLoc ();
379
+ builder.createRetainValue (loc, val, builder.getDefaultAtomicity ());
380
+ builder.createDestroyAddr (loc, UCCAI->getSrc ());
381
+ builder.createStore (loc, val, UCCAI->getDest (),
382
+ StoreOwnershipQualifier::Unqualified);
383
+ return eraseInstFromFunction (*UCCAI);
384
+ }
385
+
386
+ // Perform the purly type-based cast optimization.
346
387
if (CastOpt.optimizeUnconditionalCheckedCastAddrInst (UCCAI))
347
388
MadeChange = true ;
348
389
@@ -522,6 +563,62 @@ visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CCABI) {
522
563
if (CCABI->getFunction ()->hasOwnership ())
523
564
return nullptr ;
524
565
566
+ // Optimize the checked_cast_addr_br in this pattern:
567
+ //
568
+ // %box = alloc_existential_box $Error, $ConcreteError
569
+ // %a = project_existential_box $ConcreteError in %b : $Error
570
+ // store %value to %a : $*ConcreteError
571
+ // %err = alloc_stack $Error
572
+ // store %box to %err : $*Error
573
+ // %dest = alloc_stack $ConcreteError
574
+ // checked_cast_addr_br <consumption-kind> Error in %err : $*Error to
575
+ // ConcreteError in %dest : $*ConcreteError, success_bb, failing_bb
576
+ //
577
+ // to:
578
+ // ...
579
+ // retain_value %value : $ConcreteError
580
+ // destroy_addr %err : $*Error // if consumption-kind is take
581
+ // store %value to %dest $*ConcreteError
582
+ // br success_bb
583
+ //
584
+ // This lets the alloc_existential_box become dead and it can be removed in
585
+ // following optimizations.
586
+ //
587
+ // TODO: Also handle the WillFail case.
588
+ SILValue val = getConcreteValueOfExistentialBoxAddr (CCABI->getSrc (), CCABI);
589
+ if (canBeUsedAsCastDestination (val, CCABI, DA)) {
590
+ SILBuilderContext builderCtx (Builder.getModule (), Builder.getTrackingList ());
591
+ SILBuilderWithScope builder (CCABI, builderCtx);
592
+ SILLocation loc = CCABI->getLoc ();
593
+ builder.createRetainValue (loc, val, builder.getDefaultAtomicity ());
594
+ switch (CCABI->getConsumptionKind ()) {
595
+ case CastConsumptionKind::TakeAlways:
596
+ case CastConsumptionKind::TakeOnSuccess:
597
+ builder.createDestroyAddr (loc, CCABI->getSrc ());
598
+ break ;
599
+ case CastConsumptionKind::CopyOnSuccess:
600
+ break ;
601
+ case CastConsumptionKind::BorrowAlways:
602
+ llvm_unreachable (" BorrowAlways is not supported on addresses" );
603
+ }
604
+ builder.createStore (loc, val, CCABI->getDest (),
605
+ StoreOwnershipQualifier::Unqualified);
606
+
607
+ // Replace the cast with a constant conditional branch.
608
+ // Don't just create an unconditional branch to not change the CFG in
609
+ // SILCombine. SimplifyCFG will clean that up.
610
+ //
611
+ // Another possibility would be to run this optimization in SimplifyCFG.
612
+ // But this has other problems, like it's more difficult to reason about a
613
+ // consistent dominator tree in SimplifyCFG.
614
+ SILType boolTy = SILType::getBuiltinIntegerType (1 , builder.getASTContext ());
615
+ auto *trueVal = builder.createIntegerLiteral (loc, boolTy, 1 );
616
+ builder.createCondBranch (loc, trueVal, CCABI->getSuccessBB (),
617
+ CCABI->getFailureBB ());
618
+ return eraseInstFromFunction (*CCABI);
619
+ }
620
+
621
+ // Perform the purly type-based cast optimization.
525
622
if (CastOpt.optimizeCheckedCastAddrBranchInst (CCABI))
526
623
MadeChange = true ;
527
624
0 commit comments