mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
introduce a common superclass, SILNode. This is in preparation for allowing instructions to have multiple results. It is also a somewhat more elegant representation for instructions that have zero results. Instructions that are known to have exactly one result inherit from a class, SingleValueInstruction, that subclasses both ValueBase and SILInstruction. Some care must be taken when working with SILNode pointers and testing for equality; please see the comment on SILNode for more information. A number of SIL passes needed to be updated in order to handle this new distinction between SIL values and SIL instructions. Note that the SIL parser is now stricter about not trying to assign a result value from an instruction (like 'return' or 'strong_retain') that does not produce any.
535 lines
21 KiB
C++
535 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()->getResults().empty() &&
|
|
"Did not expect user with a result!");
|
|
Use->set(Converted);
|
|
}
|
|
|
|
eraseInstFromFunction(*CFI);
|
|
return nullptr;
|
|
}
|