Skip to content

Commit 98c20d4

Browse files
committed
[cast-opt] Slim down a large function by extracting out a part of it into a subroutine.
I also added documentation around what the code is actually trying to do/invariants/etc. NFCI.
1 parent d1389ad commit 98c20d4

File tree

1 file changed

+73
-54
lines changed

1 file changed

+73
-54
lines changed

lib/SILOptimizer/Utils/CastOptimizer.cpp

+73-54
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,72 @@ static SubstitutionMap lookupBridgeToObjCProtocolSubs(SILModule &mod,
7575
target, conf);
7676
}
7777

78+
/// Given that our insertion point is at the cast that we are trying to
79+
/// optimize, convert our incoming value to something that can be passed to the
80+
/// bridge call.
81+
static std::pair<SILValue, SILInstruction *>
82+
convertObjectToLoadableBridgeableType(SILBuilderWithScope &builder,
83+
SILDynamicCastInst dynamicCast,
84+
SILValue src) {
85+
auto *f = dynamicCast.getFunction();
86+
auto loc = dynamicCast.getLocation();
87+
bool isConditional = dynamicCast.isConditional();
88+
89+
SILValue load =
90+
builder.createLoad(loc, src, LoadOwnershipQualifier::Unqualified);
91+
92+
SILType silBridgedTy = *dynamicCast.getLoweredBridgedTargetObjectType();
93+
94+
// If we are not conditional...
95+
if (!isConditional) {
96+
// and our loaded type is our bridged type, just return the load as our
97+
// SILValue and signal to our caller that we did not create a new cast
98+
// instruction by returning nullptr as second.
99+
if (load->getType() == silBridgedTy) {
100+
return {load, nullptr};
101+
}
102+
103+
// Otherwise, just perform an unconditional checked cast to the sil bridged
104+
// ty. We return the cast as our value and as our new cast instruction.
105+
auto *cast =
106+
builder.createUnconditionalCheckedCast(loc, load, silBridgedTy);
107+
return {cast, cast};
108+
}
109+
110+
// If we /are/ conditional and we do not need to bridge the load to the sil,
111+
// then we just create our cast success block and branch from the end of the
112+
// cast instruction block to the cast success block. We leave our insertion
113+
// point in the cast success block since when we return, we are going to
114+
// insert the bridge call/switch there. We return the argument of the cast
115+
// success block as the value to be passed to the bridging function.
116+
if (load->getType() == silBridgedTy) {
117+
SILBasicBlock *castSuccessBB = f->createBasicBlock();
118+
castSuccessBB->createPhiArgument(silBridgedTy, ValueOwnershipKind::Owned);
119+
builder.createBranch(loc, castSuccessBB, load);
120+
builder.setInsertionPoint(castSuccessBB);
121+
return {castSuccessBB->getArgument(0), nullptr};
122+
}
123+
124+
auto *castFailBB = ([&]() -> SILBasicBlock * {
125+
auto *failureBB = dynamicCast.getFailureBlock();
126+
SILBuilderWithScope failureBBBuilder(&(*failureBB->begin()), builder);
127+
return splitBasicBlockAndBranch(failureBBBuilder, &(*failureBB->begin()),
128+
nullptr, nullptr);
129+
}());
130+
131+
// Ok, we need to perform the full cast optimization. This means that we are
132+
// going to replace the cast terminator in inst_block with a
133+
// checked_cast_br. This in turn means
134+
auto *castSuccessBB = f->createBasicBlock();
135+
castSuccessBB->createPhiArgument(silBridgedTy, ValueOwnershipKind::Owned);
136+
137+
auto *ccbi = builder.createCheckedCastBranch(loc, false, load, silBridgedTy,
138+
castSuccessBB, castFailBB);
139+
splitEdge(ccbi, /* EdgeIdx to CastFailBB */ 1);
140+
builder.setInsertionPoint(castSuccessBB);
141+
return {castSuccessBB->getArgument(0), ccbi};
142+
}
143+
78144
/// Create a call of _forceBridgeFromObjectiveC_bridgeable or
79145
/// _conditionallyBridgeFromObjectiveC_bridgeable which converts an ObjC
80146
/// instance into a corresponding Swift type, conforming to
@@ -187,62 +253,15 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
187253

188254
SILBuilderWithScope Builder(Inst, builderContext);
189255

190-
// If this is a conditional cast:
191-
//
192-
// We need a new fail BB in order to add a dealloc_stack to it
193-
SILBasicBlock *CastFailBB = nullptr;
194-
if (isConditional) {
195-
auto CurrInsPoint = Builder.getInsertionPoint();
196-
CastFailBB = splitBasicBlockAndBranch(Builder, &(*FailureBB->begin()),
197-
nullptr, nullptr);
198-
Builder.setInsertionPoint(CurrInsPoint);
199-
}
200-
201-
// Check if we can simplify a cast into:
202-
// - ObjCTy to _ObjectiveCBridgeable._ObjectiveCType.
203-
// - then convert _ObjectiveCBridgeable._ObjectiveCType to
204-
// a Swift type using _forceBridgeFromObjectiveC.
205-
206-
// Inline constructor.
256+
// Generate a load for the source argument since as part of our optimization
257+
// we are going to promote the cast to work with objects instead of
258+
// addresses. Additionally, if we have an objc object that is not bridgeable,
259+
// but that could be converted to something that is bridgeable, we try to
260+
// convert to the bridgeable type.
207261
SILValue srcOp;
208262
SILInstruction *newI;
209-
std::tie(srcOp, newI) = [&]() -> std::pair<SILValue, SILInstruction *> {
210-
// Generate a load for the source argument.
211-
SILValue load =
212-
Builder.createLoad(Loc, src, LoadOwnershipQualifier::Unqualified);
213-
214-
SILType silBridgedTy = *dynamicCast.getLoweredBridgedTargetObjectType();
215-
216-
// If type of the source and the expected ObjC type are equal, there is no
217-
// need to generate the conversion from ObjCTy to
218-
// _ObjectiveCBridgeable._ObjectiveCType.
219-
if (load->getType() == silBridgedTy) {
220-
if (isConditional) {
221-
SILBasicBlock *castSuccessBB = F->createBasicBlock();
222-
castSuccessBB->createPhiArgument(silBridgedTy,
223-
ValueOwnershipKind::Owned);
224-
Builder.createBranch(Loc, castSuccessBB, load);
225-
Builder.setInsertionPoint(castSuccessBB);
226-
return {castSuccessBB->getArgument(0), nullptr};
227-
}
228-
229-
return {load, nullptr};
230-
}
231-
232-
if (isConditional) {
233-
SILBasicBlock *castSuccessBB = F->createBasicBlock();
234-
castSuccessBB->createPhiArgument(silBridgedTy, ValueOwnershipKind::Owned);
235-
auto *ccbi = Builder.createCheckedCastBranch(
236-
Loc, false, load, silBridgedTy, castSuccessBB, CastFailBB);
237-
splitEdge(ccbi, /* EdgeIdx to CastFailBB */ 1);
238-
Builder.setInsertionPoint(castSuccessBB);
239-
return {castSuccessBB->getArgument(0), ccbi};
240-
}
241-
242-
auto *cast =
243-
Builder.createUnconditionalCheckedCast(Loc, load, silBridgedTy);
244-
return {cast, cast};
245-
}();
263+
std::tie(srcOp, newI) =
264+
convertObjectToLoadableBridgeableType(Builder, dynamicCast, src);
246265

247266
// Now emit the a cast from the casted ObjC object into a target type.
248267
// This is done by means of calling _forceBridgeFromObjectiveC or

0 commit comments

Comments
 (0)