Skip to content

Commit 57a450b

Browse files
committed
Generate unchecked_ref_cast, not unchecked_ref_bit_cast.
This improves support for promoting to and generating unchecked_ref_cast so we no longer need unchecked_ref_bit_cast, which will just go away in the next commit. Swift SVN r32597
1 parent 9009c5e commit 57a450b

37 files changed

+416
-426
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,6 @@ class SILBuilder {
466466
return insert(new (F.getModule()) UncheckedBitwiseCastInst(Loc, Op, Ty));
467467
}
468468

469-
// Create the appropriate cast instruction based on result type.
470-
SILInstruction *createUncheckedBitCast(SILLocation Loc,
471-
SILValue Op,
472-
SILType Ty);
473-
474469
RefToBridgeObjectInst *createRefToBridgeObject(SILLocation Loc,
475470
SILValue Ref,
476471
SILValue Bits) {
@@ -1043,6 +1038,21 @@ class SILBuilder {
10431038
ProjectBoxInst(loc, valueTy, boxOperand));
10441039
}
10451040

1041+
//===--------------------------------------------------------------------===//
1042+
// Unchecked cast helpers
1043+
//===--------------------------------------------------------------------===//
1044+
1045+
// Create an UncheckedRefCast if the source and dest types are legal,
1046+
// otherwise return null.
1047+
// Unwrap or wrap optional types as needed.
1048+
SILInstruction *tryCreateUncheckedRefCast(SILLocation Loc, SILValue Op,
1049+
SILType ResultTy);
1050+
1051+
// Create the appropriate cast instruction based on result type.
1052+
SILInstruction *createUncheckedBitCast(SILLocation Loc,
1053+
SILValue Op,
1054+
SILType Ty);
1055+
10461056
//===--------------------------------------------------------------------===//
10471057
// Runtime failure
10481058
//===--------------------------------------------------------------------===//

include/swift/SIL/SILInstruction.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,12 +1527,6 @@ class UncheckedRefCastInst
15271527

15281528
UncheckedRefCastInst(SILLocation Loc, SILValue Operand, SILType Ty)
15291529
: UnaryInstructionBase(Loc, Operand, Ty) {}
1530-
1531-
public:
1532-
// Only reference cast heap objects with single pointer representation.
1533-
static bool canRefCastType(SILType Ty) {
1534-
return Ty.isHeapObjectReferenceType();
1535-
}
15361530
};
15371531

15381532
/// Converts a heap object reference to a different type without any runtime
@@ -1611,16 +1605,6 @@ class UncheckedRefBitCastInst
16111605

16121606
UncheckedRefBitCastInst(SILLocation Loc, SILValue Operand, SILType Ty)
16131607
: UnaryInstructionBase(Loc, Operand, Ty) {}
1614-
1615-
public:
1616-
// Reference bitcast from representations with single pointer low bits.
1617-
static bool canRefBitCastFromType(SILType Ty) {
1618-
return Ty.isHeapObjectReferenceType() || Ty.isClassExistentialType();
1619-
}
1620-
// Only reference bitcast to simple single pointer representations.
1621-
static bool canRefBitCastToType(SILType Ty) {
1622-
return Ty.isHeapObjectReferenceType();
1623-
}
16241608
};
16251609

16261610
/// Bitwise copy a value into another value of the same size or smaller.

