Skip to content

Commit 042b742

Browse files
authored
Merge pull request llvm#23987 from gottesmm/pr-60fe2b33f02283c1007c6f0b3446dc213026cbbf
[cast-opt] Small clarity improvements and refactoring.
2 parents 9347328 + 98c20d4 commit 042b742

File tree

2 files changed

+80
-56
lines changed

2 files changed

+80
-56
lines changed

include/swift/SIL/DynamicCasts.h

+7
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,13 @@ struct SILDynamicCastInst {
448448
return t->getCanonicalType();
449449
}
450450

451+
Optional<SILType> getLoweredBridgedTargetObjectType() const {
452+
CanType t = getBridgedTargetType();
453+
if (!t)
454+
return None;
455+
return SILType::getPrimitiveObjectType(t);
456+
}
457+
451458
bool isConditional() const {
452459
switch (getKind()) {
453460
case SILDynamicCastKind::CheckedCastAddrBranchInst: {

lib/SILOptimizer/Utils/CastOptimizer.cpp

+73-56
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
@@ -166,7 +232,6 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
166232
SILInstruction *Inst = dynamicCast.getInstruction();
167233
bool isConditional = dynamicCast.isConditional();
168234
SILValue Dest = dynamicCast.getDest();
169-
CanType BridgedTargetTy = dynamicCast.getBridgedTargetType();
170235
SILBasicBlock *SuccessBB = dynamicCast.getSuccessBlock();
171236
SILBasicBlock *FailureBB = dynamicCast.getFailureBlock();
172237
auto *F = Inst->getFunction();
@@ -186,65 +251,17 @@ CastOptimizer::optimizeBridgedObjCToSwiftCast(SILDynamicCastInst dynamicCast) {
186251
ParameterConvention::Direct_Guaranteed &&
187252
"Parameter should be @guaranteed");
188253

189-
CanType CanBridgedTy = BridgedTargetTy->getCanonicalType();
190-
SILType silBridgedTy = SILType::getPrimitiveObjectType(CanBridgedTy);
191-
192254
SILBuilderWithScope Builder(Inst, builderContext);
193255

194-
// If this is a conditional cast:
195-
//
196-
// We need a new fail BB in order to add a dealloc_stack to it
197-
SILBasicBlock *CastFailBB = nullptr;
198-
if (isConditional) {
199-
auto CurrInsPoint = Builder.getInsertionPoint();
200-
CastFailBB = splitBasicBlockAndBranch(Builder, &(*FailureBB->begin()),
201-
nullptr, nullptr);
202-
Builder.setInsertionPoint(CurrInsPoint);
203-
}
204-
205-
// Check if we can simplify a cast into:
206-
// - ObjCTy to _ObjectiveCBridgeable._ObjectiveCType.
207-
// - then convert _ObjectiveCBridgeable._ObjectiveCType to
208-
// a Swift type using _forceBridgeFromObjectiveC.
209-
210-
// 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.
211261
SILValue srcOp;
212262
SILInstruction *newI;
213-
std::tie(srcOp, newI) = [&]() -> std::pair<SILValue, SILInstruction *> {
214-
// Generate a load for the source argument.
215-
SILValue load =
216-
Builder.createLoad(Loc, src, LoadOwnershipQualifier::Unqualified);
217-
218-
// If type of the source and the expected ObjC type are equal, there is no
219-
// need to generate the conversion from ObjCTy to
220-
// _ObjectiveCBridgeable._ObjectiveCType.
221-
if (load->getType() == silBridgedTy) {
222-
if (isConditional) {
223-
SILBasicBlock *castSuccessBB = F->createBasicBlock();
224-
castSuccessBB->createPhiArgument(silBridgedTy,
225-
ValueOwnershipKind::Owned);
226-
Builder.createBranch(Loc, castSuccessBB, load);
227-
Builder.setInsertionPoint(castSuccessBB);
228-
return {castSuccessBB->getArgument(0), nullptr};
229-
}
230-
231-
return {load, nullptr};
232-
}
233-
234-
if (isConditional) {
235-
SILBasicBlock *castSuccessBB = F->createBasicBlock();
236-
castSuccessBB->createPhiArgument(silBridgedTy, ValueOwnershipKind::Owned);
237-
auto *ccbi = Builder.createCheckedCastBranch(
238-
Loc, false, load, silBridgedTy, castSuccessBB, CastFailBB);
239-
splitEdge(ccbi, /* EdgeIdx to CastFailBB */ 1);
240-
Builder.setInsertionPoint(castSuccessBB);
241-
return {castSuccessBB->getArgument(0), ccbi};
242-
}
243-
244-
auto *cast =
245-
Builder.createUnconditionalCheckedCast(Loc, load, silBridgedTy);
246-
return {cast, cast};
247-
}();
263+
std::tie(srcOp, newI) =
264+
convertObjectToLoadableBridgeableType(Builder, dynamicCast, src);
248265

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

0 commit comments

Comments
 (0)