Skip to content

Commit 70a6b35

Browse files
authored
Merge pull request #18909 from gottesmm/pr-8e73798ca4b3595b91b338743b446c1af0afbc96
[silgen] Eliminate last use of emitCheckedCastBranchOld and delete de…
2 parents c3b1143 + 4030d40 commit 70a6b35

File tree

6 files changed

+183
-277
lines changed

6 files changed

+183
-277
lines changed

lib/SILGen/SILGenDynamicCast.cpp

Lines changed: 23 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ namespace {
155155
if (operandValue.getType().isAddress()) {
156156
operandValue = SGF.B.createLoadTake(Loc, operandValue);
157157
}
158+
159+
// If we are not supposed to destroy this value on failure, then we need
160+
// to borrow it.
161+
if (!shouldDestroyOnFailure(consumption)) {
162+
operandValue = operandValue.borrow(SGF, Loc);
163+
}
158164
SGF.B.createCheckedCastBranch(Loc, /*exact*/ false, operandValue,
159165
origTargetTL.getLoweredType(), trueBB,
160166
falseBB, TrueCount, FalseCount);
@@ -171,8 +177,16 @@ namespace {
171177
result = finishFromResultBuffer(hasAbstraction, resultBuffer,
172178
abstraction, origTargetTL, ctx);
173179
} else {
174-
ManagedValue argument =
175-
SGF.B.createOwnedPhiArgument(origTargetTL.getLoweredType());
180+
// If we had copy_on_success, then we need to use a guaranteed
181+
// argument.
182+
ManagedValue argument;
183+
if (!shouldTakeOnSuccess(consumption)) {
184+
argument = SGF.B.createGuaranteedPhiArgument(
185+
origTargetTL.getLoweredType());
186+
} else {
187+
argument =
188+
SGF.B.createOwnedPhiArgument(origTargetTL.getLoweredType());
189+
}
176190
result = finishFromResultScalar(hasAbstraction, argument, consumption,
177191
abstraction, origTargetTL, ctx);
178192
}
@@ -215,7 +229,13 @@ namespace {
215229
return;
216230
}
217231

218-
handleFalse(SGF.B.createOwnedPhiArgument(operandValue.getType()));
232+
if (consumption == CastConsumptionKind::CopyOnSuccess) {
233+
SGF.B.createGuaranteedPhiArgument(operandValue.getType());
234+
handleFalse(None);
235+
} else {
236+
handleFalse(SGF.B.createOwnedPhiArgument(operandValue.getType()));
237+
}
238+
219239
assert(!SGF.B.hasValidInsertionPoint() && "handler did not end block");
220240
}
221241
}
@@ -306,225 +326,6 @@ void SILGenFunction::emitCheckedCastBranch(
306326
ctx, handleTrue, handleFalse, TrueCount, FalseCount);
307327
}
308328

