//===--- 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(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(RRPI->getOperand())) if (auto *IER = dyn_cast(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(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(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"(%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(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(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(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(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(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(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(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(URCI->getOperand())) if (auto *IER = dyn_cast(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(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(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(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(); if (MetatypeTy->getRepresentation() != Representation) return nullptr; if (isa(Op)) return Builder.createMetatype(MCI->getLoc(), Ty); if (auto *VMI = dyn_cast(Op)) return Builder.createValueMetatype(MCI->getLoc(), Ty, VMI->getOperand()); if (auto *EMI = dyn_cast(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(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; }