//===--- SILInstruction.cpp - Instructions for SIL code -------------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file defines the high-level SILInstruction classes used for SIL code. // //===----------------------------------------------------------------------===// #include "swift/SIL/SILInstruction.h" #include "swift/Basic/type_traits.h" #include "swift/Basic/Unicode.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILCloner.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILVisitor.h" #include "swift/Basic/AssertImplements.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/SIL/SILModule.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" using namespace swift; using namespace Lowering; //===----------------------------------------------------------------------===// // Instruction-specific properties on SILValue //===----------------------------------------------------------------------===// SILLocation SILInstruction::getLoc() const { return Location.getLocation(); } const SILDebugScope *SILInstruction::getDebugScope() const { return Location.getScope(); } void SILInstruction::setDebugScope(const SILDebugScope *DS) { if (getDebugScope() && getDebugScope()->InlinedCallSite) assert(DS->InlinedCallSite && "throwing away inlined scope info"); assert(DS->getParentFunction() == getFunction() && "scope belongs to different function"); Location = SILDebugLocation(getLoc(), DS); } //===----------------------------------------------------------------------===// // ilist_traits Implementation //===----------------------------------------------------------------------===// // The trait object is embedded into a basic block. Use dirty hacks to // reconstruct the BB from the 'self' pointer of the trait. SILBasicBlock *llvm::ilist_traits::getContainingBlock() { size_t Offset( size_t(&((SILBasicBlock *)nullptr->*SILBasicBlock::getSublistAccess()))); iplist *Anchor(static_cast *>(this)); return reinterpret_cast(reinterpret_cast(Anchor) - Offset); } void llvm::ilist_traits::addNodeToList(SILInstruction *I) { assert(I->ParentBB == nullptr && "Already in a list!"); I->ParentBB = getContainingBlock(); } void llvm::ilist_traits::removeNodeFromList(SILInstruction *I) { // When an instruction is removed from a BB, clear the parent pointer. assert(I->ParentBB && "Not in a list!"); I->ParentBB = nullptr; } void llvm::ilist_traits:: transferNodesFromList(llvm::ilist_traits &L2, instr_iterator first, instr_iterator last) { // If transferring instructions within the same basic block, no reason to // update their parent pointers. SILBasicBlock *ThisParent = getContainingBlock(); if (ThisParent == L2.getContainingBlock()) return; // Update the parent fields in the instructions. for (; first != last; ++first) { SWIFT_FUNC_STAT_NAMED("sil"); first->ParentBB = ThisParent; } } //===----------------------------------------------------------------------===// // SILInstruction Implementation //===----------------------------------------------------------------------===// // Assert that all subclasses of ValueBase implement classof. #define NODE(CLASS, PARENT) \ ASSERT_IMPLEMENTS_STATIC(CLASS, PARENT, classof, bool(const SILNode*)); #include "swift/SIL/SILNodes.def" SILFunction *SILInstruction::getFunction() { return getParent()->getParent(); } const SILFunction *SILInstruction::getFunction() const { return getParent()->getParent(); } SILModule &SILInstruction::getModule() const { return getFunction()->getModule(); } /// eraseFromParent - This method unlinks 'self' from the containing basic /// block and deletes it. /// void SILInstruction::eraseFromParent() { #ifndef NDEBUG for (auto result : getResults()) { assert(result->use_empty() && "Uses of SILInstruction remain at deletion."); } #endif getParent()->erase(this); } void SILInstruction::moveFront(SILBasicBlock *Block) { getParent()->remove(this); Block->push_front(this); } /// Unlink this instruction from its current basic block and insert it into /// the basic block that Later lives in, right before Later. void SILInstruction::moveBefore(SILInstruction *Later) { if (this == Later) return; getParent()->remove(this); Later->getParent()->insert(Later, this); } /// Unlink this instruction from its current basic block and insert it into /// the basic block that Earlier lives in, right after Earlier. void SILInstruction::moveAfter(SILInstruction *Earlier) { // Since MovePos is an instruction, we know that there is always a valid // iterator after it. auto Later = std::next(SILBasicBlock::iterator(Earlier)); moveBefore(&*Later); } void SILInstruction::dropAllReferences() { MutableArrayRef PossiblyDeadOps = getAllOperands(); for (auto OpI = PossiblyDeadOps.begin(), OpE = PossiblyDeadOps.end(); OpI != OpE; ++OpI) { OpI->drop(); } // If we have a function ref inst, we need to especially drop its function // argument so that it gets a proper ref decrement. if (auto *FRI = dyn_cast(this)) { if (!FRI->getReferencedFunction()) return; FRI->dropReferencedFunction(); return; } // If we have a KeyPathInst, drop its pattern reference so that we can // decrement refcounts on referenced functions. if (auto *KPI = dyn_cast(this)) { if (!KPI->hasPattern()) return; KPI->dropReferencedPattern(); return; } } namespace { class AllResultsAccessor : public SILInstructionVisitor { public: // Make sure we hit a linker error if we ever miss an instruction. #define INST(ID, NAME) SILInstructionResultArray visit##ID(ID *I); #define NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \ SILInstructionResultArray visit##ID(ID *I) { \ return SILInstructionResultArray(); \ } #define SINGLE_VALUE_INST(ID, TEXTUALNAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \ SILInstructionResultArray visit##ID(ID *I) { \ return SILInstructionResultArray( \ static_cast(I)); \ } #define MULTIPLE_VALUE_INST(ID, TEXTUALNAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \ SILInstructionResultArray visit##ID(ID *I) { \ return SILInstructionResultArray(I->getAllResults()); \ } #include "swift/SIL/SILNodes.def" }; } // end anonymous namespace SILInstructionResultArray SILInstruction::getResultsImpl() const { return AllResultsAccessor().visit(const_cast(this)); } // Initialize the static members of SILInstruction. int SILInstruction::NumCreatedInstructions = 0; int SILInstruction::NumDeletedInstructions = 0; /// Map a SILInstruction name to its SILInstructionKind. SILInstructionKind swift::getSILInstructionKind(StringRef name) { #define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \ if (name == #NAME) \ return SILInstructionKind::ID; #include "swift/SIL/SILNodes.def" #ifdef NDEBUG llvm::errs() << "Unknown SIL instruction name\n"; abort(); #endif llvm_unreachable("Unknown SIL insruction name"); } /// Map SILInstructionKind to a corresponding SILInstruction name. StringRef swift::getSILInstructionName(SILInstructionKind kind) { switch (kind) { #define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \ case SILInstructionKind::ID: \ return #NAME; #include "swift/SIL/SILNodes.def" } llvm_unreachable("bad kind"); } void SILInstruction::replaceAllUsesOfAllResultsWithUndef() { for (auto result : getResults()) { result->replaceAllUsesWithUndef(); } } void SILInstruction::replaceAllUsesPairwiseWith(SILInstruction *other) { auto results = getResults(); // If we don't have any results, fast-path out without asking the other // instruction for its results. if (results.empty()) { assert(other->getResults().empty()); return; } // Replace values with the corresponding values of the other instruction. auto otherResults = other->getResults(); assert(results.size() == otherResults.size()); for (auto i : indices(results)) { results[i]->replaceAllUsesWith(otherResults[i]); } } void SILInstruction::replaceAllUsesPairwiseWith( const llvm::SmallVectorImpl &NewValues) { auto Results = getResults(); // If we don't have any results, fast-path out without asking the other // instruction for its results. if (Results.empty()) { assert(NewValues.empty()); return; } // Replace values with the corresponding values of the list. Make sure they // are all the same type. assert(Results.size() == NewValues.size()); for (unsigned i : indices(Results)) { assert(Results[i]->getType() == NewValues[i]->getType() && "Can only replace results with new values of the same type"); Results[i]->replaceAllUsesWith(NewValues[i]); } } Operand *BeginBorrowInst::getSingleNonEndingUse() const { Operand *singleUse = nullptr; for (auto *use : getUses()) { if (isa(use->getUser())) continue; if (singleUse) return nullptr; singleUse = use; } return singleUse; } namespace { class InstructionDestroyer : public SILInstructionVisitor { public: #define INST(CLASS, PARENT) \ void visit##CLASS(CLASS *I) { I->~CLASS(); } #include "swift/SIL/SILNodes.def" }; } // end anonymous namespace void SILInstruction::destroy(SILInstruction *I) { InstructionDestroyer().visit(I); } namespace { /// Given a pair of instructions that are already known to have the same kind, /// type, and operands check any special state in the two instructions that /// could disrupt equality. class InstructionIdentityComparer : public SILInstructionVisitor { public: InstructionIdentityComparer(const SILInstruction *L) : LHS(L) { } /// Make sure we only process instructions we know how to process. bool visitSILInstruction(const SILInstruction *RHS) { return false; } bool visitInjectEnumAddrInst(const InjectEnumAddrInst *RHS) { auto *X = cast(LHS); return X->getElement() == RHS->getElement(); } bool visitDestroyAddrInst(const DestroyAddrInst *RHS) { return true; } bool visitReleaseValueInst(const ReleaseValueInst *RHS) { return true; } bool visitReleaseValueAddrInst(const ReleaseValueAddrInst *RHS) { return true; } bool visitRetainValueInst(const RetainValueInst *RHS) { return true; } bool visitRetainValueAddrInst(const RetainValueAddrInst *RHS) { return true; } bool visitDeallocStackInst(const DeallocStackInst *RHS) { return true; } bool visitAllocStackInst(const AllocStackInst *RHS) { return true; } bool visitDeallocBoxInst(const DeallocBoxInst *RHS) { return true; } bool visitAllocBoxInst(const AllocBoxInst *RHS) { return true; } bool visitDeallocRefInst(const DeallocRefInst *RHS) { return true; } bool visitDeallocPartialRefInst(const DeallocPartialRefInst *RHS) { return true; } bool visitAllocRefInst(const AllocRefInst *RHS) { auto *LHSInst = cast(LHS); auto LHSTypes = LHSInst->getTailAllocatedTypes(); auto RHSTypes = RHS->getTailAllocatedTypes(); unsigned NumTypes = LHSTypes.size(); assert(NumTypes == RHSTypes.size()); for (unsigned Idx = 0; Idx < NumTypes; ++Idx) { if (LHSTypes[Idx] != RHSTypes[Idx]) return false; } return true; } bool visitAllocRefDynamicInst(const AllocRefDynamicInst *RHS) { return true; } bool visitProjectValueBufferInst(const ProjectValueBufferInst *RHS) { auto *X = cast(LHS); return X->getValueType() == RHS->getValueType(); } bool visitProjectBoxInst(const ProjectBoxInst *RHS) { return true; } bool visitProjectExistentialBoxInst(const ProjectExistentialBoxInst *RHS) { return true; } bool visitBeginAccessInst(const BeginAccessInst *right) { auto left = cast(LHS); return left->getAccessKind() == right->getAccessKind() && left->getEnforcement() == right->getEnforcement() && left->hasNoNestedConflict() == right->hasNoNestedConflict() && left->isFromBuiltin() == right->isFromBuiltin(); } bool visitEndAccessInst(const EndAccessInst *right) { auto left = cast(LHS); return left->isAborting() == right->isAborting(); } bool visitBeginUnpairedAccessInst(const BeginUnpairedAccessInst *right) { auto left = cast(LHS); return left->getAccessKind() == right->getAccessKind() && left->getEnforcement() == right->getEnforcement() && left->hasNoNestedConflict() == right->hasNoNestedConflict() && left->isFromBuiltin() == right->isFromBuiltin(); } bool visitEndUnpairedAccessInst(const EndUnpairedAccessInst *right) { auto left = cast(LHS); return left->getEnforcement() == right->getEnforcement() && left->isAborting() == right->isAborting() && left->isFromBuiltin() == right->isFromBuiltin(); } bool visitStrongReleaseInst(const StrongReleaseInst *RHS) { return true; } bool visitStrongRetainInst(const StrongRetainInst *RHS) { return true; } bool visitLoadInst(const LoadInst *RHS) { auto LHSQualifier = cast(LHS)->getOwnershipQualifier(); return LHSQualifier == RHS->getOwnershipQualifier(); } bool visitLoadBorrowInst(const LoadBorrowInst *RHS) { return true; } bool visitEndBorrowInst(const EndBorrowInst *RHS) { return true; } bool visitBeginBorrowInst(const BeginBorrowInst *BBI) { return true; } bool visitStoreBorrowInst(const StoreBorrowInst *RHS) { auto *X = cast(LHS); return X->getSrc() == RHS->getSrc() && X->getDest() == RHS->getDest(); } bool visitStoreInst(const StoreInst *RHS) { auto *X = cast(LHS); return X->getSrc() == RHS->getSrc() && X->getDest() == RHS->getDest() && X->getOwnershipQualifier() == RHS->getOwnershipQualifier(); } bool visitBindMemoryInst(const BindMemoryInst *RHS) { auto *X = cast(LHS); return X->getBoundType() == RHS->getBoundType(); } bool visitFunctionRefInst(const FunctionRefInst *RHS) { auto *X = cast(LHS); return X->getReferencedFunction() == RHS->getReferencedFunction(); } bool visitDynamicFunctionRefInst(const DynamicFunctionRefInst *RHS) { auto *X = cast(LHS); return X->getReferencedFunction() == RHS->getReferencedFunction(); } bool visitPreviousDynamicFunctionRefInst( const PreviousDynamicFunctionRefInst *RHS) { auto *X = cast(LHS); return X->getReferencedFunction() == RHS->getReferencedFunction(); } bool visitAllocGlobalInst(const AllocGlobalInst *RHS) { auto *X = cast(LHS); return X->getReferencedGlobal() == RHS->getReferencedGlobal(); } bool visitGlobalAddrInst(const GlobalAddrInst *RHS) { auto *X = cast(LHS); return X->getReferencedGlobal() == RHS->getReferencedGlobal(); } bool visitIntegerLiteralInst(const IntegerLiteralInst *RHS) { APInt X = cast(LHS)->getValue(); APInt Y = RHS->getValue(); return X.getBitWidth() == Y.getBitWidth() && X == Y; } bool visitFloatLiteralInst(const FloatLiteralInst *RHS) { // Avoid floating point comparison issues by doing a bitwise comparison. APInt X = cast(LHS)->getBits(); APInt Y = RHS->getBits(); return X.getBitWidth() == Y.getBitWidth() && X == Y; } bool visitStringLiteralInst(const StringLiteralInst *RHS) { auto LHS_ = cast(LHS); return LHS_->getEncoding() == RHS->getEncoding() && LHS_->getValue().equals(RHS->getValue()); } bool visitStructInst(const StructInst *RHS) { // We have already checked the operands. Make sure that the StructDecls // match up. StructDecl *S1 = cast(LHS)->getStructDecl(); return S1 == RHS->getStructDecl(); } bool visitStructExtractInst(const StructExtractInst *RHS) { // We have already checked that the operands of our struct_extracts // match. Thus we need to check the field/struct decl which are not // operands. auto *X = cast(LHS); if (X->getStructDecl() != RHS->getStructDecl()) return false; if (X->getField() != RHS->getField()) return false; return true; } bool visitRefElementAddrInst(RefElementAddrInst *RHS) { auto *X = cast(LHS); if (X->getField() != RHS->getField()) return false; if (X->getOperand() != RHS->getOperand()) return false; return true; } bool visitRefTailAddrInst(RefTailAddrInst *RHS) { auto *X = cast(LHS); return X->getTailType() == RHS->getTailType(); } bool visitStructElementAddrInst(const StructElementAddrInst *RHS) { // We have already checked that the operands of our struct_element_addrs // match. Thus we only need to check the field/struct decl which are not // operands. auto *X = cast(LHS); if (X->getStructDecl() != RHS->getStructDecl()) return false; if (X->getField() != RHS->getField()) return false; return true; } bool visitTupleInst(const TupleInst *RHS) { // We have already checked the operands. Make sure that the tuple types // match up. TupleType *TT1 = cast(LHS)->getTupleType(); return TT1 == RHS->getTupleType(); } bool visitTupleExtractInst(const TupleExtractInst *RHS) { // We have already checked that the operands match. Thus we only need to // check the field no and tuple type which are not represented as operands. auto *X = cast(LHS); if (X->getTupleType() != RHS->getTupleType()) return false; if (X->getFieldNo() != RHS->getFieldNo()) return false; return true; } bool visitTupleElementAddrInst(const TupleElementAddrInst *RHS) { // We have already checked that the operands match. Thus we only need to // check the field no and tuple type which are not represented as operands. auto *X = cast(LHS); if (X->getTupleType() != RHS->getTupleType()) return false; if (X->getFieldNo() != RHS->getFieldNo()) return false; return true; } bool visitMetatypeInst(const MetatypeInst *RHS) { // We have already compared the operands/types, so we should have equality // at this point. return true; } bool visitValueMetatypeInst(const ValueMetatypeInst *RHS) { // We have already compared the operands/types, so we should have equality // at this point. return true; } bool visitExistentialMetatypeInst(const ExistentialMetatypeInst *RHS) { // We have already compared the operands/types, so we should have equality // at this point. return true; } bool visitIndexRawPointerInst(IndexRawPointerInst *RHS) { // We have already compared the operands/types, so we should have equality // at this point. return true; } bool visitIndexAddrInst(IndexAddrInst *RHS) { // We have already compared the operands/types, so we should have equality // at this point. return true; } bool visitTailAddrInst(TailAddrInst *RHS) { auto *X = cast(LHS); return X->getTailType() == RHS->getTailType(); } bool visitCondFailInst(CondFailInst *RHS) { // We have already compared the operands/types, so we should have equality // at this point. return true; } bool visitApplyInst(ApplyInst *RHS) { auto *X = cast(LHS); return X->getSubstitutionMap() == RHS->getSubstitutionMap(); } bool visitBuiltinInst(BuiltinInst *RHS) { auto *X = cast(LHS); if (X->getName() != RHS->getName()) return false; return X->getSubstitutions() == RHS->getSubstitutions(); } bool visitEnumInst(EnumInst *RHS) { // We already checked operands and types. Only thing we need to check is // that the element is the same. auto *X = cast(LHS); return X->getElement() == RHS->getElement(); } bool visitUncheckedEnumDataInst(UncheckedEnumDataInst *RHS) { // We already checked operands and types. Only thing we need to check is // that the element is the same. auto *X = cast(LHS); return X->getElement() == RHS->getElement(); } bool visitSelectEnumInstBase(const SelectEnumInstBase *RHS) { // Check that the instructions match cases in the same order. auto *X = cast(LHS); if (X->getNumCases() != RHS->getNumCases()) return false; if (X->hasDefault() != RHS->hasDefault()) return false; for (unsigned i = 0, e = X->getNumCases(); i < e; ++i) { if (X->getCase(i).first != RHS->getCase(i).first) return false; } return true; } bool visitSelectEnumInst(const SelectEnumInst *RHS) { return visitSelectEnumInstBase(RHS); } bool visitSelectEnumAddrInst(const SelectEnumAddrInst *RHS) { return visitSelectEnumInstBase(RHS); } bool visitSelectValueInst(const SelectValueInst *RHS) { // Check that the instructions match cases in the same order. auto *X = cast(LHS); if (X->getNumCases() != RHS->getNumCases()) return false; if (X->hasDefault() != RHS->hasDefault()) return false; for (unsigned i = 0, e = X->getNumCases(); i < e; ++i) { if (X->getCase(i).first != RHS->getCase(i).first) return false; if (X->getCase(i).second != RHS->getCase(i).second) return false; } return true; } // Conversion instructions. // All of these just return true as they have already had their // operands and types checked bool visitUncheckedRefCastInst(UncheckedRefCastInst *RHS) { return true; } bool visitUncheckedAddrCastInst(UncheckedAddrCastInst *RHS) { return true; } bool visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *RHS) { return true; } bool visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *RHS) { return true; } bool visitUpcastInst(UpcastInst *RHS) { return true; } bool visitAddressToPointerInst(AddressToPointerInst *RHS) { return true; } bool visitPointerToAddressInst(PointerToAddressInst *RHS) { return cast(LHS)->isStrict() == RHS->isStrict(); } bool visitRefToRawPointerInst(RefToRawPointerInst *RHS) { return true; } bool visitRawPointerToRefInst(RawPointerToRefInst *RHS) { return true; } #define LOADABLE_REF_STORAGE_HELPER(Name) \ bool visit##Name##ToRefInst(Name##ToRefInst *RHS) { return true; } \ bool visitRefTo##Name##Inst(RefTo##Name##Inst *RHS) { return true; } #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ LOADABLE_REF_STORAGE_HELPER(Name) \ bool visitStrongRetain##Name##Inst(const StrongRetain##Name##Inst *RHS) { \ return true; \ } #define UNCHECKED_REF_STORAGE(Name, ...) \ LOADABLE_REF_STORAGE_HELPER(Name) #include "swift/AST/ReferenceStorage.def" #undef LOADABLE_REF_STORAGE_HELPER bool visitThinToThickFunctionInst(ThinToThickFunctionInst *RHS) { return true; } bool visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *RHS) { return true; } bool visitObjCToThickMetatypeInst(ObjCToThickMetatypeInst *RHS) { return true; } bool visitConvertFunctionInst(ConvertFunctionInst *RHS) { return true; } bool visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *RHS) { return true; } bool visitObjCMetatypeToObjectInst(ObjCMetatypeToObjectInst *RHS) { return true; } bool visitObjCExistentialMetatypeToObjectInst(ObjCExistentialMetatypeToObjectInst *RHS) { return true; } bool visitProjectBlockStorageInst(ProjectBlockStorageInst *RHS) { return true; } bool visitBridgeObjectToRefInst(BridgeObjectToRefInst *X) { return true; } bool visitValueToBridgeObjectInst(ValueToBridgeObjectInst *i) { return true; } bool visitBridgeObjectToWordInst(BridgeObjectToWordInst *X) { return true; } bool visitRefToBridgeObjectInst(RefToBridgeObjectInst *X) { return true; } bool visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *X) { return true; } bool visitThinFunctionToPointerInst(ThinFunctionToPointerInst *X) { return true; } bool visitPointerToThinFunctionInst(PointerToThinFunctionInst *X) { return true; } bool visitObjCProtocolInst(ObjCProtocolInst *RHS) { auto *X = cast(LHS); return X->getProtocol() == RHS->getProtocol(); } bool visitClassMethodInst(ClassMethodInst *RHS) { auto *X = cast(LHS); return X->getMember() == RHS->getMember() && X->getOperand() == RHS->getOperand() && X->getType() == RHS->getType(); } bool visitSuperMethodInst(SuperMethodInst *RHS) { auto *X = cast(LHS); return X->getMember() == RHS->getMember() && X->getOperand() == RHS->getOperand() && X->getType() == RHS->getType(); } bool visitObjCMethodInst(ObjCMethodInst *RHS) { auto *X = cast(LHS); return X->getMember() == RHS->getMember() && X->getOperand() == RHS->getOperand() && X->getType() == RHS->getType(); } bool visitObjCSuperMethodInst(ObjCSuperMethodInst *RHS) { auto *X = cast(LHS); return X->getMember() == RHS->getMember() && X->getOperand() == RHS->getOperand() && X->getType() == RHS->getType(); } bool visitWitnessMethodInst(const WitnessMethodInst *RHS) { auto *X = cast(LHS); if (X->getMember() != RHS->getMember()) return false; if (X->getLookupType() != RHS->getLookupType()) return false; if (X->getConformance() != RHS->getConformance()) return false; return true; } bool visitMarkDependenceInst(const MarkDependenceInst *RHS) { return true; } bool visitOpenExistentialRefInst(const OpenExistentialRefInst *RHS) { return true; } private: const SILInstruction *LHS; }; } // end anonymous namespace bool SILInstruction::hasIdenticalState(const SILInstruction *RHS) const { SILInstruction *UnconstRHS = const_cast(RHS); return InstructionIdentityComparer(this).visit(UnconstRHS); } namespace { class AllOperandsAccessor : public SILInstructionVisitor > { public: #define INST(CLASS, PARENT) \ ArrayRef visit##CLASS(const CLASS *I) { \ ASSERT_IMPLEMENTS(CLASS, SILInstruction, getAllOperands, \ ArrayRef() const); \ return I->getAllOperands(); \ } #include "swift/SIL/SILNodes.def" }; class AllOperandsMutableAccessor : public SILInstructionVisitor > { public: #define INST(CLASS, PARENT) \ MutableArrayRef visit##CLASS(CLASS *I) { \ ASSERT_IMPLEMENTS(CLASS, SILInstruction, getAllOperands, \ MutableArrayRef()); \ return I->getAllOperands(); \ } #include "swift/SIL/SILNodes.def" }; #define IMPLEMENTS_METHOD(DerivedClass, BaseClass, MemberName, ExpectedType) \ (!::std::is_same::value) class TypeDependentOperandsAccessor : public SILInstructionVisitor> { public: #define INST(CLASS, PARENT) \ ArrayRef visit##CLASS(const CLASS *I) { \ if (!IMPLEMENTS_METHOD(CLASS, SILInstruction, getTypeDependentOperands, \ ArrayRef() const)) \ return {}; \ return I->getTypeDependentOperands(); \ } #include "swift/SIL/SILNodes.def" }; class TypeDependentOperandsMutableAccessor : public SILInstructionVisitor > { public: #define INST(CLASS, PARENT) \ MutableArrayRef visit##CLASS(CLASS *I) { \ if (!IMPLEMENTS_METHOD(CLASS, SILInstruction, getTypeDependentOperands, \ MutableArrayRef())) \ return {}; \ return I->getTypeDependentOperands(); \ } #include "swift/SIL/SILNodes.def" }; } // end anonymous namespace ArrayRef SILInstruction::getAllOperands() const { return AllOperandsAccessor().visit(const_cast(this)); } MutableArrayRef SILInstruction::getAllOperands() { return AllOperandsMutableAccessor().visit(this); } ArrayRef SILInstruction::getTypeDependentOperands() const { return TypeDependentOperandsAccessor().visit( const_cast(this)); } MutableArrayRef SILInstruction::getTypeDependentOperands() { return TypeDependentOperandsMutableAccessor().visit(this); } /// getOperandNumber - Return which operand this is in the operand list of the /// using instruction. unsigned Operand::getOperandNumber() const { return this - &cast(getUser())->getAllOperands()[0]; } SILInstruction::MemoryBehavior SILInstruction::getMemoryBehavior() const { if (auto *BI = dyn_cast(this)) { // Handle Swift builtin functions. const BuiltinInfo &BInfo = BI->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) return BInfo.isReadNone() ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; // Handle LLVM intrinsic functions. const IntrinsicInfo &IInfo = BI->getIntrinsicInfo(); if (IInfo.ID != llvm::Intrinsic::not_intrinsic) { // Read-only. if (IInfo.hasAttribute(llvm::Attribute::ReadOnly) && IInfo.hasAttribute(llvm::Attribute::NoUnwind)) return MemoryBehavior::MayRead; // Read-none? return IInfo.hasAttribute(llvm::Attribute::ReadNone) && IInfo.hasAttribute(llvm::Attribute::NoUnwind) ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } } // Handle full apply sites that have a resolvable callee function with an // effects attribute. if (isa(this)) { FullApplySite Site(const_cast(this)); if (auto *F = Site.getCalleeFunction()) { return F->getEffectsKind() == EffectsKind::ReadNone ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } } switch (getKind()) { #define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \ case SILInstructionKind::CLASS: \ return MemoryBehavior::MEMBEHAVIOR; #include "swift/SIL/SILNodes.def" } llvm_unreachable("We've just exhausted the switch."); } SILInstruction::ReleasingBehavior SILInstruction::getReleasingBehavior() const { switch (getKind()) { #define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \ case SILInstructionKind::CLASS: \ return ReleasingBehavior::RELEASINGBEHAVIOR; #include "swift/SIL/SILNodes.def" } llvm_unreachable("We've just exhausted the switch."); } bool SILInstruction::mayHaveSideEffects() const { // If this instruction traps then it must have side effects. if (mayTrap()) return true; MemoryBehavior B = getMemoryBehavior(); return B == MemoryBehavior::MayWrite || B == MemoryBehavior::MayReadWrite || B == MemoryBehavior::MayHaveSideEffects; } bool SILInstruction::mayRelease() const { if (getReleasingBehavior() == SILInstruction::ReleasingBehavior::DoesNotRelease) return false; switch (getKind()) { default: llvm_unreachable("Unhandled releasing instruction!"); case SILInstructionKind::ApplyInst: case SILInstructionKind::TryApplyInst: case SILInstructionKind::BeginApplyInst: case SILInstructionKind::AbortApplyInst: case SILInstructionKind::EndApplyInst: case SILInstructionKind::YieldInst: case SILInstructionKind::DestroyAddrInst: case SILInstructionKind::StrongReleaseInst: #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::Name##ReleaseInst: #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::ReleaseValueInst: case SILInstructionKind::ReleaseValueAddrInst: return true; case SILInstructionKind::DestroyValueInst: assert(!SILModuleConventions(getModule()).useLoweredAddresses()); return true; case SILInstructionKind::UnconditionalCheckedCastAddrInst: case SILInstructionKind::UnconditionalCheckedCastValueInst: return true; case SILInstructionKind::CheckedCastAddrBranchInst: { // Failing casts with take_always can release. auto *Cast = cast(this); return Cast->getConsumptionKind() == CastConsumptionKind::TakeAlways; } case SILInstructionKind::CopyAddrInst: { auto *CopyAddr = cast(this); // copy_addr without initialization can cause a release. return CopyAddr->isInitializationOfDest() == IsInitialization_t::IsNotInitialization; } case SILInstructionKind::BuiltinInst: { auto *BI = cast(this); // Builtins without side effects also do not release. if (!BI->mayHaveSideEffects()) return false; // If this is a builtin which might have side effect, but its side // effects do not cause reference counts to be decremented, return false. if (auto Kind = BI->getBuiltinKind()) { switch (Kind.getValue()) { case BuiltinValueKind::CopyArray: return false; default: break; } } if (auto ID = BI->getIntrinsicID()) { switch (ID.getValue()) { case llvm::Intrinsic::memcpy: case llvm::Intrinsic::memmove: case llvm::Intrinsic::memset: return false; default: break; } } return true; } } } bool SILInstruction::mayReleaseOrReadRefCount() const { switch (getKind()) { case SILInstructionKind::IsUniqueInst: case SILInstructionKind::IsEscapingClosureInst: return true; default: return mayRelease(); } } namespace { class TrivialCloner : public SILCloner { friend class SILCloner; friend class SILInstructionVisitor; SILInstruction *Result = nullptr; TrivialCloner(SILFunction *F) : SILCloner(*F) {} public: static SILInstruction *doIt(SILInstruction *I) { TrivialCloner TC(I->getFunction()); TC.visit(I); return TC.Result; } void postProcess(SILInstruction *Orig, SILInstruction *Cloned) { assert(Orig->getFunction() == &getBuilder().getFunction() && "cloning between functions is not supported"); Result = Cloned; SILCloner::postProcess(Orig, Cloned); } SILValue getMappedValue(SILValue Value) { return Value; } SILBasicBlock *remapBasicBlock(SILBasicBlock *BB) { return BB; } }; } // end anonymous namespace bool SILInstruction::isAllocatingStack() const { if (isa(this)) return true; if (auto *ARI = dyn_cast(this)) { if (ARI->canAllocOnStack()) return true; } if (auto *PA = dyn_cast(this)) return PA->isOnStack(); return false; } bool SILInstruction::isDeallocatingStack() const { if (isa(this)) return true; if (auto *DRI = dyn_cast(this)) { if (DRI->canAllocOnStack()) return true; } return false; } /// Create a new copy of this instruction, which retains all of the operands /// and other information of this one. If an insertion point is specified, /// then the new instruction is inserted before the specified point, otherwise /// the new instruction is returned without a parent. SILInstruction *SILInstruction::clone(SILInstruction *InsertPt) { SILInstruction *NewInst = TrivialCloner::doIt(this); if (NewInst && InsertPt) InsertPt->getParent()->insert(InsertPt, NewInst); return NewInst; } /// Returns true if the instruction can be duplicated without any special /// additional handling. It is important to know this information when /// you perform such optimizations like e.g. jump-threading. bool SILInstruction::isTriviallyDuplicatable() const { if (isa(this) || isa(this)) { return false; } if (auto *ARI = dyn_cast(this)) { if (ARI->canAllocOnStack()) return false; } if (isa(this) || isa(this) || isa(this) || isa(this) || isa(this) || isa(this)) { // Don't know how to duplicate these properly yet. Inst.clone() per // instruction does not work. Because the follow-up instructions need to // reuse the same archetype uuid which would only work if we used a // cloner. return false; } if (auto *MI = dyn_cast(this)) { // We can't build SSA for method values that lower to objc methods. if (MI->getMember().isForeign) return false; } if (isa(this)) return false; // BeginAccess defines the access scope entry point. All associated EndAccess // instructions must directly operate on the BeginAccess. if (isa(this)) return false; // begin_apply creates a token that has to be directly used by the // corresponding end_apply and abort_apply. if (isa(this)) return false; // dynamic_method_br is not duplicatable because IRGen does not support phi // nodes of objc_method type. if (isa(this)) return false; if (auto *PA = dyn_cast(this)) return !PA->isOnStack(); // If you add more cases here, you should also update SILLoop:canDuplicate. return true; } bool SILInstruction::mayTrap() const { switch(getKind()) { case SILInstructionKind::CondFailInst: case SILInstructionKind::UnconditionalCheckedCastInst: case SILInstructionKind::UnconditionalCheckedCastAddrInst: return true; default: return false; } } bool SILInstruction::isMetaInstruction() const { // Every instruction that implements getVarInfo() should be in this list. switch (getKind()) { case SILInstructionKind::AllocBoxInst: case SILInstructionKind::AllocStackInst: case SILInstructionKind::DebugValueInst: case SILInstructionKind::DebugValueAddrInst: return true; default: return false; } llvm_unreachable("Instruction not handled in isMetaInstruction()!"); } //===----------------------------------------------------------------------===// // Utilities //===----------------------------------------------------------------------===// llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, SILInstruction::MemoryBehavior B) { switch (B) { case SILInstruction::MemoryBehavior::None: return OS << "None"; case SILInstruction::MemoryBehavior::MayRead: return OS << "MayRead"; case SILInstruction::MemoryBehavior::MayWrite: return OS << "MayWrite"; case SILInstruction::MemoryBehavior::MayReadWrite: return OS << "MayReadWrite"; case SILInstruction::MemoryBehavior::MayHaveSideEffects: return OS << "MayHaveSideEffects"; } llvm_unreachable("Unhandled MemoryBehavior in switch."); } llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, SILInstruction::ReleasingBehavior B) { switch (B) { case SILInstruction::ReleasingBehavior::DoesNotRelease: return OS << "DoesNotRelease"; case SILInstruction::ReleasingBehavior::MayRelease: return OS << "MayRelease"; } llvm_unreachable("Unhandled ReleasingBehavior in switch."); } //===----------------------------------------------------------------------===// // SILInstructionResultArray //===----------------------------------------------------------------------===// SILInstructionResultArray::SILInstructionResultArray( const SingleValueInstruction *SVI) : Pointer(), Size(1) { // Make sure that even though we are munging things, we are able to get back // the original value, types, and operands. SILValue originalValue(SVI); SILType originalType = SVI->getType(); (void)originalValue; (void)originalType; // *PLEASE READ BEFORE CHANGING* // // Since SingleValueInstruction is both a ValueBase and a SILInstruction, but // SILInstruction is the first parent, we need to ensure that our ValueBase * // pointer is properly offset. by first static casting to ValueBase and then // going back to a uint8_t *. auto *Value = static_cast(SVI); assert(uintptr_t(Value) != uintptr_t(SVI) && "Expected value to be offset from SVI since it is not the first " "multi-inheritence parent"); Pointer = reinterpret_cast(Value); #ifndef NDEBUG assert(originalValue == (*this)[0] && "Wrong value returned for single result"); assert(originalType == (*this)[0]->getType()); auto ValueRange = getValues(); assert(1 == std::distance(ValueRange.begin(), ValueRange.end())); assert(originalValue == *ValueRange.begin()); auto TypedRange = getTypes(); assert(1 == std::distance(TypedRange.begin(), TypedRange.end())); assert(originalType == *TypedRange.begin()); SILInstructionResultArray Copy = *this; assert(Copy.hasSameTypes(*this)); assert(Copy == *this); #endif } SILInstructionResultArray::SILInstructionResultArray( ArrayRef MVResults) : Pointer(nullptr), Size(MVResults.size()) { // We are assuming here that MultipleValueInstructionResult when static_cast // is not offset. if (Size) Pointer = reinterpret_cast(&MVResults[0]); #ifndef NDEBUG // Verify our invariants. assert(size() == MVResults.size()); auto ValueRange = getValues(); auto VRangeBegin = ValueRange.begin(); auto VRangeIter = VRangeBegin; auto VRangeEnd = ValueRange.end(); assert(MVResults.size() == unsigned(std::distance(VRangeBegin, VRangeEnd))); auto TypedRange = getTypes(); auto TRangeBegin = TypedRange.begin(); auto TRangeIter = TRangeBegin; auto TRangeEnd = TypedRange.end(); assert(MVResults.size() == unsigned(std::distance(TRangeBegin, TRangeEnd))); for (unsigned i : indices(MVResults)) { assert(SILValue(&MVResults[i]) == (*this)[i]); assert(SILValue(&MVResults[i])->getType() == (*this)[i]->getType()); assert(SILValue(&MVResults[i]) == (*VRangeIter)); assert(SILValue(&MVResults[i])->getType() == (*VRangeIter)->getType()); assert(SILValue(&MVResults[i])->getType() == *TRangeIter); ++VRangeIter; ++TRangeIter; } SILInstructionResultArray Copy = *this; assert(Copy.hasSameTypes(*this)); assert(Copy == *this); #endif } SILValue SILInstructionResultArray::operator[](size_t Index) const { assert(Index < Size && "Index out of bounds"); // *NOTE* In the case where we have a single instruction, Index will always // necessarily be 0 implying that it is safe for us to just multiple Index by // sizeof(MultipleValueInstructionResult). size_t Offset = sizeof(MultipleValueInstructionResult) * Index; return SILValue(reinterpret_cast(&Pointer[Offset])); } bool SILInstructionResultArray::hasSameTypes( const SILInstructionResultArray &rhs) { auto &lhs = *this; if (lhs.size() != rhs.size()) return false; for (unsigned i : indices(lhs)) { if (lhs[i]->getType() != rhs[i]->getType()) return false; } return true; } bool SILInstructionResultArray:: operator==(const SILInstructionResultArray &other) { if (size() != other.size()) return false; for (auto i : indices(*this)) if ((*this)[i] != other[i]) return false; return true; } SILInstructionResultArray::type_range SILInstructionResultArray::getTypes() const { SILType (*F)(SILValue) = [](SILValue V) -> SILType { return V->getType(); }; return {llvm::map_iterator(begin(), F), llvm::map_iterator(end(), F)}; } const ValueBase *SILInstructionResultArray::front() const { assert(size() && "Can not access front of an empty result array"); return *begin(); } const ValueBase *SILInstructionResultArray::back() const { assert(size() && "Can not access back of an empty result array"); if (std::next(begin()) == end()) { return *begin(); } return *std::prev(end()); } //===----------------------------------------------------------------------===// // Multiple Value Instruction //===----------------------------------------------------------------------===// Optional MultipleValueInstruction::getIndexOfResult(SILValue Target) const { // First make sure we actually have one of our instruction results. auto *MVIR = dyn_cast(Target); if (!MVIR || MVIR->getParent() != this) return None; return MVIR->getIndex(); } MultipleValueInstructionResult::MultipleValueInstructionResult( ValueKind valueKind, unsigned index, SILType type, ValueOwnershipKind ownershipKind) : ValueBase(valueKind, type, IsRepresentative::No) { setOwnershipKind(ownershipKind); setIndex(index); } void MultipleValueInstructionResult::setOwnershipKind( ValueOwnershipKind NewKind) { Bits.MultipleValueInstructionResult.VOKind = unsigned(NewKind); } void MultipleValueInstructionResult::setIndex(unsigned NewIndex) { // We currently use 32 bits to store the Index. A previous comment wrote // that "500k fields is probably enough". Bits.MultipleValueInstructionResult.Index = NewIndex; } ValueOwnershipKind MultipleValueInstructionResult::getOwnershipKind() const { return ValueOwnershipKind(Bits.MultipleValueInstructionResult.VOKind); } MultipleValueInstruction *MultipleValueInstructionResult::getParent() { char *Ptr = reinterpret_cast( const_cast(this)); // We know that we are in a trailing objects array with an extra prefix // element that contains the pointer to our parent SILNode. So grab the // address of the beginning of the array. Ptr -= getIndex() * sizeof(MultipleValueInstructionResult); // We may have some bytes of padding depending on our platform. Move past // those bytes if we need to. static_assert(alignof(MultipleValueInstructionResult) >= alignof(MultipleValueInstruction *), "We assume this relationship in between the alignments"); Ptr -= alignof(MultipleValueInstructionResult) - alignof(MultipleValueInstruction *); // Then subtract the size of MultipleValueInstruction. Ptr -= sizeof(MultipleValueInstruction *); // Now that we have the correct address of our parent instruction, grab it and // return it avoiding type punning. uintptr_t value; memcpy(&value, Ptr, sizeof(value)); return reinterpret_cast(value); } #ifndef NDEBUG //--- // Static verification of multiple value properties. // // Make sure that all subclasses of MultipleValueInstruction implement // getAllResults() #define MULTIPLE_VALUE_INST(ID, TEXTUALNAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \ static_assert(IMPLEMENTS_METHOD(ID, PARENT, getAllResults, \ SILInstructionResultArray() const), \ #ID " does not implement SILInstructionResultArray " \ "getAllResults() const?!"); // Check that all subclasses of MultipleValueInstructionResult are the same size // as MultipleValueInstructionResult. // // If this changes, we just need to expand the size fo SILInstructionResultArray // to contain a stride. But we assume this now so we should enforce it. #define MULTIPLE_VALUE_INST_RESULT(ID, PARENT) \ static_assert( \ sizeof(ID) == sizeof(PARENT) && alignof(ID) == alignof(PARENT), \ "Expected all multiple value inst result to be the same size?!"); #include "swift/SIL/SILNodes.def" #endif