309-
namespace {
310-
class CheckedCastEmitterOld {
311-
SILGenFunction &SGF;
312-
SILLocation Loc;
313-
CanType SourceType;
314-
CanType TargetType;
315-
316-
enum class CastStrategy : uint8_t {
317-
Address,
318-
Scalar,
319-
};
320-
CastStrategy Strategy;
321-
322-
public:
323-
CheckedCastEmitterOld(SILGenFunction &SGF, SILLocation loc, Type sourceType,
324-
Type targetType)
325-
: SGF(SGF), Loc(loc), SourceType(sourceType->getCanonicalType()),
326-
TargetType(targetType->getCanonicalType()),
327-
Strategy(computeStrategy()) {}
328-
329-
bool isOperandIndirect() const { return Strategy == CastStrategy::Address; }
330-
331-
RValue emitUnconditionalCast(ManagedValue operand, SGFContext ctx) {
332-
// The cast functions don't know how to work with anything but
333-
// the most general possible abstraction level.
334-
AbstractionPattern abstraction =
335-
SGF.SGM.Types.getMostGeneralAbstraction();
336-
auto &origTargetTL = SGF.getTypeLowering(abstraction, TargetType);
337-
auto &substTargetTL = SGF.getTypeLowering(TargetType);
338-
bool hasAbstraction =
339-
(origTargetTL.getLoweredType() != substTargetTL.getLoweredType());
340-
341-
// If we're using checked_cast_addr, take the operand (which
342-
// should be an address) and build into the destination buffer.
343-
if (Strategy == CastStrategy::Address &&
344-
SGF.silConv.useLoweredAddresses()) {
345-
SILValue resultBuffer =
346-
createAbstractResultBuffer(hasAbstraction, origTargetTL, ctx);
347-
SGF.B.createUnconditionalCheckedCastAddr(
348-
Loc, operand.forward(SGF), SourceType, resultBuffer, TargetType);
349-
return RValue(SGF, Loc, TargetType,
350-
finishFromResultBuffer(hasAbstraction, resultBuffer,
351-
abstraction, origTargetTL, ctx));
352-
}
353-
354-
SILValue resultScalar;
355-
if (Strategy == CastStrategy::Address) {
356-
resultScalar = SGF.B.createUnconditionalCheckedCastValue(
357-
Loc, operand.forward(SGF), origTargetTL.getLoweredType());
358-
} else {
359-
resultScalar = SGF.B.createUnconditionalCheckedCast(
360-
Loc, operand.forward(SGF), origTargetTL.getLoweredType());
361-
}
362-
363-
return RValue(SGF, Loc, TargetType,
364-
finishFromResultScalar(hasAbstraction, resultScalar,
365-
CastConsumptionKind::TakeAlways,
366-
abstraction, origTargetTL, ctx));
367-
}
368-
369-
/// Emit a conditional cast.
370-
void emitConditional(ManagedValue operand, CastConsumptionKind consumption,
371-
SGFContext ctx,
372-
llvm::function_ref<void(ManagedValue)> handleTrue,
373-
llvm::function_ref<void()> handleFalse,
374-
ProfileCounter TrueCount = ProfileCounter(),
375-
ProfileCounter FalseCount = ProfileCounter()) {
376-
// The cast instructions don't know how to work with anything
377-
// but the most general possible abstraction level.
378-
AbstractionPattern abstraction = SGF.SGM.Types.getMostGeneralAbstraction();
379-
auto &origTargetTL = SGF.getTypeLowering(abstraction, TargetType);
380-
auto &substTargetTL = SGF.getTypeLowering(TargetType);
381-
bool hasAbstraction =
382-
(origTargetTL.getLoweredType() != substTargetTL.getLoweredType());
383-
384-
SILBasicBlock *falseBB = SGF.B.splitBlockForFallthrough();
385-
SILBasicBlock *trueBB = SGF.B.splitBlockForFallthrough();
386-
387-
// Emit the branch.
388-
SILValue scalarOperandValue;
389-
SILValue resultBuffer;
390-
if (Strategy == CastStrategy::Address) {
391-
assert(operand.getType().isAddress());
392-
resultBuffer =
393-
createAbstractResultBuffer(hasAbstraction, origTargetTL, ctx);
394-
SGF.B.createCheckedCastAddrBranch(
395-
Loc, consumption, operand.forward(SGF), SourceType, resultBuffer,
396-
TargetType, trueBB, falseBB, TrueCount, FalseCount);
397-
} else {
398-
// Tolerate being passed an address here. It comes up during switch
399-
//emission.
400-
scalarOperandValue = operand.forward(SGF);
401-
if (scalarOperandValue->getType().isAddress()) {
402-
scalarOperandValue = SGF.B.emitLoadValueOperation(
403-
Loc, scalarOperandValue, LoadOwnershipQualifier::Take);
404-
}
405-
SGF.B.createCheckedCastBranch(Loc, /*exact*/ false, scalarOperandValue,
406-
origTargetTL.getLoweredType(), trueBB,
407-
falseBB, TrueCount, FalseCount);
408-
}
409-
410-
// Emit the success block.
411-
SGF.B.setInsertionPoint(trueBB);
412-
{
413-
FullExpr scope(SGF.Cleanups, CleanupLocation::get(Loc));
414-
415-
ManagedValue result;
416-
if (Strategy == CastStrategy::Address) {
417-
result = finishFromResultBuffer(hasAbstraction, resultBuffer,
418-
abstraction, origTargetTL, ctx);
419-
} else {
420-
SILValue argument = trueBB->createPhiArgument(
421-
origTargetTL.getLoweredType(), ValueOwnershipKind::Owned);
422-
result = finishFromResultScalar(hasAbstraction, argument, consumption,
423-
abstraction, origTargetTL, ctx);
424-
}
425-
426-
handleTrue(result);
427-
assert(!SGF.B.hasValidInsertionPoint() && "handler did not end block");
428-
}
429-
430-
// Emit the failure block.
431-
SGF.B.setInsertionPoint(falseBB);
432-
{
433-
FullExpr scope(SGF.Cleanups, CleanupLocation::get(Loc));
434-
435-
// If we're using the scalar strategy, handle the consumption rules.
436-
if (Strategy != CastStrategy::Address &&
437-
shouldDestroyOnFailure(consumption)) {
438-
SGF.B.emitDestroyValueOperation(Loc, scalarOperandValue);
439-
}
440-
441-
handleFalse();
442-
assert(!SGF.B.hasValidInsertionPoint() && "handler did not end block");
443-
}
444-
}
445-
446-
SILValue createAbstractResultBuffer(bool hasAbstraction,
447-
const TypeLowering &origTargetTL,
448-
SGFContext ctx) {
449-
// Note that the conditions here must exactly match the criteria in
450-
// finishFromResultBuffer.
451-
if (!hasAbstraction) {
452-
if (auto address = ctx.getAddressForInPlaceInitialization(SGF, Loc))
453-
return address;
454-
}
455-
456-
return SGF.emitTemporaryAllocation(Loc, origTargetTL.getLoweredType());
457-
}
458-
459-
ManagedValue finishFromResultBuffer(bool hasAbstraction,
460-
SILValue buffer,
461-
AbstractionPattern abstraction,
462-
const TypeLowering &origTargetTL,
463-
SGFContext ctx) {
464-
// Note that the conditions here must exactly match the criteria in
465-
// createAbstractResultBuffer.
466-
if (!hasAbstraction) {
467-
if (ctx.finishInPlaceInitialization(SGF))
468-
return ManagedValue::forInContext();
469-
}
470-
471-
ManagedValue result;
472-
if (!origTargetTL.isAddressOnly()) {
473-
result = SGF.emitLoad(Loc, buffer, origTargetTL, ctx, IsTake);
474-
} else {
475-
result = SGF.emitManagedBufferWithCleanup(buffer, origTargetTL);
476-
}
477-
478-
if (hasAbstraction) {
479-
result = SGF.emitOrigToSubstValue(Loc, result, abstraction,
480-
TargetType, ctx);
481-
}
482-
return result;
483-
}
484-
485-
/// Our cast succeeded and gave us this abstracted value.
486-
ManagedValue finishFromResultScalar(bool hasAbstraction, SILValue value,
487-
CastConsumptionKind consumption,
488-
AbstractionPattern abstraction,
489-
const TypeLowering &origTargetTL,
490-
SGFContext ctx) {
491-
// Retain the result if this is copy-on-success.
492-
if (!shouldTakeOnSuccess(consumption))
493-
value = origTargetTL.emitCopyValue(SGF.B, Loc, value);
494-
495-
// Enter a cleanup for the +1 result.
496-
ManagedValue result
497-
= SGF.emitManagedRValueWithCleanup(value, origTargetTL);
498-
499-
// Re-abstract if necessary.
500-
if (hasAbstraction) {
501-
result = SGF.emitOrigToSubstValue(Loc, result, abstraction,
502-
TargetType, ctx);
503-
}
504-
return result;
505-
}
506-
507-
private:
508-
CastStrategy computeStrategy() const {
509-
if (canUseScalarCheckedCastInstructions(SGF.SGM.M,
510-
SourceType, TargetType))
511-
return CastStrategy::Scalar;
512-
return CastStrategy::Address;
513-
}
514-
};
515-
} // end anonymous namespace
516-
517-
void SILGenFunction::emitCheckedCastBranchOld(
518-
SILLocation loc, ConsumableManagedValue src, Type sourceType,
519-
CanType targetType, SGFContext ctx,
520-
llvm::function_ref<void(ManagedValue)> handleTrue,
521-
llvm::function_ref<void()> handleFalse, ProfileCounter TrueCount,
522-
ProfileCounter FalseCount) {
523-
CheckedCastEmitterOld emitter(*this, loc, sourceType, targetType);
524-
emitter.emitConditional(src.getFinalManagedValue(), src.getFinalConsumption(),
525-
ctx, handleTrue, handleFalse, TrueCount, FalseCount);
526-
}
527-
528329
/// Emit a collection downcast expression.
529330
///
530331
/// \param conditional Whether to emit a conditional downcast; if