include/swift/SIL/SILType.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,11 @@ class SILType {
390390
/// reflexive. `fromType` may be larger than the given type and still be
391391
/// castable. It is the caller's responsibility to ensure that the overlapping
392392
/// fields are layout compatible.
393-
static bool canUnsafeCastValue(SILType fromType, SILType toType, SILModule &M);
393+
static bool canUnsafeCastValue(SILType fromType, SILType toType,
394+
SILModule &M);
395+
396+
/// True if `operTy` can be cast by single-reference value into `resultTy`.
397+
static bool canRefCast(SILType operTy, SILType resultTy, SILModule &M);
394398

395399
/// True if the type is block-pointer-compatible, meaning it either is a block
396400
/// or is an Optional or ImplicitlyUnwrappedOptional with a block payload.
@@ -478,6 +482,17 @@ class SILType {
478482
SILType getAnyOptionalObjectType(SILModule &SILMod,
479483
OptionalTypeKind &OTK) const;
480484

485+
/// Unwraps one level of optional type.
486+
/// Returns the lowered T if the given type is Optional<T> or IUO<T>.
487+
/// Otherwise directly returns the given type.
488+
static SILType unwrapAnyOptionalType(SILType Ty, SILModule &SILMod,
489+
OptionalTypeKind &OTK) {
490+
if (auto unwrappedTy = Ty.getAnyOptionalObjectType(SILMod, OTK))
491+
return unwrappedTy;
492+
493+
return Ty;
494+
};
495+
481496
/// Classify this type as an optional type.
482497
OptionalTypeKind getOptionalTypeKind() const;
483498

lib/IRGen/IRGenSIL.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3535,14 +3535,16 @@ static void emitPointerCastInst(IRGenSILFunction &IGF,
35353535
// The input may have witness tables or other additional data, but the class
35363536
// reference is always first.
35373537
from.claimAll();
3538-
3538+
35393539
auto schema = ti.getSchema();
35403540
assert(schema.size() == 1
35413541
&& schema[0].isScalar()
35423542
&& "pointer schema is not a single scalar?!");
35433543
auto castToType = schema[0].getScalarType();
3544-
3545-
ptrValue = IGF.Builder.CreateBitCast(ptrValue, castToType);
3544+
3545+
// A retainable pointer representation may be wrapped in an optional, so we
3546+
// need to provide inttoptr/ptrtoint in addition to bitcast.
3547+
ptrValue = IGF.Builder.CreateBitOrPointerCast(ptrValue, castToType);
35463548

35473549
Explosion to;
35483550
to.add(ptrValue);

lib/SIL/SILBuilder.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ SILType SILBuilder::getPartialApplyResultType(SILType origTy, unsigned argCount,
4242
return SILType::getPrimitiveObjectType(appliedFnType);
4343
}
4444

45+
// If legal, create an unchecked_ref_cast from the given operand and result
46+
// type, otherwise return null.
47+
SILInstruction *SILBuilder::tryCreateUncheckedRefCast(SILLocation Loc,
48+
SILValue Op,
49+
SILType ResultTy) {
50+
auto &M = F.getModule();
51+
if (!SILType::canRefCast(Op.getType(), ResultTy, M))
52+
return nullptr;
53+
54+
return insert(new (M) UncheckedRefCastInst(Loc, Op, ResultTy));
55+
}
56+
4557
// Create the appropriate cast instruction based on result type.
4658
SILInstruction *SILBuilder::createUncheckedBitCast(SILLocation Loc,
4759
SILValue Op,
@@ -50,8 +62,8 @@ SILInstruction *SILBuilder::createUncheckedBitCast(SILLocation Loc,
5062
if (Ty.isTrivial(M))
5163
return insert(new (M) UncheckedTrivialBitCastInst(Loc, Op, Ty));
5264

53-
if (Op.getType().canBitCastAsSingleRef() && Ty.canBitCastAsSingleRef())
54-
return insert(new (M) UncheckedRefBitCastInst(Loc, Op, Ty));
65+
if (auto refCast = tryCreateUncheckedRefCast(Loc, Op, Ty))
66+
return refCast;
5567

5668
// The destination type is nontrivial, and may be smaller than the source
5769
// type, so RC identity cannot be assumed.

lib/SIL/SILType.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,19 @@ bool SILType::canUnsafeCastValue(SILType fromType, SILType toType,
267267
return false;
268268
}
269269

270+
// Reference cast from representations with single pointer low bits.
271+
// Only reference cast to simple single pointer representations.
272+
//
273+
// TODO: handle casting to a loadable existential by generating
274+
// init_existential_ref. Until then, only promote to a heap object dest.
275+
bool SILType::canRefCast(SILType operTy, SILType resultTy, SILModule &M) {
276+
OptionalTypeKind otk;
277+
auto fromTy = unwrapAnyOptionalType(operTy, M, otk);
278+
auto toTy = unwrapAnyOptionalType(resultTy, M, otk);
279+
return (fromTy.isHeapObjectReferenceType() || fromTy.isClassExistentialType())
280+
&& toTy.isHeapObjectReferenceType();
281+
}
282+
270283
SILType SILType::getFieldType(VarDecl *field, SILModule &M) const {
271284
assert(field->getDeclContext() == getNominalOrBoundGenericNominal());
272285
AbstractionPattern origFieldTy = M.Types.getAbstractionPattern(field);

lib/SIL/Verifier.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,14 +2145,11 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
21452145
void checkUncheckedRefCastInst(UncheckedRefCastInst *AI) {
21462146
require(AI->getOperand().getType().isObject(),
21472147
"unchecked_ref_cast operand must be a value");
2148-
require(AI->getOperand().getType().isHeapObjectReferenceType() ||
2149-
AI->getOperand().getType().isClassExistentialType(),
2150-
"unchecked_ref_cast operand must be a heap object reference or "
2151-
"class existential");
21522148
require(AI->getType().isObject(),
21532149
"unchecked_ref_cast result must be an object");
2154-
require(AI->getType().isHeapObjectReferenceType(),
2155-
"unchecked_ref_cast result must be a heap object reference");
2150+
require(SILType::canRefCast(AI->getOperand().getType(), AI->getType(),
2151+
AI->getModule()),
2152+
"unchecked_ref_cast requires a heap object reference type");
21562153
}
21572154

21582155
void checkUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *AI) {

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -506,26 +506,16 @@ emitBuiltinCastReference(SILGenFunction &gen,
506506
auto &toTL = gen.getTypeLowering(toTy);
507507
assert(!fromTL.isTrivial() && !toTL.isTrivial() && "expected ref type");
508508

509-
if (fromTL.isLoadable() || toTL.isLoadable()) {
510-
if (UncheckedRefCastInst::canRefCastType(fromTL.getLoweredType())
511-
&& UncheckedRefCastInst::canRefCastType(toTL.getLoweredType())) {
509+
if (fromTL.isLoadable() || toTL.isLoadable()) {
510+
if (auto refCast = gen.B.tryCreateUncheckedRefCast(loc, args[0].getValue(),
511+
toTL.getLoweredType())) {
512512
// Create a reference cast, forwarding the cleanup.
513513
// The cast takes the source reference.
514-
auto &in = args[0];
515-
SILValue out = gen.B.createUncheckedRefCast(loc, in.getValue(),
516-
toTL.getLoweredType());
517-
return ManagedValue(out, in.getCleanup());
518-
}
519-
if (UncheckedRefBitCastInst::canRefBitCastFromType(fromTL.getLoweredType())
520-
&& UncheckedRefBitCastInst::canRefBitCastToType(toTL.getLoweredType()))
521-
{
522-
auto &in = args[0];
523-
SILValue out = gen.B.createUncheckedRefBitCast(loc, in.getValue(),
524-
toTL.getLoweredType());
525-
return ManagedValue(out, in.getCleanup());
514+
return ManagedValue(refCast, args[0].getCleanup());
526515
}
527516
}
528-
// If casting between address-only types, cast the address.
517+
// We are either casting between address-only types, or cannot promote to a
518+
// cast of reference values.
529519
//
530520
// If the from/to types are invalid, then use a cast that will fail at
531521
// runtime. We cannot catch these errors with SIL verification because they
@@ -609,9 +599,9 @@ static ManagedValue emitBuiltinReinterpretCast(SILGenFunction &gen,
609599
SILValue out = gen.B.createUncheckedBitCast(loc, in.getValue(),
610600
toTL.getLoweredType());
611601

612-
// If the cast reduces to unchecked_ref_bit_cast, then the source and dest
602+
// If the cast reduces to unchecked_ref_cast, then the source and dest
613603
// have identical cleanup, so just forward the cleanup as an optimization.
614-
if (isa<UncheckedRefBitCastInst>(out))
604+
if (isa<UncheckedRefCastInst>(out))
615605
return ManagedValue(out, in.getCleanup());
616606

617607
// Otherwise leave the original cleanup and retain the cast value.

lib/SILGen/SILGenExpr.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,8 +2365,8 @@ RValue RValueEmitter::visitInjectIntoOptionalExpr(InjectIntoOptionalExpr *E,
23652365
if (mayLieAboutNonOptionalReturn(E->getSubExpr())) {
23662366
auto result = SGF.emitRValueAsSingleValue(E->getSubExpr());
23672367
auto optType = SGF.getLoweredLoadableType(E->getType());
2368-
SILValue bitcast = SGF.B.createUncheckedRefBitCast(E, result.getValue(),
2369-
optType);
2368+
SILValue bitcast = SGF.B.createUncheckedBitCast(E, result.getValue(),
2369+
optType);
23702370
ManagedValue bitcastMV = ManagedValue(bitcast, result.getCleanup());
23712371
return RValue(SGF, E, bitcastMV);
23722372
}
@@ -2814,9 +2814,9 @@ static bool emitOptimizedOptionalEvaluation(OptionalEvaluationExpr *E,
28142814
optTL.getLoweredType());
28152815
else
28162816
// The optional object type is the same, so we assume the optional types
2817-
// are layout identical, allowing the use of unchecked_ref_bit_cast.
2818-
result = SGF.B.createUncheckedRefBitCast(E, subMV.forward(SGF),
2819-
optTL.getLoweredType());
2817+
// are layout identical, allowing the use of unchecked bit casts.
2818+
result = SGF.B.createUncheckedBitCast(E, subMV.forward(SGF),
2819+
optTL.getLoweredType());
28202820
LoadableResult = result;
28212821
return true;
28222822
}

lib/SILGen/SILGenFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) {
459459
NSStringFromClass->getType(),
460460
SILType::getPrimitiveObjectType(OptNSStringTy),
461461
{}, metaTy);
462-
SILValue iuoptName = B.createUncheckedRefBitCast(mainClass, optName,
462+
SILValue iuoptName = B.createUncheckedBitCast(mainClass, optName,
463463
SILType::getPrimitiveObjectType(IUOptNSStringTy));
464464

465465
// Call UIApplicationMain.

0 commit comments

Comments
 (0)