@@ -66,23 +66,52 @@ getObjCToSwiftBridgingFunction(SILOptFunctionBuilder &funcBuilder,
6666 ForDefinition_t::NotForDefinition);
6767}
6868
69+ static SubstitutionMap lookupBridgeToObjCProtocolSubs (SILModule &mod,
70+ CanType target) {
71+ auto bridgedProto =
72+ mod.getASTContext ().getProtocol (KnownProtocolKind::ObjectiveCBridgeable);
73+ auto conf = *mod.getSwiftModule ()->lookupConformance (target, bridgedProto);
74+ return SubstitutionMap::getProtocolSubstitutions (conf.getRequirement (),
75+ target, conf);
76+ }
77+
6978// / Create a call of _forceBridgeFromObjectiveC_bridgeable or
7079// / _conditionallyBridgeFromObjectiveC_bridgeable which converts an ObjC
7180// / instance into a corresponding Swift type, conforming to
7281// / _ObjectiveCBridgeable.
7382SILInstruction *
7483CastOptimizer::optimizeBridgedObjCToSwiftCast (SILDynamicCastInst dynamicCast) {
84+ auto kind = dynamicCast.getKind ();
85+ (void )kind;
86+ assert (((kind == SILDynamicCastKind::CheckedCastAddrBranchInst) ||
87+ (kind == SILDynamicCastKind::UnconditionalCheckedCastAddrInst)) &&
88+ " Unsupported dynamic cast kind" );
89+
90+ CanType target = dynamicCast.getTargetType ();
91+ auto &mod = dynamicCast.getModule ();
92+
93+ // AnyHashable is a special case that we do not handle since we only handle
94+ // objc targets in this function. Bailout early.
95+ if (auto dt = target.getNominalOrBoundGenericNominal ()) {
96+ if (dt == mod.getASTContext ().getAnyHashableDecl ()) {
97+ return nullptr ;
98+ }
99+ }
100+
101+ SILValue src = dynamicCast.getSource ();
102+ // Check if we have a source type that is address only. We do not support that
103+ // today.
104+ if (src->getType ().isAddressOnly (mod)) {
105+ return nullptr ;
106+ }
75107
76108 SILInstruction *Inst = dynamicCast.getInstruction ();
77109 bool isConditional = dynamicCast.isConditional ();
78- SILValue Src = dynamicCast.getSource ();
79110 SILValue Dest = dynamicCast.getDest ();
80- CanType Target = dynamicCast.getTargetType ();
81111 CanType BridgedTargetTy = dynamicCast.getBridgedTargetType ();
82112 SILBasicBlock *SuccessBB = dynamicCast.getSuccessBlock ();
83113 SILBasicBlock *FailureBB = dynamicCast.getFailureBlock ();
84114 auto *F = Inst->getFunction ();
85- auto &M = Inst->getModule ();
86115 auto Loc = Inst->getLoc ();
87116
88117 // The conformance to _BridgedToObjectiveC is statically known.
@@ -93,23 +122,16 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
93122 if (!bridgingFunc)
94123 return nullptr ;
95124
125+ auto paramTypes = bridgingFunc->getLoweredFunctionType ()->getParameters ();
126+ (void )paramTypes;
127+ assert (paramTypes[0 ].getConvention () ==
128+ ParameterConvention::Direct_Guaranteed &&
129+ " Parameter should be @guaranteed" );
130+
96131 CanType CanBridgedTy = BridgedTargetTy->getCanonicalType ();
97- SILType SILBridgedTy = SILType::getPrimitiveObjectType (CanBridgedTy);
132+ SILType silBridgedTy = SILType::getPrimitiveObjectType (CanBridgedTy);
98133
99134 SILBuilderWithScope Builder (Inst, BuilderContext);
100- SILValue SrcOp;
101- SILInstruction *NewI = nullptr ;
102-
103- assert (Src->getType ().isAddress () && " Source should have an address type" );
104- assert (Dest->getType ().isAddress () && " Source should have an address type" );
105-
106- // AnyHashable is a special case - it does not conform to NSObject -
107- // If AnyHashable - Bail out of the optimization
108- if (auto DT = Target.getNominalOrBoundGenericNominal ()) {
109- if (DT == M.getASTContext ().getAnyHashableDecl ()) {
110- return nullptr ;
111- }
112- }
113135
114136 // If this is a conditional cast:
115137 // We need a new fail BB in order to add a dealloc_stack to it
@@ -121,81 +143,59 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
121143 Builder.setInsertionPoint (CurrInsPoint);
122144 }
123145
124- // We know this is always true since SILBridgedTy is an object and Src is an
125- // address.
126- assert (SILBridgedTy != Src->getType ());
127-
128146 // Check if we can simplify a cast into:
129147 // - ObjCTy to _ObjectiveCBridgeable._ObjectiveCType.
130148 // - then convert _ObjectiveCBridgeable._ObjectiveCType to
131149 // a Swift type using _forceBridgeFromObjectiveC.
132150
133- if (!Src->getType ().isLoadable (M)) {
134- // This code path is never reached in current test cases
135- // If reached, we'd have to convert from an ObjC Any* to a loadable type
136- // Should use check_addr / make a source we can actually load
137- return nullptr ;
138- }
151+ // Inline constructor.
152+ SILValue srcOp;
153+ SILInstruction *newI;
154+ std::tie (srcOp, newI) = [&]() -> std::pair<SILValue, SILInstruction *> {
155+ // Generate a load for the source argument.
156+ SILValue load =
157+ Builder.createLoad (Loc, src, LoadOwnershipQualifier::Unqualified);
158+
159+ // If type of the source and the expected ObjC type are equal, there is no
160+ // need to generate the conversion from ObjCTy to
161+ // _ObjectiveCBridgeable._ObjectiveCType.
162+ if (load->getType () == silBridgedTy) {
163+ if (isConditional) {
164+ SILBasicBlock *castSuccessBB = F->createBasicBlock ();
165+ castSuccessBB->createPhiArgument (silBridgedTy,
166+ ValueOwnershipKind::Owned);
167+ Builder.createBranch (Loc, castSuccessBB, load);
168+ Builder.setInsertionPoint (castSuccessBB);
169+ return {castSuccessBB->getArgument (0 ), nullptr };
170+ }
139171
140- // Generate a load for the source argument.
141- auto *Load =
142- Builder.createLoad (Loc, Src, LoadOwnershipQualifier::Unqualified);
143- // Try to convert the source into the expected ObjC type first.
172+ return {load, nullptr };
173+ }
144174
145- if (Load->getType () == SILBridgedTy) {
146- // If type of the source and the expected ObjC type are
147- // equal, there is no need to generate the conversion
148- // from ObjCTy to _ObjectiveCBridgeable._ObjectiveCType.
149175 if (isConditional) {
150- SILBasicBlock *CastSuccessBB = F->createBasicBlock ();
151- CastSuccessBB ->createPhiArgument (SILBridgedTy , ValueOwnershipKind::Owned);
152- Builder.createBranch (Loc, CastSuccessBB, SILValue (Load));
153- Builder. setInsertionPoint (CastSuccessBB );
154- SrcOp = CastSuccessBB-> getArgument ( 0 );
155- } else {
156- SrcOp = Load ;
176+ SILBasicBlock *castSuccessBB = F->createBasicBlock ();
177+ castSuccessBB ->createPhiArgument (silBridgedTy , ValueOwnershipKind::Owned);
178+ auto *ccbi = Builder.createCheckedCastBranch (
179+ Loc, false , load, silBridgedTy, castSuccessBB, ConvFailBB );
180+ splitEdge (ccbi, /* EdgeIdx to ConvFailBB */ 1 );
181+ Builder. setInsertionPoint (castSuccessBB);
182+ return {castSuccessBB-> getArgument ( 0 ), ccbi} ;
157183 }
158- } else if (isConditional) {
159- SILBasicBlock *CastSuccessBB = F->createBasicBlock ();
160- CastSuccessBB->createPhiArgument (SILBridgedTy, ValueOwnershipKind::Owned);
161- auto *CCBI = Builder.createCheckedCastBranch (Loc, false , Load, SILBridgedTy,
162- CastSuccessBB, ConvFailBB);
163- NewI = CCBI;
164- splitEdge (CCBI, /* EdgeIdx to ConvFailBB */ 1 );
165- Builder.setInsertionPoint (CastSuccessBB);
166- SrcOp = CastSuccessBB->getArgument (0 );
167- } else {
168- auto cast = Builder.createUnconditionalCheckedCast (Loc, Load, SILBridgedTy);
169- NewI = cast;
170- SrcOp = cast;
171- }
184+
185+ auto *cast =
186+ Builder.createUnconditionalCheckedCast (Loc, load, silBridgedTy);
187+ return {cast, cast};
188+ }();
172189
173190 // Now emit the a cast from the casted ObjC object into a target type.
174191 // This is done by means of calling _forceBridgeFromObjectiveC or
175192 // _conditionallyBridgeFromObjectiveC_bridgeable from the Target type.
176- // Lookup the required function in the Target type.
177-
178- // Lookup the _ObjectiveCBridgeable protocol.
179- auto BridgedProto =
180- M.getASTContext ().getProtocol (KnownProtocolKind::ObjectiveCBridgeable);
181- auto Conf = *M.getSwiftModule ()->lookupConformance (Target, BridgedProto);
182-
183- auto ParamTypes = bridgingFunc->getLoweredFunctionType ()->getParameters ();
193+ auto *funcRef = Builder.createFunctionRef (Loc, bridgingFunc);
194+ SubstitutionMap subMap = lookupBridgeToObjCProtocolSubs (mod, target);
184195
185- auto *FuncRef = Builder.createFunctionRef (Loc, bridgingFunc);
186-
187- auto MetaTy = MetatypeType::get (Target, MetatypeRepresentation::Thick);
196+ auto MetaTy = MetatypeType::get (target, MetatypeRepresentation::Thick);
188197 auto SILMetaTy = F->getTypeLowering (MetaTy).getLoweredType ();
189198 auto *MetaTyVal = Builder.createMetatype (Loc, SILMetaTy);
190- SmallVector<SILValue, 1 > Args;
191-
192- // Add substitutions
193- auto SubMap = SubstitutionMap::getProtocolSubstitutions (Conf.getRequirement (),
194- Target, Conf);
195-
196- auto SILFnTy = FuncRef->getType ();
197- SILType SubstFnTy = SILFnTy.substGenericArgs (M, SubMap);
198- SILFunctionConventions substConv (SubstFnTy.castTo <SILFunctionType>(), M);
199199
200200 // Temporary to hold the intermediate result.
201201 AllocStackInst *Tmp = nullptr ;
@@ -213,38 +213,35 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
213213 InOutOptionalParam = Dest;
214214 }
215215
216- (void )ParamTypes;
217- assert (ParamTypes[0 ].getConvention () == ParameterConvention::Direct_Guaranteed &&
218- " Parameter should be @guaranteed" );
219-
220216 // Emit a retain.
221- Builder.createRetainValue (Loc, SrcOp , Builder.getDefaultAtomicity ());
217+ Builder.createRetainValue (Loc, srcOp , Builder.getDefaultAtomicity ());
222218
219+ SmallVector<SILValue, 1 > Args;
223220 Args.push_back (InOutOptionalParam);
224- Args.push_back (SrcOp );
221+ Args.push_back (srcOp );
225222 Args.push_back (MetaTyVal);
226223
227- auto *AI = Builder.createApply (Loc, FuncRef, SubMap , Args, false );
224+ auto *AI = Builder.createApply (Loc, funcRef, subMap , Args, false );
228225
229226 // If we have guaranteed normal arguments, insert the destroy.
230227 //
231228 // TODO: Is it safe to just eliminate the initial retain?
232- Builder.createReleaseValue (Loc, SrcOp , Builder.getDefaultAtomicity ());
229+ Builder.createReleaseValue (Loc, srcOp , Builder.getDefaultAtomicity ());
233230
234231 // If the source of a cast should be destroyed, emit a release.
235232 if (isa<UnconditionalCheckedCastAddrInst>(Inst)) {
236- Builder.createReleaseValue (Loc, SrcOp , Builder.getDefaultAtomicity ());
233+ Builder.createReleaseValue (Loc, srcOp , Builder.getDefaultAtomicity ());
237234 }
238235
239236 if (auto *CCABI = dyn_cast<CheckedCastAddrBranchInst>(Inst)) {
240237 switch (CCABI->getConsumptionKind ()) {
241238 case CastConsumptionKind::TakeAlways:
242- Builder.createReleaseValue (Loc, SrcOp , Builder.getDefaultAtomicity ());
239+ Builder.createReleaseValue (Loc, srcOp , Builder.getDefaultAtomicity ());
243240 break ;
244241 case CastConsumptionKind::TakeOnSuccess:
245242 // Insert a release in the success BB.
246243 Builder.setInsertionPoint (SuccessBB->begin ());
247- Builder.createReleaseValue (Loc, SrcOp , Builder.getDefaultAtomicity ());
244+ Builder.createReleaseValue (Loc, srcOp , Builder.getDefaultAtomicity ());
248245 break ;
249246 case CastConsumptionKind::BorrowAlways:
250247 llvm_unreachable (" checked_cast_addr_br never has BorrowAlways" );
@@ -263,7 +260,7 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
263260 SILBasicBlock *ConvSuccessBB = Inst->getFunction ()->createBasicBlock ();
264261 SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 1 > CaseBBs;
265262 CaseBBs.push_back (
266- std::make_pair (M .getASTContext ().getOptionalNoneDecl (), FailureBB));
263+ std::make_pair (mod .getASTContext ().getOptionalNoneDecl (), FailureBB));
267264 Builder.createSwitchEnumAddr (Loc, InOutOptionalParam, ConvSuccessBB,
268265 CaseBBs);
269266
@@ -282,7 +279,7 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
282279 }
283280
284281 EraseInstAction (Inst);
285- return (NewI ) ? NewI : AI;
282+ return (newI ) ? newI : AI;
286283}
287284
288285static bool canOptimizeCast (const swift::Type &BridgedTargetTy,
0 commit comments