//===--- CFG.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 // //===----------------------------------------------------------------------===// #include "swift/SILOptimizer/Analysis/CFG.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" #include "swift/Demangling/ManglingMacros.h" #include "llvm/ADT/TinyPtrVector.h" using namespace swift; static bool isSafeNonExitTerminator(TermInst *TI) { switch (TI->getTermKind()) { case TermKind::BranchInst: case TermKind::CondBranchInst: case TermKind::SwitchValueInst: case TermKind::SwitchEnumInst: case TermKind::SwitchEnumAddrInst: case TermKind::DynamicMethodBranchInst: case TermKind::CheckedCastBranchInst: case TermKind::CheckedCastValueBranchInst: case TermKind::CheckedCastAddrBranchInst: return true; case TermKind::UnreachableInst: case TermKind::ReturnInst: case TermKind::ThrowInst: case TermKind::UnwindInst: return false; // yield is special because it can do arbitrary, // potentially-process-terminating things. case TermKind::YieldInst: return false; case TermKind::TryApplyInst: return true; } llvm_unreachable("Unhandled TermKind in switch."); } static bool isTrapNoReturnFunction(ApplyInst *AI) { const char *fatalName = MANGLE_AS_STRING(MANGLE_SYM(s18_fatalErrorMessageyys12StaticStringV_AcCSutF)); auto *Fn = AI->getReferencedFunction(); // We use endswith here since if we specialize fatal error we will always // prepend the specialization records to fatalName. if (!Fn || !Fn->getName().endswith(fatalName)) return false; return true; } bool swift:: findAllNonFailureExitBBs(SILFunction *F, llvm::TinyPtrVector &BBs) { for (SILBasicBlock &BB : *F) { TermInst *TI = BB.getTerminator(); // If we know that this terminator is not an exit terminator, continue. if (isSafeNonExitTerminator(TI)) continue; // A return inst is always a non-failure exit bb. if (TI->isFunctionExiting()) { BBs.push_back(&BB); continue; } // If we don't have an unreachable inst at this point, this is a terminator // we don't understand. Be conservative and return false. if (!isa(TI)) return false; // Ok, at this point we know we have a terminator. If it is the only // instruction in our BB, it is a failure BB. continue... if (TI == &*BB.begin()) continue; // If the unreachable is preceded by a no-return apply inst, then it is a // non-failure exit BB. Add it to our list and continue. auto PrevIter = std::prev(SILBasicBlock::iterator(TI)); if (auto *AI = dyn_cast(&*PrevIter)) { if (AI->isCalleeNoReturn() && !isTrapNoReturnFunction(AI)) { BBs.push_back(&BB); continue; } } // Otherwise, it must be a failure BB where we leak, continue. continue; } // We understood all terminators, return true. return true; }