//===--- Local.cpp - Functions that perform local SIL transformations. ---===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===---------------------------------------------------------------------===// #include "swift/SILPasses/Utils/Local.h" #include "swift/SILAnalysis/Analysis.h" #include "swift/SIL/CallGraph.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Intrinsics.h" #include using namespace swift; bool swift::isSideEffectFree(BuiltinFunctionRefInst *FR) { // First, check if we are dealing with a swift builtin. const BuiltinInfo &BInfo = FR->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) { return BInfo.isReadNone(); } // Second, specialcase llvm intrinsic. const IntrinsicInfo & IInfo = FR->getIntrinsicInfo(); if (IInfo.ID != llvm::Intrinsic::not_intrinsic) { return ( (IInfo.hasAttribute(llvm::Attribute::ReadNone) || IInfo.hasAttribute(llvm::Attribute::ReadOnly)) && IInfo.hasAttribute(llvm::Attribute::NoUnwind) ); } llvm_unreachable("All cases are covered."); } bool swift::isReadNone(BuiltinFunctionRefInst *FR) { // First, check if we are dealing with a swift builtin. const BuiltinInfo &BInfo = FR->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) return BInfo.isReadNone(); // Second, specialcase llvm intrinsic. const IntrinsicInfo & IInfo = FR->getIntrinsicInfo(); if (IInfo.ID != llvm::Intrinsic::not_intrinsic) return IInfo.hasAttribute(llvm::Attribute::ReadNone) && IInfo.hasAttribute(llvm::Attribute::NoUnwind); llvm_unreachable("All cases are covered."); } /// \brief Perform a fast local check to see if the instruction is dead. /// /// This routine only examines the state of the instruction at hand. bool swift::isInstructionTriviallyDead(SILInstruction *I) { if (!I->use_empty() || isa(I)) return false; // We know that some calls do not have side effects. if (const ApplyInst *AI = dyn_cast(I)) { if (BuiltinFunctionRefInst *FR = dyn_cast(AI->getCallee().getDef())) { return isSideEffectFree(FR); } } // condfail instructions that obviously can't fail are dead. if (auto *CFI = dyn_cast(I)) if (auto *ILI = dyn_cast(CFI->getOperand())) if (!ILI->getValue()) return true; // mark_uninitialized is never dead. if (isa(I)) return false; if (!I->mayHaveSideEffects()) return true; return false; } /// \brief For each of the given instructions, if they are dead delete them /// along with their dead operands. /// /// \param IA The instruction to be deleted. /// \param Force If Force is set, don't check if the top level instructions /// are considered dead - delete them regardless. bool swift::recursivelyDeleteTriviallyDeadInstructions(ArrayRef IA, bool Force) { // Delete these instruction and others that become dead after it's deleted. llvm::SmallPtrSet DeadInsts; for (auto I : IA) { // If the instruction is not dead or force is false, there is nothing to do. if (Force || isInstructionTriviallyDead(I)) DeadInsts.insert(I); } llvm::SmallPtrSet NextInsts; while (!DeadInsts.empty()) { for (auto I : DeadInsts) { // Check if any of the operands will become dead as well. MutableArrayRef Ops = I->getAllOperands(); for (Operand &Op : Ops) { SILValue OpVal = Op.get(); if (!OpVal) continue; // Remove the reference from the instruction being deleted to this // operand. Op.drop(); // If the operand is an instruction that is only used by the instruction // being deleted, delete it. if (SILInstruction *OpValInst = dyn_cast(OpVal)) if (!DeadInsts.count(OpValInst) && isInstructionTriviallyDead(OpValInst)) NextInsts.insert(OpValInst); } } for (auto I : DeadInsts) { // This will remove this instruction and all its uses. I->eraseFromParent(); } NextInsts.swap(DeadInsts); NextInsts.clear(); } return true; } /// \brief If the given instruction is dead, delete it along with its dead /// operands. /// /// \param I The instruction to be deleted. /// \param Force If Force is set, don't check if the top level instruction is /// considered dead - delete it regardless. /// \return Returns true if any instructions were deleted. bool swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *I, bool Force) { return recursivelyDeleteTriviallyDeadInstructions( ArrayRef(I), Force); } void swift::eraseUsesOfInstruction(SILInstruction *Inst) { for (auto UI : Inst->getUses()) { auto *User = UI->getUser(); // If the instruction itself has any uses, recursively zap them so that // nothing uses this instruction. eraseUsesOfInstruction(User); // Walk through the operand list and delete any random instructions that // will become trivially dead when this instruction is removed. for (auto &Op : User->getAllOperands()) { if (auto *OpI = dyn_cast(Op.get().getDef())) { // Don't recursively delete the pointer we're getting in. if (OpI != Inst) { Op.drop(); recursivelyDeleteTriviallyDeadInstructions(OpI); } } } User->eraseFromParent(); } } void swift::bottomUpCallGraphOrder(SILModule *M, std::vector &order) { CallGraphSorter sorter; for (auto &Caller : *M) for (auto &BB : Caller) for (auto &I : BB) if (FunctionRefInst *FRI = dyn_cast(&I)) { SILFunction *Callee = FRI->getReferencedFunction(); sorter.addEdge(&Caller, Callee); } sorter.sort(order); } void swift::replaceWithSpecializedFunction(ApplyInst *AI, SILFunction *NewF) { SILLocation Loc = AI->getLoc(); ArrayRef Subst; SmallVector Arguments; for (auto &Op : AI->getArgumentOperands()) { Arguments.push_back(Op.get()); } SILBuilder Builder(AI); FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF); ApplyInst *NAI = Builder.createApply(Loc, FRI, Arguments, AI->isTransparent()); SILValue(AI, 0).replaceAllUsesWith(SILValue(NAI, 0)); recursivelyDeleteTriviallyDeadInstructions(AI, true); } /// \brief Returns True if the operand or one of its users is captured. static bool useCaptured(Operand *UI) { auto *User = UI->getUser(); // These instructions do not cause the address to escape. if (isa(User) || isa(User) || isa(User) || (isa(User) && UI->getOperandNumber() == 1) || (isa(User) && UI->getOperandNumber() == 1)) { return false; } if ((isa(User) || isa(User)) && User->hasOneUse()) { return useCaptured(*User->use_begin()); } return true; } bool swift::canValueEscape(SILValue V, SmallVectorImpl &Users) { for (auto UI : V.getUses()) { auto *User = UI->getUser(); // These instructions do not cause the address to escape. if (!useCaptured(UI)) { Users.push_back(User); continue; } // These instructions only cause the value to escape if they are used in // a way that escapes. Recursively check that the uses of the instruction // don't escape and collect all of the uses of the value. if (isa(User) || isa(User) || isa(User) || isa(User) || isa(User) || isa(User) || isa(User)) { Users.push_back(User); if (canValueEscape(User, Users)) return true; continue; } // apply instructions do not capture the pointer when it is passed // indirectly if (auto apply = dyn_cast(User)) { if (apply->getSubstCalleeType() ->getInterfaceParameters()[UI->getOperandNumber()-1].isIndirect()) { Users.push_back(User); continue; } } // partial_apply instructions do not allow the pointer to escape // when it is passed indirectly, unless the partial_apply itself // escapes if (auto partialApply = dyn_cast(User)) { auto args = partialApply->getArguments(); auto params = partialApply->getSubstCalleeType() ->getInterfaceParameters(); params = params.slice(params.size() - args.size(), args.size()); if (params[UI->getOperandNumber()-1].isIndirect()) { Users.push_back(User); if (canValueEscape(User, Users)) return true; continue; } } return true; } return false; }