//===--- 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/SILAnalysis/DominanceAnalysis.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/IR/Intrinsics.h" #include using namespace swift; bool swift::isSideEffectFree(BuiltinInst *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(BuiltinInst *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."); } bool swift::isReadNone(FunctionRefInst *FR) { auto *F = FR->getReferencedFunction(); if (!F) return false; return F->getEffectsInfo() == EffectsKind::ReadNone; } /// \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 (auto *FRI = dyn_cast(AI->getCallee())) // If we call an apply inst to a global initializer, but the value is not // used it is safe to remove it. if (FRI->getReferencedFunction()->isGlobalInit()) return true; } if (auto *BI = dyn_cast(I)) { return isSideEffectFree(BI); } // 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; // These invalidate enums so "write" memory, but that is not an essential // operation so we can remove these if they are trivially dead. if (isa(I)) return true; if (!I->mayHaveSideEffects()) return true; return false; } namespace { using CallbackTy = std::function; } // end anonymous namespace bool swift:: recursivelyDeleteTriviallyDeadInstructions(ArrayRef IA, bool Force, CallbackTy Callback) { // 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 and force is false, do nothing. if (Force || isInstructionTriviallyDead(I)) DeadInsts.insert(I); } llvm::SmallPtrSet NextInsts; while (!DeadInsts.empty()) { for (auto I : DeadInsts) { // Call the callback before we mutate the to be deleted instruction in any // way. Callback(I); // 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, CallbackTy Callback) { ArrayRef AI = ArrayRef(I); return recursivelyDeleteTriviallyDeadInstructions(AI, Force, Callback); } 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())) { // Don't recursively delete the pointer we're getting in. if (OpI != Inst) { Op.drop(); recursivelyDeleteTriviallyDeadInstructions(OpI); } } } User->eraseFromParent(); } } 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()); } SILBuilderWithScope<2> Builder(AI); FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF); ApplyInst *NAI = Builder.createApply(Loc, FRI, Arguments, AI->isTransparent()); AI->replaceAllUsesWith(NAI); recursivelyDeleteTriviallyDeadInstructions(AI, true); } bool swift::hasUnboundGenericTypes(TypeSubstitutionMap &SubsMap) { // Check whether any of the substitutions are dependent. for (auto &entry : SubsMap) if (entry.second->getCanonicalType()->hasArchetype()) return true; return false; } bool swift::hasUnboundGenericTypes(ArrayRef Subs) { // Check whether any of the substitutions are dependent. for (auto &sub : Subs) if (sub.getReplacement()->getCanonicalType()->hasArchetype()) return true; return false; } bool swift::hasAnyExistentialTypes(ArrayRef Subs) { // Check whether any of the substitutions are dependent. for (auto &sub : Subs) if (sub.getReplacement()->getCanonicalType()->isAnyExistentialType()) return true; return false; } /// Find a new position for an ApplyInst's FuncRef so that it dominates its /// use. Not that FuncionRefInsts may be shared by multiple ApplyInsts. void swift::placeFuncRef(ApplyInst *AI, DominanceInfo *DT) { FunctionRefInst *FuncRef = cast(AI->getCallee()); SILBasicBlock *DomBB = DT->findNearestCommonDominator(AI->getParent(), FuncRef->getParent()); if (DomBB == AI->getParent() && DomBB != FuncRef->getParent()) // Prefer to place the FuncRef immediately before the call. Since we're // moving FuncRef up, this must be the only call to it in the block. FuncRef->moveBefore(AI); else // Otherwise, conservatively stick it at the beginning of the block. FuncRef->moveBefore(DomBB->begin()); } /// \brief Add an argument, \p val, to the branch-edge that is pointing into /// block \p Dest. Return a new instruction and do not erase the old /// instruction. TermInst *swift::addArgumentToBranch(SILValue Val, SILBasicBlock *Dest, TermInst *Branch) { SILBuilderWithScope<2> Builder(Branch); if (CondBranchInst *CBI = dyn_cast(Branch)) { SmallVector TrueArgs; SmallVector FalseArgs; for (auto A : CBI->getTrueArgs()) TrueArgs.push_back(A); for (auto A : CBI->getFalseArgs()) FalseArgs.push_back(A); if (Dest == CBI->getTrueBB()) { TrueArgs.push_back(Val); assert(TrueArgs.size() == Dest->getNumBBArg()); } else { FalseArgs.push_back(Val); assert(FalseArgs.size() == Dest->getNumBBArg()); } return Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, CBI->getFalseBB(), FalseArgs); } if (BranchInst *BI = dyn_cast(Branch)) { SmallVector Args; for (auto A : BI->getArgs()) Args.push_back(A); Args.push_back(Val); assert(Args.size() == Dest->getNumBBArg()); return Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); } llvm_unreachable("unsupported terminator"); } SILLinkage swift::getSpecializedLinkage(SILLinkage L) { switch (L) { case SILLinkage::Public: case SILLinkage::PublicExternal: case SILLinkage::Shared: case SILLinkage::SharedExternal: case SILLinkage::Hidden: case SILLinkage::HiddenExternal: // Specializations of public or hidden symbols can be shared by all TUs // that specialize the definition. return SILLinkage::Shared; case SILLinkage::Private: case SILLinkage::PrivateExternal: // Specializations of private symbols should remain so. // TODO: maybe PrivateExternals should get SharedExternal (these are private // functions from the stdlib which are specialized in another module). return SILLinkage::Private; } } /// Match array semantic calls. swift::ArraySemanticsCall::ArraySemanticsCall(ValueBase *V, StringRef SemanticStr, bool MatchPartialName) { if (auto AI = dyn_cast(V)) if (auto FRI = dyn_cast(AI->getCallee())) if (auto FunRef = FRI->getReferencedFunction()) { if (MatchPartialName) { if (FunRef->hasDefinedSemantics() && FunRef->getSemanticsString().startswith(SemanticStr)) { SemanticsCall = AI; return; } } else { if (FunRef->hasSemanticsString(SemanticStr)) { SemanticsCall = AI; return; } } } // Otherwise, this is not the semantic call we are looking for. SemanticsCall = nullptr; } /// Determine which kind of array semantics call this is. ArrayCallKind swift::ArraySemanticsCall::getKind() { if (!SemanticsCall) return ArrayCallKind::kNone; auto F = cast(SemanticsCall->getCallee()) ->getReferencedFunction(); auto Kind = llvm::StringSwitch(F->getSemanticsString()) .Case("array.init", ArrayCallKind::kArrayInit) .Case("array.check_subscript", ArrayCallKind::kCheckSubscript) .Case("array.check_index", ArrayCallKind::kCheckIndex) .Case("array.get_count", ArrayCallKind::kGetCount) .Case("array.get_capacity", ArrayCallKind::kGetCapacity) .Case("array.get_element", ArrayCallKind::kGetElement) .Case("array.make_mutable", ArrayCallKind::kMakeMutable) .Case("array.get_element_address", ArrayCallKind::kGetElementAddress) .Case("array.mutate_unknown", ArrayCallKind::kMutateUnknown) .Default(ArrayCallKind::kNone); return Kind; } SILValue swift::ArraySemanticsCall::getSelf() { assert(SemanticsCall && "Must have a semantics call"); assert(SemanticsCall->getNumArguments() && "Must have arguments"); return SemanticsCall->getSelfArgument(); } SILValue swift::ArraySemanticsCall::getIndex() { assert(SemanticsCall && "Must have a semantics call"); assert(SemanticsCall->getNumArguments() && "Must have arguments"); assert(getKind() == ArrayCallKind::kCheckSubscript || getKind() == ArrayCallKind::kCheckIndex || getKind() == ArrayCallKind::kGetElement || getKind() == ArrayCallKind::kGetElementAddress); return SemanticsCall->getArgument(0); } static bool canHoistArrayArgument(SILValue Arr, SILInstruction *InsertBefore, DominanceInfo *DT) { auto *SelfVal = Arr.getDef(); auto *SelfBB = SelfVal->getParentBB(); if (DT->dominates(SelfBB, InsertBefore->getParent())) return true; if (auto LI = dyn_cast(SelfVal)) { // Are we loading a value from an address in a struct defined at a point // dominating the hoist point. auto Val = LI->getOperand().getDef(); bool DoesNotDominate; StructElementAddrInst *SEI; while ((DoesNotDominate = !DT->dominates(Val->getParentBB(), InsertBefore->getParent())) && (SEI = dyn_cast(Val))) Val = SEI->getOperand().getDef(); return DoesNotDominate == false; } return false; } bool swift::ArraySemanticsCall::canHoist(SILInstruction *InsertBefore, DominanceInfo *DT) { switch (getKind()) { case ArrayCallKind::kCheckSubscript: case ArrayCallKind::kCheckIndex: { return canHoistArrayArgument(getSelf(), InsertBefore, DT); } default: break; } return false; } /// Copy the array load to the insert point. static SILValue copyArrayLoad(SILValue ArrayStructValue, SILInstruction *InsertBefore, DominanceInfo *DT) { if (isa(ArrayStructValue.getDef())) { // Assume that the argument dominates the insert point. assert(DT->dominates(ArrayStructValue.getDef()->getParentBB(), InsertBefore->getParent())); return ArrayStructValue; } auto *LI = cast(ArrayStructValue.getDef()); if (DT->dominates(LI->getParent(), InsertBefore->getParent())) return ArrayStructValue; // Recursively move struct_element_addr. auto *Val = LI->getOperand().getDef(); auto *InsertPt = InsertBefore; while (!DT->dominates(Val->getParentBB(), InsertBefore->getParent())) { auto *Inst = cast(Val); Inst->moveBefore(InsertPt); Val = Inst->getOperand().getDef(); InsertPt = Inst; } return SILValue(LI->clone(InsertBefore), 0); } static ApplyInst *hoistOrCopyCall(ApplyInst *AI, SILInstruction *InsertBefore, bool LeaveOriginal, DominanceInfo *DT) { if (!LeaveOriginal) { AI->moveBefore(InsertBefore); } else { // Leave the original and 'hoist' a clone. AI = cast(AI->clone(InsertBefore)); } placeFuncRef(AI, DT); return AI; } ApplyInst *swift::ArraySemanticsCall::hoistOrCopy(SILInstruction *InsertBefore, DominanceInfo *DT, bool LeaveOriginal) { auto Kind = getKind(); switch (Kind) { case ArrayCallKind::kCheckSubscript: case ArrayCallKind::kCheckIndex: { auto Self = getSelf(); // We are going to have a retain, emit a matching release. if (!LeaveOriginal) SILBuilderWithScope<1>(SemanticsCall) .createReleaseValue(SemanticsCall->getLoc(), Self); // Hoist the array load, if neccessary. SILBuilder B(InsertBefore); auto NewArrayStructValue = copyArrayLoad(Self, InsertBefore, DT); // Retain the array. B.createRetainValue(SemanticsCall->getLoc(), NewArrayStructValue) ->setDebugScope(SemanticsCall->getDebugScope()); auto Call = hoistOrCopyCall(SemanticsCall, InsertBefore, LeaveOriginal, DT); Call->setSelfArgument(NewArrayStructValue); return Call; } case ArrayCallKind::kMakeMutable: { assert(!LeaveOriginal && "Copying not yet implemented"); SemanticsCall->moveBefore(InsertBefore); placeFuncRef(SemanticsCall, DT); return SemanticsCall; } default: llvm_unreachable("Don't know how to hoist this instruction"); break; } // End switch. } void swift::ArraySemanticsCall::replaceByRetainValue() { assert(getKind() < ArrayCallKind::kMakeMutable && "Must be a semantics call that passes the array by value"); SILBuilderWithScope<1>(SemanticsCall) .createReleaseValue(SemanticsCall->getLoc(), getSelf()); SemanticsCall->eraseFromParent(); } /// Remove all instructions in the body of \p BB in safe manner by using /// undef. void swift::clearBlockBody(SILBasicBlock *BB) { // Instructions in the dead block may be used by other dead blocks. Replace // any uses of them with undef values. while (!BB->empty()) { // Grab the last instruction in the BB. auto *Inst = &BB->getInstList().back(); // Replace any non-dead results with SILUndef values. Inst->replaceAllUsesWithUndef(); // Pop the instruction off of the back of the basic block. BB->getInstList().pop_back(); } } // Handle the mechanical aspects of removing an unreachable block. void swift::removeDeadBlock(SILBasicBlock *BB) { // Clear the body of BB. clearBlockBody(BB); // Now that the BB is empty, eliminate it. BB->eraseFromParent(); }