/// Carry out the operations required for an indirect conditional cast /// using a scalar cast operation. void swift:: emitIndirectConditionalCastWithScalar(SILBuilder &B, Module *M, SILLocation loc, CastConsumptionKind consumption, SILValue src, CanType sourceType, SILValue dest, CanType targetType, SILBasicBlock *indirectSuccBB, SILBasicBlock *indirectFailBB) { assert(canUseScalarCheckedCastInstructions(B.getModule(), sourceType, targetType)); // We only need a different failure block if the cast consumption // requires us to destroy the source value. SILBasicBlock *scalarFailBB; if (!shouldDestroyOnFailure(consumption)) { scalarFailBB = indirectFailBB; } else { scalarFailBB = B.splitBlockForFallthrough(); } // We always need a different success block. SILBasicBlock *scalarSuccBB = B.splitBlockForFallthrough(); auto &srcTL = B.getModule().Types.getTypeLowering(src->getType()); // Always take; this works under an assumption that retaining the // result is equivalent to retaining the source. That means that // these casts would not be appropriate for bridging-like conversions. SILValue srcValue = srcTL.emitLoadOfCopy(B, loc, src, IsTake); SILType targetValueType = dest->getType().getObjectType(); B.createCheckedCastBranch(loc, /*exact*/ false, srcValue, targetValueType, scalarSuccBB, scalarFailBB); // Emit the success block. B.setInsertionPoint(scalarSuccBB); { auto &targetTL = B.getModule().Types.getTypeLowering(targetValueType); SILValue succValue = new (B.getModule()) SILArgument(scalarSuccBB, targetValueType); if (!shouldTakeOnSuccess(consumption)) targetTL.emitRetainValue(B, loc, succValue); targetTL.emitStoreOfCopy(B, loc, succValue, dest, IsInitialization); B.createBranch(loc, indirectSuccBB); } // Emit the failure block. if (shouldDestroyOnFailure(consumption)) { B.setInsertionPoint(scalarFailBB); srcTL.emitReleaseValue(B, loc, srcValue); B.createBranch(loc, indirectFailBB); } }
void BridgedReturn::outline(SILFunction *Fun, ApplyInst *NewOutlinedCall) { // Outline the bridged return result blocks. // switch_enum %20 : $Optional<NSString>, case #O.some: bb1, case #O.none: bb2 // // bb1(%23 : $NSString): // %24 = function_ref @$SSS10FoundationE36_unconditionallyBridgeFromObjectiveC // %25 = enum $Optional<NSString>, #Optional.some!enumelt.1, %23 : $NSString // %26 = metatype $@thin String.Type // %27 = apply %24(%25, %26) // %28 = enum $Optional<String>, #Optional.some!enumelt.1, %27 : $String // br bb3(%28 : $Optional<String>) // // bb2: // %30 = enum $Optional<String>, #Optional.none!enumelt // br bb3(%30 : $Optional<String>) // // bb3(%32 : $Optional<String>): auto *StartBB = switchInfo.SwitchEnum->getParent(); auto *OutlinedEntryBB = StartBB->split(SILBasicBlock::iterator(switchInfo.SwitchEnum)); auto *OldMergeBB = switchInfo.Br->getDestBB(); auto *NewTailBB = OldMergeBB->split(OldMergeBB->begin()); auto Loc = switchInfo.SwitchEnum->getLoc(); { SILBuilder Builder(StartBB); Builder.createBranch(Loc, NewTailBB); OldMergeBB->getArgument(0)->replaceAllUsesWith(NewOutlinedCall); } // Outlined function already existed. Just delete instructions and wire up // blocks. if (!Fun) { OutlinedEntryBB->eraseInstructions(); OutlinedEntryBB->eraseFromParent(); switchInfo.NoneBB->eraseInstructions(); switchInfo.NoneBB->eraseFromParent(); switchInfo.SomeBB->eraseInstructions(); switchInfo.SomeBB->eraseFromParent(); OldMergeBB->eraseInstructions(); OldMergeBB->eraseFromParent(); return; } // Move the blocks into the new function. assert(Fun->begin() != Fun->end() && "The entry block must already have been created"); SILBasicBlock *EntryBB = &*Fun->begin(); auto &FromBlockList = OutlinedEntryBB->getParent()->getBlocks(); Fun->getBlocks().splice(Fun->begin(), FromBlockList, OldMergeBB); OldMergeBB->moveAfter(EntryBB); auto InsertPt = SILFunction::iterator(OldMergeBB); Fun->getBlocks().splice(InsertPt, FromBlockList, OutlinedEntryBB); Fun->getBlocks().splice(InsertPt, FromBlockList, switchInfo.NoneBB); Fun->getBlocks().splice(InsertPt, FromBlockList, switchInfo.SomeBB); SILBuilder Builder (EntryBB); Builder.createBranch(Loc, OutlinedEntryBB); Builder.setInsertionPoint(OldMergeBB); Builder.createReturn(Loc, OldMergeBB->getArgument(0)); }