lib/SILGen/SILGenFunction.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,20 +1593,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
15931593
ProfileCounter TrueCount = ProfileCounter(),
15941594
ProfileCounter FalseCount = ProfileCounter());
15951595

1596-
/// A form of checked cast branch that uses the old non-ownership preserving
1597-
/// semantics.
1598-
///
1599-
/// The main difference is that this code does not pass the old argument as a
1600-
/// block argument in the failure case. This causes values to be double
1601-
/// consumed.
1602-
void
1603-
emitCheckedCastBranchOld(SILLocation loc, ConsumableManagedValue src,
1604-
Type sourceType, CanType targetType, SGFContext ctx,
1605-
llvm::function_ref<void(ManagedValue)> handleTrue,
1606-
llvm::function_ref<void()> handleFalse,
1607-
ProfileCounter TrueCount = ProfileCounter(),
1608-
ProfileCounter FalseCount = ProfileCounter());
1609-
16101596
/// Emit the control flow for an optional 'bind' operation, branching to the
16111597
/// active failure destination if the optional value addressed by optionalAddr
16121598
/// is nil, and leaving the insertion point on the success branch.

lib/SILGen/SILGenPattern.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,7 +1594,7 @@ void PatternMatchEmission::emitIsDispatch(ArrayRef<RowToSpecialize> rows,
15941594
innerFailure = &specializedFailure;
15951595

15961596
// Perform a conditional cast branch.
1597-
SGF.emitCheckedCastBranchOld(
1597+
SGF.emitCheckedCastBranch(
15981598
loc, castOperand, sourceType, targetType, SGFContext(),
15991599
// Success block: recurse.
16001600
[&](ManagedValue castValue) {
@@ -1603,7 +1603,7 @@ void PatternMatchEmission::emitIsDispatch(ArrayRef<RowToSpecialize> rows,
16031603
assert(!SGF.B.hasValidInsertionPoint() && "did not end block");
16041604
},
16051605
// Failure block: branch out to the continuation block.
1606-
[&] { (*innerFailure)(loc); }, rows[0].Count);
1606+
[&](Optional<ManagedValue> mv) { (*innerFailure)(loc); }, rows[0].Count);
16071607
}
16081608

16091609
namespace {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===--- checked_cast_test.swift ------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// RUN: %target-run-simple-swift
14+
// REQUIRES: executable_test
15+
16+
// Test that we emit proper ARC here and do not crash.
17+
18+
private class Foo {
19+
init() {}
20+
}
21+
22+
final private class Bar : Foo {
23+
}
24+
25+
final private class Baz : Foo {
26+
}
27+
28+
private func checked_cast_default(_ f: Foo) -> Int {
29+
switch f {
30+
case is Bar:
31+
return 0
32+
case is Baz:
33+
return 1
34+
default:
35+
return 2
36+
}
37+
}
38+
39+
private func checked_cast_exhaustive(_ f: Foo) -> Int {
40+
switch f {
41+
case is Bar:
42+
return 0
43+
case is Baz:
44+
return 1
45+
case is Foo:
46+
return 2
47+
}
48+
}
49+
50+
func main() {
51+
let b = Baz()
52+
let x = checked_cast_default(b)
53+
precondition(x == 1)
54+
let y = checked_cast_exhaustive(b)
55+
precondition(y == 1)
56+
}
57+
58+
main()

0 commit comments

Comments
 (0)