mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
534 lines
21 KiB
C++
534 lines
21 KiB
C++
//===--- SILCombinerCastVisitors.cpp --------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "sil-combine"
|
|
#include "SILCombiner.h"
|
|
#include "swift/SIL/DynamicCasts.h"
|
|
#include "swift/SIL/PatternMatch.h"
|
|
#include "swift/SIL/SILBuilder.h"
|
|
#include "swift/SIL/SILVisitor.h"
|
|
#include "swift/SIL/DebugUtils.h"
|
|
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
|
|
#include "swift/SILOptimizer/Analysis/ARCAnalysis.h"
|
|
#include "swift/SILOptimizer/Analysis/CFG.h"
|
|
#include "swift/SILOptimizer/Analysis/ValueTracking.h"
|
|
#include "swift/SILOptimizer/Utils/Local.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::PatternMatch;
|
|
|
|
SILInstruction *
|
|
SILCombiner::visitRefToRawPointerInst(RefToRawPointerInst *RRPI) {
|
|
// Ref to raw pointer consumption of other ref casts.
|
|
if (auto *URCI = dyn_cast<UncheckedRefCastInst>(RRPI->getOperand())) {
|
|
// (ref_to_raw_pointer (unchecked_ref_cast x))
|
|
// -> (ref_to_raw_pointer x)
|
|
if (URCI->getOperand()->getType().isAnyClassReferenceType()) {
|
|
RRPI->setOperand(URCI->getOperand());
|
|
return URCI->use_empty() ? eraseInstFromFunction(*URCI) : nullptr;
|
|
}
|
|
// (ref_to_raw_pointer (unchecked_ref_cast x))
|
|
// -> (unchecked_trivial_bit_cast x)
|
|
return Builder.createUncheckedTrivialBitCast(RRPI->getLoc(),
|
|
URCI->getOperand(),
|
|
RRPI->getType());
|
|
}
|
|
|
|
// (ref_to_raw_pointer (open_existential_ref (init_existential_ref x))) ->
|
|
// (ref_to_raw_pointer x)
|
|
if (auto *OER = dyn_cast<OpenExistentialRefInst>(RRPI->getOperand()))
|
|
if (auto *IER = dyn_cast<InitExistentialRefInst>(OER->getOperand()))
|
|
return Builder.createRefToRawPointer(RRPI->getLoc(), IER->getOperand(),
|
|
RRPI->getType());
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *SILCombiner::visitUpcastInst(UpcastInst *UCI) {
|
|
// Ref to raw pointer consumption of other ref casts.
|
|
//
|
|
// (upcast (upcast x)) -> (upcast x)
|
|
if (auto *Op = dyn_cast<UpcastInst>(UCI->getOperand())) {
|
|
UCI->setOperand(Op->getOperand());
|
|
return Op->use_empty() ? eraseInstFromFunction(*Op) : nullptr;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::
|
|
visitPointerToAddressInst(PointerToAddressInst *PTAI) {
|
|
Builder.setCurrentDebugScope(PTAI->getDebugScope());
|
|
|
|
// If we reach this point, we know that the types must be different since
|
|
// otherwise simplifyInstruction would have handled the identity case. This is
|
|
// always legal to do since address-to-pointer pointer-to-address implies
|
|
// layout compatibility.
|
|
//
|
|
// (pointer-to-address strict (address-to-pointer %x))
|
|
// -> (unchecked_addr_cast %x)
|
|
if (PTAI->isStrict()) {
|
|
if (auto *ATPI = dyn_cast<AddressToPointerInst>(PTAI->getOperand())) {
|
|
return Builder.createUncheckedAddrCast(PTAI->getLoc(), ATPI->getOperand(),
|
|
PTAI->getType());
|
|
}
|
|
}
|
|
// Turn this also into an index_addr. We generate this pattern after switching
|
|
// the Word type to an explicit Int32 or Int64 in the stdlib.
|
|
//
|
|
// %101 = builtin "strideof"<Int>(%84 : $@thick Int.Type) :
|
|
// $Builtin.Word
|
|
// %102 = builtin "zextOrBitCast_Word_Int64"(%101 : $Builtin.Word) :
|
|
// $Builtin.Int64
|
|
// %111 = builtin "smul_with_overflow_Int64"(%108 : $Builtin.Int64,
|
|
// %102 : $Builtin.Int64, %20 : $Builtin.Int1) :
|
|
// $(Builtin.Int64, Builtin.Int1)
|
|
// %112 = tuple_extract %111 : $(Builtin.Int64, Builtin.Int1), 0
|
|
// %113 = builtin "truncOrBitCast_Int64_Word"(%112 : $Builtin.Int64) :
|
|
// $Builtin.Word
|
|
// %114 = index_raw_pointer %100 : $Builtin.RawPointer, %113 : $Builtin.Word
|
|
// %115 = pointer_to_address %114 : $Builtin.RawPointer to [strict] $*Int
|
|
SILValue Distance;
|
|
SILValue TruncOrBitCast;
|
|
MetatypeInst *Metatype;
|
|
IndexRawPointerInst *IndexRawPtr;
|
|
BuiltinInst *StrideMul;
|
|
if (match(
|
|
PTAI->getOperand(),
|
|
m_IndexRawPointerInst(IndexRawPtr))) {
|
|
SILValue Ptr = IndexRawPtr->getOperand(0);
|
|
SILValue TruncOrBitCast = IndexRawPtr->getOperand(1);
|
|
if (match(TruncOrBitCast,
|
|
m_ApplyInst(BuiltinValueKind::TruncOrBitCast,
|
|
m_TupleExtractInst(m_BuiltinInst(StrideMul), 0)))) {
|
|
if (match(StrideMul,
|
|
m_ApplyInst(
|
|
BuiltinValueKind::SMulOver, m_SILValue(Distance),
|
|
m_ApplyInst(BuiltinValueKind::ZExtOrBitCast,
|
|
m_ApplyInst(BuiltinValueKind::Strideof,
|
|
m_MetatypeInst(Metatype))))) ||
|
|
match(StrideMul,
|
|
m_ApplyInst(
|
|
BuiltinValueKind::SMulOver,
|
|
m_ApplyInst(BuiltinValueKind::ZExtOrBitCast,
|
|
m_ApplyInst(BuiltinValueKind::Strideof,
|
|
m_MetatypeInst(Metatype))),
|
|
m_SILValue(Distance)))) {
|
|
SILType InstanceType =
|
|
Metatype->getType().getMetatypeInstanceType(PTAI->getModule());
|
|
auto *Trunc = cast<BuiltinInst>(TruncOrBitCast);
|
|
|
|
// Make sure that the type of the metatype matches the type that we are
|
|
// casting to so we stride by the correct amount.
|
|
if (InstanceType.getAddressType() != PTAI->getType()) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto *NewPTAI = Builder.createPointerToAddress(PTAI->getLoc(), Ptr,
|
|
PTAI->getType(),
|
|
PTAI->isStrict(),
|
|
PTAI->isInvariant());
|
|
auto DistanceAsWord = Builder.createBuiltin(
|
|
PTAI->getLoc(), Trunc->getName(), Trunc->getType(), {}, Distance);
|
|
|
|
return Builder.createIndexAddr(PTAI->getLoc(), NewPTAI, DistanceAsWord);
|
|
}
|
|
}
|
|
}
|
|
// Turn:
|
|
//
|
|
// %stride = Builtin.strideof(T) * %distance
|
|
// %ptr' = index_raw_pointer %ptr, %stride
|
|
// %result = pointer_to_address %ptr, [strict] $T'
|
|
//
|
|
// To:
|
|
//
|
|
// %addr = pointer_to_address %ptr, [strict] $T
|
|
// %result = index_addr %addr, %distance
|
|
//
|
|
BuiltinInst *Bytes;
|
|
if (match(PTAI->getOperand(),
|
|
m_IndexRawPointerInst(m_ValueBase(),
|
|
m_TupleExtractInst(m_BuiltinInst(Bytes),
|
|
0)))) {
|
|
if (match(Bytes, m_ApplyInst(BuiltinValueKind::SMulOver, m_ValueBase(),
|
|
m_ApplyInst(BuiltinValueKind::Strideof,
|
|
m_MetatypeInst(Metatype)),
|
|
m_ValueBase()))) {
|
|
SILType InstanceType =
|
|
Metatype->getType().getMetatypeInstanceType(PTAI->getModule());
|
|
|
|
// Make sure that the type of the metatype matches the type that we are
|
|
// casting to so we stride by the correct amount.
|
|
if (InstanceType.getAddressType() != PTAI->getType())
|
|
return nullptr;
|
|
|
|
auto IRPI = cast<IndexRawPointerInst>(PTAI->getOperand());
|
|
SILValue Ptr = IRPI->getOperand(0);
|
|
SILValue Distance = Bytes->getArguments()[0];
|
|
auto *NewPTAI =
|
|
Builder.createPointerToAddress(PTAI->getLoc(), Ptr, PTAI->getType(),
|
|
PTAI->isStrict(), PTAI->isInvariant());
|
|
return Builder.createIndexAddr(PTAI->getLoc(), NewPTAI, Distance);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI) {
|
|
Builder.setCurrentDebugScope(UADCI->getDebugScope());
|
|
SILModule &Mod = UADCI->getModule();
|
|
|
|
// (unchecked-addr-cast (unchecked-addr-cast x X->Y) Y->Z)
|
|
// ->
|
|
// (unchecked-addr-cast x X->Z)
|
|
if (auto *OtherUADCI = dyn_cast<UncheckedAddrCastInst>(UADCI->getOperand()))
|
|
return Builder.createUncheckedAddrCast(UADCI->getLoc(),
|
|
OtherUADCI->getOperand(),
|
|
UADCI->getType());
|
|
|
|
// (unchecked-addr-cast cls->superclass) -> (upcast cls->superclass)
|
|
if (UADCI->getType() != UADCI->getOperand()->getType() &&
|
|
UADCI->getType().isExactSuperclassOf(UADCI->getOperand()->getType()))
|
|
return Builder.createUpcast(UADCI->getLoc(), UADCI->getOperand(),
|
|
UADCI->getType());
|
|
|
|
// See if we have all loads from this unchecked_addr_cast. If we do, load the
|
|
// original type and create the appropriate bitcast.
|
|
|
|
// First if our UADCI has not users, bail. This will be eliminated by DCE.
|
|
if (UADCI->use_empty())
|
|
return nullptr;
|
|
|
|
SILType InputTy = UADCI->getOperand()->getType();
|
|
SILType OutputTy = UADCI->getType();
|
|
|
|
// If either type is address only, do not do anything here.
|
|
if (InputTy.isAddressOnly(Mod) || OutputTy.isAddressOnly(Mod))
|
|
return nullptr;
|
|
|
|
bool InputIsTrivial = InputTy.isTrivial(Mod);
|
|
bool OutputIsTrivial = OutputTy.isTrivial(Mod);
|
|
|
|
// If our input is trivial and our output type is not, do not do
|
|
// anything. This is to ensure that we do not change any types reference
|
|
// semantics from trivial -> reference counted.
|
|
if (InputIsTrivial && !OutputIsTrivial)
|
|
return nullptr;
|
|
|
|
// Check that the input type can be value cast to the output type. It is
|
|
// possible to cast the address of a smaller InputType to the address of a
|
|
// larger OutputType (the actual memory object must be large enough to hold
|
|
// both types). However, such address casts cannot be converted to value
|
|
// casts.
|
|
if (!SILType::canUnsafeCastValue(InputTy, OutputTy, UADCI->getModule()))
|
|
return nullptr;
|
|
|
|
// For each user U of the unchecked_addr_cast...
|
|
for (auto U : getNonDebugUses(UADCI))
|
|
// Check if it is load. If it is not a load, bail...
|
|
if (!isa<LoadInst>(U->getUser()))
|
|
return nullptr;
|
|
|
|
SILValue Op = UADCI->getOperand();
|
|
SILLocation Loc = UADCI->getLoc();
|
|
|
|
// Ok, we have all loads. Lets simplify this. Go back through the loads a
|
|
// second time, rewriting them into a load + bitcast from our source.
|
|
auto UsesRange = getNonDebugUses(UADCI);
|
|
for (auto UI = UsesRange.begin(), E = UsesRange.end(); UI != E;) {
|
|
// Grab the original load.
|
|
LoadInst *L = cast<LoadInst>(UI->getUser());
|
|
UI++;
|
|
|
|
// Insert a new load from our source and bitcast that as appropriate.
|
|
LoadInst *NewLoad =
|
|
Builder.createLoad(Loc, Op, LoadOwnershipQualifier::Unqualified);
|
|
auto *BitCast = Builder.createUncheckedBitCast(Loc, NewLoad,
|
|
OutputTy.getObjectType());
|
|
// Replace all uses of the old load with the new bitcasted result and erase
|
|
// the old load.
|
|
replaceInstUsesWith(*L, BitCast);
|
|
eraseInstFromFunction(*L);
|
|
}
|
|
|
|
// Delete the old cast.
|
|
return eraseInstFromFunction(*UADCI);
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::visitUncheckedRefCastInst(UncheckedRefCastInst *URCI) {
|
|
// (unchecked-ref-cast (unchecked-ref-cast x X->Y) Y->Z)
|
|
// ->
|
|
// (unchecked-ref-cast x X->Z)
|
|
if (auto *OtherURCI = dyn_cast<UncheckedRefCastInst>(URCI->getOperand()))
|
|
return Builder.createUncheckedRefCast(URCI->getLoc(),
|
|
OtherURCI->getOperand(),
|
|
URCI->getType());
|
|
|
|
// (unchecked_ref_cast (upcast x X->Y) Y->Z) -> (unchecked_ref_cast x X->Z)
|
|
if (auto *UI = dyn_cast<UpcastInst>(URCI->getOperand()))
|
|
return Builder.createUncheckedRefCast(URCI->getLoc(),
|
|
UI->getOperand(),
|
|
URCI->getType());
|
|
|
|
if (URCI->getType() != URCI->getOperand()->getType() &&
|
|
URCI->getType().isExactSuperclassOf(URCI->getOperand()->getType()))
|
|
return Builder.createUpcast(URCI->getLoc(), URCI->getOperand(),
|
|
URCI->getType());
|
|
|
|
// (unchecked_ref_cast (open_existential_ref (init_existential_ref X))) ->
|
|
// (unchecked_ref_cast X)
|
|
if (auto *OER = dyn_cast<OpenExistentialRefInst>(URCI->getOperand()))
|
|
if (auto *IER = dyn_cast<InitExistentialRefInst>(OER->getOperand()))
|
|
return Builder.createUncheckedRefCast(URCI->getLoc(), IER->getOperand(),
|
|
URCI->getType());
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *URCI) {
|
|
SILType SrcTy = URCI->getSrc()->getType();
|
|
if (!SrcTy.isLoadable(URCI->getModule()))
|
|
return nullptr;
|
|
|
|
SILType DestTy = URCI->getDest()->getType();
|
|
if (!DestTy.isLoadable(URCI->getModule()))
|
|
return nullptr;
|
|
|
|
// After promoting unchecked_ref_cast_addr to unchecked_ref_cast, the SIL
|
|
// verifier will assert that the loadable source and dest type of reference
|
|
// castable. If the static types are invalid, simply avoid promotion, that way
|
|
// the runtime will then report a failure if this cast is ever executed.
|
|
if (!SILType::canRefCast(SrcTy.getObjectType(), DestTy.getObjectType(),
|
|
URCI->getModule()))
|
|
return nullptr;
|
|
|
|
SILLocation Loc = URCI->getLoc();
|
|
Builder.setCurrentDebugScope(URCI->getDebugScope());
|
|
LoadInst *load = Builder.createLoad(Loc, URCI->getSrc(),
|
|
LoadOwnershipQualifier::Unqualified);
|
|
auto *cast = Builder.tryCreateUncheckedRefCast(Loc, load,
|
|
DestTy.getObjectType());
|
|
assert(cast && "SILBuilder cannot handle reference-castable types");
|
|
Builder.createStore(Loc, cast, URCI->getDest(),
|
|
StoreOwnershipQualifier::Unqualified);
|
|
|
|
return eraseInstFromFunction(*URCI);
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::
|
|
visitUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *UCCAI) {
|
|
CastOpt.optimizeUnconditionalCheckedCastAddrInst(UCCAI);
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::
|
|
visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *UCCI) {
|
|
if (CastOpt.optimizeUnconditionalCheckedCastInst(UCCI))
|
|
return nullptr;
|
|
|
|
// FIXME: rename from RemoveCondFails to RemoveRuntimeAsserts.
|
|
if (RemoveCondFails) {
|
|
auto LoweredTargetType = UCCI->getType();
|
|
auto Loc = UCCI->getLoc();
|
|
auto Op = UCCI->getOperand();
|
|
if (LoweredTargetType.isAddress()) {
|
|
// unconditional_checked_cast -> unchecked_addr_cast
|
|
return Builder.createUncheckedAddrCast(Loc, Op, LoweredTargetType);
|
|
} else if (LoweredTargetType.isHeapObjectReferenceType()) {
|
|
if (!(Op->getType().isHeapObjectReferenceType() ||
|
|
Op->getType().isClassExistentialType())) {
|
|
return nullptr;
|
|
}
|
|
// unconditional_checked_cast -> unchecked_ref_cast
|
|
return Builder.createUncheckedRefCast(Loc, Op, LoweredTargetType);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::
|
|
visitRawPointerToRefInst(RawPointerToRefInst *RawToRef) {
|
|
// (raw_pointer_to_ref (ref_to_raw_pointer x X->Y) Y->Z)
|
|
// ->
|
|
// (unchecked_ref_cast X->Z)
|
|
if (auto *RefToRaw = dyn_cast<RefToRawPointerInst>(RawToRef->getOperand())) {
|
|
return Builder.createUncheckedRefCast(RawToRef->getLoc(),
|
|
RefToRaw->getOperand(),
|
|
RawToRef->getType());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::
|
|
visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *UTBCI) {
|
|
// (unchecked_trivial_bit_cast Y->Z
|
|
// (unchecked_trivial_bit_cast X->Y x))
|
|
// ->
|
|
// (unchecked_trivial_bit_cast X->Z x)
|
|
SILValue Op = UTBCI->getOperand();
|
|
if (auto *OtherUTBCI = dyn_cast<UncheckedTrivialBitCastInst>(Op)) {
|
|
return Builder.createUncheckedTrivialBitCast(UTBCI->getLoc(),
|
|
OtherUTBCI->getOperand(),
|
|
UTBCI->getType());
|
|
}
|
|
|
|
// (unchecked_trivial_bit_cast Y->Z
|
|
// (unchecked_ref_cast X->Y x))
|
|
// ->
|
|
// (unchecked_trivial_bit_cast X->Z x)
|
|
if (auto *URBCI = dyn_cast<UncheckedRefCastInst>(Op)) {
|
|
return Builder.createUncheckedTrivialBitCast(UTBCI->getLoc(),
|
|
URBCI->getOperand(),
|
|
UTBCI->getType());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::
|
|
visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI) {
|
|
// (unchecked_bitwise_cast Y->Z (unchecked_bitwise_cast X->Y x))
|
|
// OR (unchecked_trivial_cast Y->Z (unchecked_bitwise_cast X->Y x))
|
|
// ->
|
|
// (unchecked_bitwise_cast X->Z x)
|
|
SILValue Oper;
|
|
if (match(UBCI->getOperand(),
|
|
m_CombineOr(m_UncheckedBitwiseCastInst(m_SILValue(Oper)),
|
|
m_UncheckedTrivialBitCastInst(m_SILValue(Oper))))) {
|
|
return Builder.createUncheckedBitwiseCast(UBCI->getLoc(), Oper,
|
|
UBCI->getType());
|
|
}
|
|
if (UBCI->getType().isTrivial(UBCI->getModule()))
|
|
return Builder.createUncheckedTrivialBitCast(UBCI->getLoc(),
|
|
UBCI->getOperand(),
|
|
UBCI->getType());
|
|
|
|
if (auto refCast = Builder.tryCreateUncheckedRefCast(
|
|
UBCI->getLoc(), UBCI->getOperand(), UBCI->getType()))
|
|
return refCast;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
/// Helper function for simplifying conversions between
|
|
/// thick and objc metatypes.
|
|
static SILInstruction *
|
|
visitMetatypeConversionInst(SILBuilder &Builder, ConversionInst *MCI,
|
|
MetatypeRepresentation Representation) {
|
|
SILValue Op = MCI->getOperand(0);
|
|
// Instruction has a proper target type already.
|
|
SILType Ty = MCI->getType();
|
|
auto MetatypeTy = Op->getType().getAs<AnyMetatypeType>();
|
|
|
|
if (MetatypeTy->getRepresentation() != Representation)
|
|
return nullptr;
|
|
|
|
if (isa<MetatypeInst>(Op))
|
|
return Builder.createMetatype(MCI->getLoc(), Ty);
|
|
|
|
if (auto *VMI = dyn_cast<ValueMetatypeInst>(Op))
|
|
return Builder.createValueMetatype(MCI->getLoc(), Ty, VMI->getOperand());
|
|
|
|
if (auto *EMI = dyn_cast<ExistentialMetatypeInst>(Op))
|
|
return Builder.createExistentialMetatype(MCI->getLoc(), Ty,
|
|
EMI->getOperand());
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *TTOCMI) {
|
|
// Perform the following transformations:
|
|
// (thick_to_objc_metatype (metatype @thick)) ->
|
|
// (metatype @objc_metatype)
|
|
//
|
|
// (thick_to_objc_metatype (value_metatype @thick)) ->
|
|
// (value_metatype @objc_metatype)
|
|
//
|
|
// (thick_to_objc_metatype (existential_metatype @thick)) ->
|
|
// (existential_metatype @objc_metatype)
|
|
return visitMetatypeConversionInst(Builder, TTOCMI,
|
|
MetatypeRepresentation::Thick);
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::visitObjCToThickMetatypeInst(ObjCToThickMetatypeInst *OCTTMI) {
|
|
// Perform the following transformations:
|
|
// (objc_to_thick_metatype (metatype @objc_metatype)) ->
|
|
// (metatype @thick)
|
|
//
|
|
// (objc_to_thick_metatype (value_metatype @objc_metatype)) ->
|
|
// (value_metatype @thick)
|
|
//
|
|
// (objc_to_thick_metatype (existential_metatype @objc_metatype)) ->
|
|
// (existential_metatype @thick)
|
|
return visitMetatypeConversionInst(Builder, OCTTMI,
|
|
MetatypeRepresentation::ObjC);
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::visitCheckedCastBranchInst(CheckedCastBranchInst *CBI) {
|
|
CastOpt.optimizeCheckedCastBranchInst(CBI);
|
|
return nullptr;
|
|
}
|
|
|
|
SILInstruction *
|
|
SILCombiner::
|
|
visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CCABI) {
|
|
CastOpt.optimizeCheckedCastAddrBranchInst(CCABI);
|
|
return nullptr;
|
|
}
|
|
|
|
/// Replace a convert_function that only has refcounting uses with its
|
|
/// operand.
|
|
SILInstruction *SILCombiner::visitConvertFunctionInst(ConvertFunctionInst *CFI) {
|
|
auto anyNonRefCountUse =
|
|
std::any_of(CFI->use_begin(),
|
|
CFI->use_end(),
|
|
[](Operand *Use) {
|
|
return !isa<RefCountingInst>(Use->getUser());
|
|
});
|
|
|
|
if (anyNonRefCountUse)
|
|
return nullptr;
|
|
|
|
// Replace all retain/releases on convert_function by retain/releases on
|
|
// its argument. This is required to preserve the lifetime of its argument,
|
|
// which could be e.g. a partial_apply instruction capturing some further
|
|
// arguments.
|
|
auto Converted = CFI->getConverted();
|
|
while (!CFI->use_empty()) {
|
|
auto *Use = *(CFI->use_begin());
|
|
assert(!Use->getUser()->hasValue() && "Did not expect user with a result!");
|
|
Use->set(Converted);
|
|
}
|
|
|
|
eraseInstFromFunction(*CFI);
|
|
return nullptr;
|
|
}
|