diff --git a/llvm/include/llvm/Transforms/Scalar/SCCP.h b/llvm/include/llvm/Transforms/Scalar/SCCP.h --- a/llvm/include/llvm/Transforms/Scalar/SCCP.h +++ b/llvm/include/llvm/Transforms/Scalar/SCCP.h @@ -40,10 +40,6 @@ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; -bool runIPSCCP(Module &M, const DataLayout &DL, - std::function GetTLI, - function_ref getAnalysis); - bool runFunctionSpecialization( Module &M, const DataLayout &DL, std::function GetTLI, diff --git a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h --- a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h +++ b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h @@ -15,6 +15,8 @@ #define LLVM_TRANSFORMS_UTILS_SCCPSOLVER_H #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Transforms/Utils/PredicateInfo.h" #include @@ -173,6 +175,24 @@ void visitCall(CallInst &I); }; +//===----------------------------------------------------------------------===// +// +/// Helper functions used by the SCCP and IPSCCP passes. +// +bool isConstant(const ValueLatticeElement &LV); + +bool isOverdefined(const ValueLatticeElement &LV); + +bool simplifyInstsInBlock(SCCPSolver &Solver, BasicBlock &BB, + SmallPtrSetImpl &InsertedValues, + Statistic &InstRemovedStat, + Statistic &InstReplacedStat); + +bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V); + +bool removeNonFeasibleEdges(const llvm::SCCPSolver &Solver, BasicBlock *BB, + DomTreeUpdater &DTU, + BasicBlock *&NewUnreachableBB); } // namespace llvm #endif // LLVM_TRANSFORMS_UTILS_SCCPSOLVER_H diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt --- a/llvm/lib/Transforms/IPO/CMakeLists.txt +++ b/llvm/lib/Transforms/IPO/CMakeLists.txt @@ -66,10 +66,8 @@ Linker Object ProfileData - Scalar Support TransformUtils Vectorize Instrumentation - Scalar ) diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -124,20 +124,6 @@ // order across executions. using SpecializationMap = SmallMapVector; -// Helper to check if \p LV is either a constant or a constant -// range with a single element. This should cover exactly the same cases as the -// old ValueLatticeElement::isConstant() and is intended to be used in the -// transition to ValueLatticeElement. -static bool isConstant(const ValueLatticeElement &LV) { - return LV.isConstant() || - (LV.isConstantRange() && LV.getConstantRange().isSingleElement()); -} - -// Helper to check if \p LV is either overdefined or a constant int. -static bool isOverdefined(const ValueLatticeElement &LV) { - return !LV.isUnknownOrUndef() && !isConstant(LV); -} - static Constant *getPromotableAlloca(AllocaInst *Alloca, CallInst *Call) { Value *StoreValue = nullptr; for (auto *User : Alloca->users()) { diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp --- a/llvm/lib/Transforms/IPO/SCCP.cpp +++ b/llvm/lib/Transforms/IPO/SCCP.cpp @@ -11,18 +11,353 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/SCCP.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Analysis/ValueLattice.h" +#include "llvm/Analysis/ValueLatticeUtils.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/InitializePasses.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/Support/ModRef.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar/SCCP.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/SCCPSolver.h" using namespace llvm; +#define DEBUG_TYPE "sccp" + +STATISTIC(NumInstRemoved, "Number of instructions removed"); +STATISTIC(NumArgsElimed ,"Number of arguments constant propagated"); +STATISTIC(NumGlobalConst, "Number of globals found to be constant"); +STATISTIC(NumDeadBlocks , "Number of basic blocks unreachable"); +STATISTIC(NumInstReplaced, + "Number of instructions replaced with (simpler) instruction"); + +static void findReturnsToZap(Function &F, + SmallVector &ReturnsToZap, + SCCPSolver &Solver) { + // We can only do this if we know that nothing else can call the function. + if (!Solver.isArgumentTrackedFunction(&F)) + return; + + if (Solver.mustPreserveReturn(&F)) { + LLVM_DEBUG( + dbgs() + << "Can't zap returns of the function : " << F.getName() + << " due to present musttail or \"clang.arc.attachedcall\" call of " + "it\n"); + return; + } + + assert( + all_of(F.users(), + [&Solver](User *U) { + if (isa(U) && + !Solver.isBlockExecutable(cast(U)->getParent())) + return true; + // Non-callsite uses are not impacted by zapping. Also, constant + // uses (like blockaddresses) could stuck around, without being + // used in the underlying IR, meaning we do not have lattice + // values for them. + if (!isa(U)) + return true; + if (U->getType()->isStructTy()) { + return all_of(Solver.getStructLatticeValueFor(U), + [](const ValueLatticeElement &LV) { + return !isOverdefined(LV); + }); + } + return !isOverdefined(Solver.getLatticeValueFor(U)); + }) && + "We can only zap functions where all live users have a concrete value"); + + for (BasicBlock &BB : F) { + if (CallInst *CI = BB.getTerminatingMustTailCall()) { + LLVM_DEBUG(dbgs() << "Can't zap return of the block due to present " + << "musttail call : " << *CI << "\n"); + (void)CI; + return; + } + + if (auto *RI = dyn_cast(BB.getTerminator())) + if (!isa(RI->getOperand(0))) + ReturnsToZap.push_back(RI); + } +} + +static bool runIPSCCP( + Module &M, const DataLayout &DL, + std::function GetTLI, + function_ref getAnalysis) { + SCCPSolver Solver(DL, GetTLI, M.getContext()); + + // Loop over all functions, marking arguments to those with their addresses + // taken or that are external as overdefined. + for (Function &F : M) { + if (F.isDeclaration()) + continue; + + Solver.addAnalysis(F, getAnalysis(F)); + + // Determine if we can track the function's return values. If so, add the + // function to the solver's set of return-tracked functions. + if (canTrackReturnsInterprocedurally(&F)) + Solver.addTrackedFunction(&F); + + // Determine if we can track the function's arguments. If so, add the + // function to the solver's set of argument-tracked functions. + if (canTrackArgumentsInterprocedurally(&F)) { + Solver.addArgumentTrackedFunction(&F); + continue; + } + + // Assume the function is called. + Solver.markBlockExecutable(&F.front()); + + // Assume nothing about the incoming arguments. + for (Argument &AI : F.args()) + Solver.markOverdefined(&AI); + } + + // Determine if we can track any of the module's global variables. If so, add + // the global variables we can track to the solver's set of tracked global + // variables. + for (GlobalVariable &G : M.globals()) { + G.removeDeadConstantUsers(); + if (canTrackGlobalVariableInterprocedurally(&G)) + Solver.trackValueOfGlobalVariable(&G); + } + + // Solve for constants. + bool ResolvedUndefs = true; + Solver.solve(); + while (ResolvedUndefs) { + LLVM_DEBUG(dbgs() << "RESOLVING UNDEFS\n"); + ResolvedUndefs = false; + for (Function &F : M) { + if (Solver.resolvedUndefsIn(F)) + ResolvedUndefs = true; + } + if (ResolvedUndefs) + Solver.solve(); + } + + bool MadeChanges = false; + + // Iterate over all of the instructions in the module, replacing them with + // constants if we have found them to be of constant values. + + for (Function &F : M) { + if (F.isDeclaration()) + continue; + + SmallVector BlocksToErase; + + if (Solver.isBlockExecutable(&F.front())) { + bool ReplacedPointerArg = false; + for (Argument &Arg : F.args()) { + if (!Arg.use_empty() && tryToReplaceWithConstant(Solver, &Arg)) { + ReplacedPointerArg |= Arg.getType()->isPointerTy(); + ++NumArgsElimed; + } + } + + // If we replaced an argument, we may now also access a global (currently + // classified as "other" memory). Update memory attribute to reflect this. + if (ReplacedPointerArg) { + auto UpdateAttrs = [&](AttributeList AL) { + MemoryEffects ME = AL.getMemoryEffects(); + if (ME == MemoryEffects::unknown()) + return AL; + + ME |= MemoryEffects(MemoryEffects::Other, + ME.getModRef(MemoryEffects::ArgMem)); + return AL.addFnAttribute( + F.getContext(), + Attribute::getWithMemoryEffects(F.getContext(), ME)); + }; + + F.setAttributes(UpdateAttrs(F.getAttributes())); + for (User *U : F.users()) { + auto *CB = dyn_cast(U); + if (!CB || CB->getCalledFunction() != &F) + continue; + + CB->setAttributes(UpdateAttrs(CB->getAttributes())); + } + } + MadeChanges |= ReplacedPointerArg; + } + + SmallPtrSet InsertedValues; + for (BasicBlock &BB : F) { + if (!Solver.isBlockExecutable(&BB)) { + LLVM_DEBUG(dbgs() << " BasicBlock Dead:" << BB); + ++NumDeadBlocks; + + MadeChanges = true; + + if (&BB != &F.front()) + BlocksToErase.push_back(&BB); + continue; + } + + MadeChanges |= simplifyInstsInBlock(Solver, BB, InsertedValues, + NumInstRemoved, NumInstReplaced); + } + + DomTreeUpdater DTU = Solver.getDTU(F); + // Change dead blocks to unreachable. We do it after replacing constants + // in all executable blocks, because changeToUnreachable may remove PHI + // nodes in executable blocks we found values for. The function's entry + // block is not part of BlocksToErase, so we have to handle it separately. + for (BasicBlock *BB : BlocksToErase) { + NumInstRemoved += changeToUnreachable(BB->getFirstNonPHI(), + /*PreserveLCSSA=*/false, &DTU); + } + if (!Solver.isBlockExecutable(&F.front())) + NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHI(), + /*PreserveLCSSA=*/false, &DTU); + + BasicBlock *NewUnreachableBB = nullptr; + for (BasicBlock &BB : F) + MadeChanges |= removeNonFeasibleEdges(Solver, &BB, DTU, NewUnreachableBB); + + for (BasicBlock *DeadBB : BlocksToErase) + if (!DeadBB->hasAddressTaken()) + DTU.deleteBB(DeadBB); + + for (BasicBlock &BB : F) { + for (Instruction &Inst : llvm::make_early_inc_range(BB)) { + if (Solver.getPredicateInfoFor(&Inst)) { + if (auto *II = dyn_cast(&Inst)) { + if (II->getIntrinsicID() == Intrinsic::ssa_copy) { + Value *Op = II->getOperand(0); + Inst.replaceAllUsesWith(Op); + Inst.eraseFromParent(); + } + } + } + } + } + } + + // If we inferred constant or undef return values for a function, we replaced + // all call uses with the inferred value. This means we don't need to bother + // actually returning anything from the function. Replace all return + // instructions with return undef. + // + // Do this in two stages: first identify the functions we should process, then + // actually zap their returns. This is important because we can only do this + // if the address of the function isn't taken. In cases where a return is the + // last use of a function, the order of processing functions would affect + // whether other functions are optimizable. + SmallVector ReturnsToZap; + + for (const auto &I : Solver.getTrackedRetVals()) { + Function *F = I.first; + const ValueLatticeElement &ReturnValue = I.second; + + // If there is a known constant range for the return value, add !range + // metadata to the function's call sites. + if (ReturnValue.isConstantRange() && + !ReturnValue.getConstantRange().isSingleElement()) { + // Do not add range metadata if the return value may include undef. + if (ReturnValue.isConstantRangeIncludingUndef()) + continue; + + auto &CR = ReturnValue.getConstantRange(); + for (User *User : F->users()) { + auto *CB = dyn_cast(User); + if (!CB || CB->getCalledFunction() != F) + continue; + + // Limit to cases where the return value is guaranteed to be neither + // poison nor undef. Poison will be outside any range and currently + // values outside of the specified range cause immediate undefined + // behavior. + if (!isGuaranteedNotToBeUndefOrPoison(CB, nullptr, CB)) + continue; + + // Do not touch existing metadata for now. + // TODO: We should be able to take the intersection of the existing + // metadata and the inferred range. + if (CB->getMetadata(LLVMContext::MD_range)) + continue; + + LLVMContext &Context = CB->getParent()->getContext(); + Metadata *RangeMD[] = { + ConstantAsMetadata::get(ConstantInt::get(Context, CR.getLower())), + ConstantAsMetadata::get(ConstantInt::get(Context, CR.getUpper()))}; + CB->setMetadata(LLVMContext::MD_range, MDNode::get(Context, RangeMD)); + } + continue; + } + if (F->getReturnType()->isVoidTy()) + continue; + if (isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef()) + findReturnsToZap(*F, ReturnsToZap, Solver); + } + + for (auto *F : Solver.getMRVFunctionsTracked()) { + assert(F->getReturnType()->isStructTy() && + "The return type should be a struct"); + StructType *STy = cast(F->getReturnType()); + if (Solver.isStructLatticeConstant(F, STy)) + findReturnsToZap(*F, ReturnsToZap, Solver); + } + + // Zap all returns which we've identified as zap to change. + SmallSetVector FuncZappedReturn; + for (ReturnInst *RI : ReturnsToZap) { + Function *F = RI->getParent()->getParent(); + RI->setOperand(0, UndefValue::get(F->getReturnType())); + // Record all functions that are zapped. + FuncZappedReturn.insert(F); + } + + // Remove the returned attribute for zapped functions and the + // corresponding call sites. + for (Function *F : FuncZappedReturn) { + for (Argument &A : F->args()) + F->removeParamAttr(A.getArgNo(), Attribute::Returned); + for (Use &U : F->uses()) { + // Skip over blockaddr users. + if (isa(U.getUser())) + continue; + CallBase *CB = cast(U.getUser()); + for (Use &Arg : CB->args()) + CB->removeParamAttr(CB->getArgOperandNo(&Arg), Attribute::Returned); + } + } + + // If we inferred constant or undef values for globals variables, we can + // delete the global and any stores that remain to it. + for (const auto &I : make_early_inc_range(Solver.getTrackedGlobals())) { + GlobalVariable *GV = I.first; + if (isOverdefined(I.second)) + continue; + LLVM_DEBUG(dbgs() << "Found that GV '" << GV->getName() + << "' is constant!\n"); + while (!GV->use_empty()) { + StoreInst *SI = cast(GV->user_back()); + SI->eraseFromParent(); + MadeChanges = true; + } + M.getGlobalList().erase(GV); + ++NumGlobalConst; + } + + return MadeChanges; +} + PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) { const DataLayout &DL = M.getDataLayout(); auto &FAM = AM.getResult(M).getManager(); diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -27,19 +27,15 @@ #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Analysis/ValueLattice.h" -#include "llvm/Analysis/ValueLatticeUtils.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" -#include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" @@ -67,182 +63,6 @@ STATISTIC(NumInstReplaced, "Number of instructions replaced with (simpler) instruction"); -STATISTIC(IPNumInstRemoved, "Number of instructions removed by IPSCCP"); -STATISTIC(IPNumArgsElimed ,"Number of arguments constant propagated by IPSCCP"); -STATISTIC(IPNumGlobalConst, "Number of globals found to be constant by IPSCCP"); -STATISTIC( - IPNumInstReplaced, - "Number of instructions replaced with (simpler) instruction by IPSCCP"); - -// Helper to check if \p LV is either a constant or a constant -// range with a single element. This should cover exactly the same cases as the -// old ValueLatticeElement::isConstant() and is intended to be used in the -// transition to ValueLatticeElement. -static bool isConstant(const ValueLatticeElement &LV) { - return LV.isConstant() || - (LV.isConstantRange() && LV.getConstantRange().isSingleElement()); -} - -// Helper to check if \p LV is either overdefined or a constant range with more -// than a single element. This should cover exactly the same cases as the old -// ValueLatticeElement::isOverdefined() and is intended to be used in the -// transition to ValueLatticeElement. -static bool isOverdefined(const ValueLatticeElement &LV) { - return !LV.isUnknownOrUndef() && !isConstant(LV); -} - -static bool canRemoveInstruction(Instruction *I) { - if (wouldInstructionBeTriviallyDead(I)) - return true; - - // Some instructions can be handled but are rejected above. Catch - // those cases by falling through to here. - // TODO: Mark globals as being constant earlier, so - // TODO: wouldInstructionBeTriviallyDead() knows that atomic loads - // TODO: are safe to remove. - return isa(I); -} - -static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) { - Constant *Const = nullptr; - if (V->getType()->isStructTy()) { - std::vector IVs = Solver.getStructLatticeValueFor(V); - if (llvm::any_of(IVs, isOverdefined)) - return false; - std::vector ConstVals; - auto *ST = cast(V->getType()); - for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) { - ValueLatticeElement V = IVs[i]; - ConstVals.push_back(isConstant(V) - ? Solver.getConstant(V) - : UndefValue::get(ST->getElementType(i))); - } - Const = ConstantStruct::get(ST, ConstVals); - } else { - const ValueLatticeElement &IV = Solver.getLatticeValueFor(V); - if (isOverdefined(IV)) - return false; - - Const = - isConstant(IV) ? Solver.getConstant(IV) : UndefValue::get(V->getType()); - } - assert(Const && "Constant is nullptr here!"); - - // Replacing `musttail` instructions with constant breaks `musttail` invariant - // unless the call itself can be removed. - // Calls with "clang.arc.attachedcall" implicitly use the return value and - // those uses cannot be updated with a constant. - CallBase *CB = dyn_cast(V); - if (CB && ((CB->isMustTailCall() && - !canRemoveInstruction(CB)) || - CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall))) { - Function *F = CB->getCalledFunction(); - - // Don't zap returns of the callee - if (F) - Solver.addToMustPreserveReturnsInFunctions(F); - - LLVM_DEBUG(dbgs() << " Can\'t treat the result of call " << *CB - << " as a constant\n"); - return false; - } - - LLVM_DEBUG(dbgs() << " Constant: " << *Const << " = " << *V << '\n'); - - // Replaces all of the uses of a variable with uses of the constant. - V->replaceAllUsesWith(Const); - return true; -} - -/// Try to replace signed instructions with their unsigned equivalent. -static bool replaceSignedInst(SCCPSolver &Solver, - SmallPtrSetImpl &InsertedValues, - Instruction &Inst) { - // Determine if a signed value is known to be >= 0. - auto isNonNegative = [&Solver](Value *V) { - // If this value was constant-folded, it may not have a solver entry. - // Handle integers. Otherwise, return false. - if (auto *C = dyn_cast(V)) { - auto *CInt = dyn_cast(C); - return CInt && !CInt->isNegative(); - } - const ValueLatticeElement &IV = Solver.getLatticeValueFor(V); - return IV.isConstantRange(/*UndefAllowed=*/false) && - IV.getConstantRange().isAllNonNegative(); - }; - - Instruction *NewInst = nullptr; - switch (Inst.getOpcode()) { - // Note: We do not fold sitofp -> uitofp here because that could be more - // expensive in codegen and may not be reversible in the backend. - case Instruction::SExt: { - // If the source value is not negative, this is a zext. - Value *Op0 = Inst.getOperand(0); - if (InsertedValues.count(Op0) || !isNonNegative(Op0)) - return false; - NewInst = new ZExtInst(Op0, Inst.getType(), "", &Inst); - break; - } - case Instruction::AShr: { - // If the shifted value is not negative, this is a logical shift right. - Value *Op0 = Inst.getOperand(0); - if (InsertedValues.count(Op0) || !isNonNegative(Op0)) - return false; - NewInst = BinaryOperator::CreateLShr(Op0, Inst.getOperand(1), "", &Inst); - break; - } - case Instruction::SDiv: - case Instruction::SRem: { - // If both operands are not negative, this is the same as udiv/urem. - Value *Op0 = Inst.getOperand(0), *Op1 = Inst.getOperand(1); - if (InsertedValues.count(Op0) || InsertedValues.count(Op1) || - !isNonNegative(Op0) || !isNonNegative(Op1)) - return false; - auto NewOpcode = Inst.getOpcode() == Instruction::SDiv ? Instruction::UDiv - : Instruction::URem; - NewInst = BinaryOperator::Create(NewOpcode, Op0, Op1, "", &Inst); - break; - } - default: - return false; - } - - // Wire up the new instruction and update state. - assert(NewInst && "Expected replacement instruction"); - NewInst->takeName(&Inst); - InsertedValues.insert(NewInst); - Inst.replaceAllUsesWith(NewInst); - Solver.removeLatticeValueFor(&Inst); - Inst.eraseFromParent(); - return true; -} - -static bool simplifyInstsInBlock(SCCPSolver &Solver, BasicBlock &BB, - SmallPtrSetImpl &InsertedValues, - Statistic &InstRemovedStat, - Statistic &InstReplacedStat) { - bool MadeChanges = false; - for (Instruction &Inst : make_early_inc_range(BB)) { - if (Inst.getType()->isVoidTy()) - continue; - if (tryToReplaceWithConstant(Solver, &Inst)) { - if (canRemoveInstruction(&Inst)) - Inst.eraseFromParent(); - - MadeChanges = true; - ++InstRemovedStat; - } else if (replaceSignedInst(Solver, InsertedValues, Inst)) { - MadeChanges = true; - ++InstReplacedStat; - } - } - return MadeChanges; -} - -static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB, - DomTreeUpdater &DTU, - BasicBlock *&NewUnreachableBB); - // runSCCP() - Run the Sparse Conditional Constant Propagation algorithm, // and return true if the function was modified. static bool runSCCP(Function &F, const DataLayout &DL, @@ -367,414 +187,3 @@ // createSCCPPass - This is the public interface to this file. FunctionPass *llvm::createSCCPPass() { return new SCCPLegacyPass(); } -static void findReturnsToZap(Function &F, - SmallVector &ReturnsToZap, - SCCPSolver &Solver) { - // We can only do this if we know that nothing else can call the function. - if (!Solver.isArgumentTrackedFunction(&F)) - return; - - if (Solver.mustPreserveReturn(&F)) { - LLVM_DEBUG( - dbgs() - << "Can't zap returns of the function : " << F.getName() - << " due to present musttail or \"clang.arc.attachedcall\" call of " - "it\n"); - return; - } - - assert( - all_of(F.users(), - [&Solver](User *U) { - if (isa(U) && - !Solver.isBlockExecutable(cast(U)->getParent())) - return true; - // Non-callsite uses are not impacted by zapping. Also, constant - // uses (like blockaddresses) could stuck around, without being - // used in the underlying IR, meaning we do not have lattice - // values for them. - if (!isa(U)) - return true; - if (U->getType()->isStructTy()) { - return all_of(Solver.getStructLatticeValueFor(U), - [](const ValueLatticeElement &LV) { - return !isOverdefined(LV); - }); - } - return !isOverdefined(Solver.getLatticeValueFor(U)); - }) && - "We can only zap functions where all live users have a concrete value"); - - for (BasicBlock &BB : F) { - if (CallInst *CI = BB.getTerminatingMustTailCall()) { - LLVM_DEBUG(dbgs() << "Can't zap return of the block due to present " - << "musttail call : " << *CI << "\n"); - (void)CI; - return; - } - - if (auto *RI = dyn_cast(BB.getTerminator())) - if (!isa(RI->getOperand(0))) - ReturnsToZap.push_back(RI); - } -} - -static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB, - DomTreeUpdater &DTU, - BasicBlock *&NewUnreachableBB) { - SmallPtrSet FeasibleSuccessors; - bool HasNonFeasibleEdges = false; - for (BasicBlock *Succ : successors(BB)) { - if (Solver.isEdgeFeasible(BB, Succ)) - FeasibleSuccessors.insert(Succ); - else - HasNonFeasibleEdges = true; - } - - // All edges feasible, nothing to do. - if (!HasNonFeasibleEdges) - return false; - - // SCCP can only determine non-feasible edges for br, switch and indirectbr. - Instruction *TI = BB->getTerminator(); - assert((isa(TI) || isa(TI) || - isa(TI)) && - "Terminator must be a br, switch or indirectbr"); - - if (FeasibleSuccessors.size() == 0) { - // Branch on undef/poison, replace with unreachable. - SmallPtrSet SeenSuccs; - SmallVector Updates; - for (BasicBlock *Succ : successors(BB)) { - Succ->removePredecessor(BB); - if (SeenSuccs.insert(Succ).second) - Updates.push_back({DominatorTree::Delete, BB, Succ}); - } - TI->eraseFromParent(); - new UnreachableInst(BB->getContext(), BB); - DTU.applyUpdatesPermissive(Updates); - } else if (FeasibleSuccessors.size() == 1) { - // Replace with an unconditional branch to the only feasible successor. - BasicBlock *OnlyFeasibleSuccessor = *FeasibleSuccessors.begin(); - SmallVector Updates; - bool HaveSeenOnlyFeasibleSuccessor = false; - for (BasicBlock *Succ : successors(BB)) { - if (Succ == OnlyFeasibleSuccessor && !HaveSeenOnlyFeasibleSuccessor) { - // Don't remove the edge to the only feasible successor the first time - // we see it. We still do need to remove any multi-edges to it though. - HaveSeenOnlyFeasibleSuccessor = true; - continue; - } - - Succ->removePredecessor(BB); - Updates.push_back({DominatorTree::Delete, BB, Succ}); - } - - BranchInst::Create(OnlyFeasibleSuccessor, BB); - TI->eraseFromParent(); - DTU.applyUpdatesPermissive(Updates); - } else if (FeasibleSuccessors.size() > 1) { - SwitchInstProfUpdateWrapper SI(*cast(TI)); - SmallVector Updates; - - // If the default destination is unfeasible it will never be taken. Replace - // it with a new block with a single Unreachable instruction. - BasicBlock *DefaultDest = SI->getDefaultDest(); - if (!FeasibleSuccessors.contains(DefaultDest)) { - if (!NewUnreachableBB) { - NewUnreachableBB = - BasicBlock::Create(DefaultDest->getContext(), "default.unreachable", - DefaultDest->getParent(), DefaultDest); - new UnreachableInst(DefaultDest->getContext(), NewUnreachableBB); - } - - SI->setDefaultDest(NewUnreachableBB); - Updates.push_back({DominatorTree::Delete, BB, DefaultDest}); - Updates.push_back({DominatorTree::Insert, BB, NewUnreachableBB}); - } - - for (auto CI = SI->case_begin(); CI != SI->case_end();) { - if (FeasibleSuccessors.contains(CI->getCaseSuccessor())) { - ++CI; - continue; - } - - BasicBlock *Succ = CI->getCaseSuccessor(); - Succ->removePredecessor(BB); - Updates.push_back({DominatorTree::Delete, BB, Succ}); - SI.removeCase(CI); - // Don't increment CI, as we removed a case. - } - - DTU.applyUpdatesPermissive(Updates); - } else { - llvm_unreachable("Must have at least one feasible successor"); - } - return true; -} - -bool llvm::runIPSCCP( - Module &M, const DataLayout &DL, - std::function GetTLI, - function_ref getAnalysis) { - SCCPSolver Solver(DL, GetTLI, M.getContext()); - - // Loop over all functions, marking arguments to those with their addresses - // taken or that are external as overdefined. - for (Function &F : M) { - if (F.isDeclaration()) - continue; - - Solver.addAnalysis(F, getAnalysis(F)); - - // Determine if we can track the function's return values. If so, add the - // function to the solver's set of return-tracked functions. - if (canTrackReturnsInterprocedurally(&F)) - Solver.addTrackedFunction(&F); - - // Determine if we can track the function's arguments. If so, add the - // function to the solver's set of argument-tracked functions. - if (canTrackArgumentsInterprocedurally(&F)) { - Solver.addArgumentTrackedFunction(&F); - continue; - } - - // Assume the function is called. - Solver.markBlockExecutable(&F.front()); - - // Assume nothing about the incoming arguments. - for (Argument &AI : F.args()) - Solver.markOverdefined(&AI); - } - - // Determine if we can track any of the module's global variables. If so, add - // the global variables we can track to the solver's set of tracked global - // variables. - for (GlobalVariable &G : M.globals()) { - G.removeDeadConstantUsers(); - if (canTrackGlobalVariableInterprocedurally(&G)) - Solver.trackValueOfGlobalVariable(&G); - } - - // Solve for constants. - bool ResolvedUndefs = true; - Solver.solve(); - while (ResolvedUndefs) { - LLVM_DEBUG(dbgs() << "RESOLVING UNDEFS\n"); - ResolvedUndefs = false; - for (Function &F : M) { - if (Solver.resolvedUndefsIn(F)) - ResolvedUndefs = true; - } - if (ResolvedUndefs) - Solver.solve(); - } - - bool MadeChanges = false; - - // Iterate over all of the instructions in the module, replacing them with - // constants if we have found them to be of constant values. - - for (Function &F : M) { - if (F.isDeclaration()) - continue; - - SmallVector BlocksToErase; - - if (Solver.isBlockExecutable(&F.front())) { - bool ReplacedPointerArg = false; - for (Argument &Arg : F.args()) { - if (!Arg.use_empty() && tryToReplaceWithConstant(Solver, &Arg)) { - ReplacedPointerArg |= Arg.getType()->isPointerTy(); - ++IPNumArgsElimed; - } - } - - // If we replaced an argument, we may now also access a global (currently - // classified as "other" memory). Update memory attribute to reflect this. - if (ReplacedPointerArg) { - auto UpdateAttrs = [&](AttributeList AL) { - MemoryEffects ME = AL.getMemoryEffects(); - if (ME == MemoryEffects::unknown()) - return AL; - - ME |= MemoryEffects(MemoryEffects::Other, - ME.getModRef(MemoryEffects::ArgMem)); - return AL.addFnAttribute( - F.getContext(), - Attribute::getWithMemoryEffects(F.getContext(), ME)); - }; - - F.setAttributes(UpdateAttrs(F.getAttributes())); - for (User *U : F.users()) { - auto *CB = dyn_cast(U); - if (!CB || CB->getCalledFunction() != &F) - continue; - - CB->setAttributes(UpdateAttrs(CB->getAttributes())); - } - } - MadeChanges |= ReplacedPointerArg; - } - - SmallPtrSet InsertedValues; - for (BasicBlock &BB : F) { - if (!Solver.isBlockExecutable(&BB)) { - LLVM_DEBUG(dbgs() << " BasicBlock Dead:" << BB); - ++NumDeadBlocks; - - MadeChanges = true; - - if (&BB != &F.front()) - BlocksToErase.push_back(&BB); - continue; - } - - MadeChanges |= simplifyInstsInBlock(Solver, BB, InsertedValues, - IPNumInstRemoved, IPNumInstReplaced); - } - - DomTreeUpdater DTU = Solver.getDTU(F); - // Change dead blocks to unreachable. We do it after replacing constants - // in all executable blocks, because changeToUnreachable may remove PHI - // nodes in executable blocks we found values for. The function's entry - // block is not part of BlocksToErase, so we have to handle it separately. - for (BasicBlock *BB : BlocksToErase) { - NumInstRemoved += changeToUnreachable(BB->getFirstNonPHI(), - /*PreserveLCSSA=*/false, &DTU); - } - if (!Solver.isBlockExecutable(&F.front())) - NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHI(), - /*PreserveLCSSA=*/false, &DTU); - - BasicBlock *NewUnreachableBB = nullptr; - for (BasicBlock &BB : F) - MadeChanges |= removeNonFeasibleEdges(Solver, &BB, DTU, NewUnreachableBB); - - for (BasicBlock *DeadBB : BlocksToErase) - if (!DeadBB->hasAddressTaken()) - DTU.deleteBB(DeadBB); - - for (BasicBlock &BB : F) { - for (Instruction &Inst : llvm::make_early_inc_range(BB)) { - if (Solver.getPredicateInfoFor(&Inst)) { - if (auto *II = dyn_cast(&Inst)) { - if (II->getIntrinsicID() == Intrinsic::ssa_copy) { - Value *Op = II->getOperand(0); - Inst.replaceAllUsesWith(Op); - Inst.eraseFromParent(); - } - } - } - } - } - } - - // If we inferred constant or undef return values for a function, we replaced - // all call uses with the inferred value. This means we don't need to bother - // actually returning anything from the function. Replace all return - // instructions with return undef. - // - // Do this in two stages: first identify the functions we should process, then - // actually zap their returns. This is important because we can only do this - // if the address of the function isn't taken. In cases where a return is the - // last use of a function, the order of processing functions would affect - // whether other functions are optimizable. - SmallVector ReturnsToZap; - - for (const auto &I : Solver.getTrackedRetVals()) { - Function *F = I.first; - const ValueLatticeElement &ReturnValue = I.second; - - // If there is a known constant range for the return value, add !range - // metadata to the function's call sites. - if (ReturnValue.isConstantRange() && - !ReturnValue.getConstantRange().isSingleElement()) { - // Do not add range metadata if the return value may include undef. - if (ReturnValue.isConstantRangeIncludingUndef()) - continue; - - auto &CR = ReturnValue.getConstantRange(); - for (User *User : F->users()) { - auto *CB = dyn_cast(User); - if (!CB || CB->getCalledFunction() != F) - continue; - - // Limit to cases where the return value is guaranteed to be neither - // poison nor undef. Poison will be outside any range and currently - // values outside of the specified range cause immediate undefined - // behavior. - if (!isGuaranteedNotToBeUndefOrPoison(CB, nullptr, CB)) - continue; - - // Do not touch existing metadata for now. - // TODO: We should be able to take the intersection of the existing - // metadata and the inferred range. - if (CB->getMetadata(LLVMContext::MD_range)) - continue; - - LLVMContext &Context = CB->getParent()->getContext(); - Metadata *RangeMD[] = { - ConstantAsMetadata::get(ConstantInt::get(Context, CR.getLower())), - ConstantAsMetadata::get(ConstantInt::get(Context, CR.getUpper()))}; - CB->setMetadata(LLVMContext::MD_range, MDNode::get(Context, RangeMD)); - } - continue; - } - if (F->getReturnType()->isVoidTy()) - continue; - if (isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef()) - findReturnsToZap(*F, ReturnsToZap, Solver); - } - - for (auto *F : Solver.getMRVFunctionsTracked()) { - assert(F->getReturnType()->isStructTy() && - "The return type should be a struct"); - StructType *STy = cast(F->getReturnType()); - if (Solver.isStructLatticeConstant(F, STy)) - findReturnsToZap(*F, ReturnsToZap, Solver); - } - - // Zap all returns which we've identified as zap to change. - SmallSetVector FuncZappedReturn; - for (ReturnInst *RI : ReturnsToZap) { - Function *F = RI->getParent()->getParent(); - RI->setOperand(0, UndefValue::get(F->getReturnType())); - // Record all functions that are zapped. - FuncZappedReturn.insert(F); - } - - // Remove the returned attribute for zapped functions and the - // corresponding call sites. - for (Function *F : FuncZappedReturn) { - for (Argument &A : F->args()) - F->removeParamAttr(A.getArgNo(), Attribute::Returned); - for (Use &U : F->uses()) { - // Skip over blockaddr users. - if (isa(U.getUser())) - continue; - CallBase *CB = cast(U.getUser()); - for (Use &Arg : CB->args()) - CB->removeParamAttr(CB->getArgOperandNo(&Arg), Attribute::Returned); - } - } - - // If we inferred constant or undef values for globals variables, we can - // delete the global and any stores that remain to it. - for (const auto &I : make_early_inc_range(Solver.getTrackedGlobals())) { - GlobalVariable *GV = I.first; - if (isOverdefined(I.second)) - continue; - LLVM_DEBUG(dbgs() << "Found that GV '" << GV->getName() - << "' is constant!\n"); - while (!GV->use_empty()) { - StoreInst *SI = cast(GV->user_back()); - SI->eraseFromParent(); - MadeChanges = true; - } - M.getGlobalList().erase(GV); - ++IPNumGlobalConst; - } - - return MadeChanges; -} diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp --- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -16,11 +16,13 @@ #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ValueLattice.h" +#include "llvm/Analysis/ValueLatticeUtils.h" #include "llvm/IR/InstVisitor.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/Local.h" #include #include #include @@ -39,7 +41,7 @@ MaxNumRangeExtensions); } -namespace { +namespace llvm { // Helper to check if \p LV is either a constant or a constant // range with a single element. This should cover exactly the same cases as the @@ -58,9 +60,247 @@ return !LV.isUnknownOrUndef() && !isConstant(LV); } -} // namespace +static bool canRemoveInstruction(Instruction *I) { + if (wouldInstructionBeTriviallyDead(I)) + return true; -namespace llvm { + // Some instructions can be handled but are rejected above. Catch + // those cases by falling through to here. + // TODO: Mark globals as being constant earlier, so + // TODO: wouldInstructionBeTriviallyDead() knows that atomic loads + // TODO: are safe to remove. + return isa(I); +} + +bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) { + Constant *Const = nullptr; + if (V->getType()->isStructTy()) { + std::vector IVs = Solver.getStructLatticeValueFor(V); + if (llvm::any_of(IVs, isOverdefined)) + return false; + std::vector ConstVals; + auto *ST = cast(V->getType()); + for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) { + ValueLatticeElement V = IVs[i]; + ConstVals.push_back(isConstant(V) + ? Solver.getConstant(V) + : UndefValue::get(ST->getElementType(i))); + } + Const = ConstantStruct::get(ST, ConstVals); + } else { + const ValueLatticeElement &IV = Solver.getLatticeValueFor(V); + if (isOverdefined(IV)) + return false; + + Const = + isConstant(IV) ? Solver.getConstant(IV) : UndefValue::get(V->getType()); + } + assert(Const && "Constant is nullptr here!"); + + // Replacing `musttail` instructions with constant breaks `musttail` invariant + // unless the call itself can be removed. + // Calls with "clang.arc.attachedcall" implicitly use the return value and + // those uses cannot be updated with a constant. + CallBase *CB = dyn_cast(V); + if (CB && ((CB->isMustTailCall() && + !canRemoveInstruction(CB)) || + CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall))) { + Function *F = CB->getCalledFunction(); + + // Don't zap returns of the callee + if (F) + Solver.addToMustPreserveReturnsInFunctions(F); + + LLVM_DEBUG(dbgs() << " Can\'t treat the result of call " << *CB + << " as a constant\n"); + return false; + } + + LLVM_DEBUG(dbgs() << " Constant: " << *Const << " = " << *V << '\n'); + + // Replaces all of the uses of a variable with uses of the constant. + V->replaceAllUsesWith(Const); + return true; +} + +/// Try to replace signed instructions with their unsigned equivalent. +static bool replaceSignedInst(SCCPSolver &Solver, + SmallPtrSetImpl &InsertedValues, + Instruction &Inst) { + // Determine if a signed value is known to be >= 0. + auto isNonNegative = [&Solver](Value *V) { + // If this value was constant-folded, it may not have a solver entry. + // Handle integers. Otherwise, return false. + if (auto *C = dyn_cast(V)) { + auto *CInt = dyn_cast(C); + return CInt && !CInt->isNegative(); + } + const ValueLatticeElement &IV = Solver.getLatticeValueFor(V); + return IV.isConstantRange(/*UndefAllowed=*/false) && + IV.getConstantRange().isAllNonNegative(); + }; + + Instruction *NewInst = nullptr; + switch (Inst.getOpcode()) { + // Note: We do not fold sitofp -> uitofp here because that could be more + // expensive in codegen and may not be reversible in the backend. + case Instruction::SExt: { + // If the source value is not negative, this is a zext. + Value *Op0 = Inst.getOperand(0); + if (InsertedValues.count(Op0) || !isNonNegative(Op0)) + return false; + NewInst = new ZExtInst(Op0, Inst.getType(), "", &Inst); + break; + } + case Instruction::AShr: { + // If the shifted value is not negative, this is a logical shift right. + Value *Op0 = Inst.getOperand(0); + if (InsertedValues.count(Op0) || !isNonNegative(Op0)) + return false; + NewInst = BinaryOperator::CreateLShr(Op0, Inst.getOperand(1), "", &Inst); + break; + } + case Instruction::SDiv: + case Instruction::SRem: { + // If both operands are not negative, this is the same as udiv/urem. + Value *Op0 = Inst.getOperand(0), *Op1 = Inst.getOperand(1); + if (InsertedValues.count(Op0) || InsertedValues.count(Op1) || + !isNonNegative(Op0) || !isNonNegative(Op1)) + return false; + auto NewOpcode = Inst.getOpcode() == Instruction::SDiv ? Instruction::UDiv + : Instruction::URem; + NewInst = BinaryOperator::Create(NewOpcode, Op0, Op1, "", &Inst); + break; + } + default: + return false; + } + + // Wire up the new instruction and update state. + assert(NewInst && "Expected replacement instruction"); + NewInst->takeName(&Inst); + InsertedValues.insert(NewInst); + Inst.replaceAllUsesWith(NewInst); + Solver.removeLatticeValueFor(&Inst); + Inst.eraseFromParent(); + return true; +} + +bool simplifyInstsInBlock(SCCPSolver &Solver, BasicBlock &BB, + SmallPtrSetImpl &InsertedValues, + Statistic &InstRemovedStat, + Statistic &InstReplacedStat) { + bool MadeChanges = false; + for (Instruction &Inst : make_early_inc_range(BB)) { + if (Inst.getType()->isVoidTy()) + continue; + if (tryToReplaceWithConstant(Solver, &Inst)) { + if (canRemoveInstruction(&Inst)) + Inst.eraseFromParent(); + + MadeChanges = true; + ++InstRemovedStat; + } else if (replaceSignedInst(Solver, InsertedValues, Inst)) { + MadeChanges = true; + ++InstReplacedStat; + } + } + return MadeChanges; +} + +bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB, + DomTreeUpdater &DTU, + BasicBlock *&NewUnreachableBB) { + SmallPtrSet FeasibleSuccessors; + bool HasNonFeasibleEdges = false; + for (BasicBlock *Succ : successors(BB)) { + if (Solver.isEdgeFeasible(BB, Succ)) + FeasibleSuccessors.insert(Succ); + else + HasNonFeasibleEdges = true; + } + + // All edges feasible, nothing to do. + if (!HasNonFeasibleEdges) + return false; + + // SCCP can only determine non-feasible edges for br, switch and indirectbr. + Instruction *TI = BB->getTerminator(); + assert((isa(TI) || isa(TI) || + isa(TI)) && + "Terminator must be a br, switch or indirectbr"); + + if (FeasibleSuccessors.size() == 0) { + // Branch on undef/poison, replace with unreachable. + SmallPtrSet SeenSuccs; + SmallVector Updates; + for (BasicBlock *Succ : successors(BB)) { + Succ->removePredecessor(BB); + if (SeenSuccs.insert(Succ).second) + Updates.push_back({DominatorTree::Delete, BB, Succ}); + } + TI->eraseFromParent(); + new UnreachableInst(BB->getContext(), BB); + DTU.applyUpdatesPermissive(Updates); + } else if (FeasibleSuccessors.size() == 1) { + // Replace with an unconditional branch to the only feasible successor. + BasicBlock *OnlyFeasibleSuccessor = *FeasibleSuccessors.begin(); + SmallVector Updates; + bool HaveSeenOnlyFeasibleSuccessor = false; + for (BasicBlock *Succ : successors(BB)) { + if (Succ == OnlyFeasibleSuccessor && !HaveSeenOnlyFeasibleSuccessor) { + // Don't remove the edge to the only feasible successor the first time + // we see it. We still do need to remove any multi-edges to it though. + HaveSeenOnlyFeasibleSuccessor = true; + continue; + } + + Succ->removePredecessor(BB); + Updates.push_back({DominatorTree::Delete, BB, Succ}); + } + + BranchInst::Create(OnlyFeasibleSuccessor, BB); + TI->eraseFromParent(); + DTU.applyUpdatesPermissive(Updates); + } else if (FeasibleSuccessors.size() > 1) { + SwitchInstProfUpdateWrapper SI(*cast(TI)); + SmallVector Updates; + + // If the default destination is unfeasible it will never be taken. Replace + // it with a new block with a single Unreachable instruction. + BasicBlock *DefaultDest = SI->getDefaultDest(); + if (!FeasibleSuccessors.contains(DefaultDest)) { + if (!NewUnreachableBB) { + NewUnreachableBB = + BasicBlock::Create(DefaultDest->getContext(), "default.unreachable", + DefaultDest->getParent(), DefaultDest); + new UnreachableInst(DefaultDest->getContext(), NewUnreachableBB); + } + + SI->setDefaultDest(NewUnreachableBB); + Updates.push_back({DominatorTree::Delete, BB, DefaultDest}); + Updates.push_back({DominatorTree::Insert, BB, NewUnreachableBB}); + } + + for (auto CI = SI->case_begin(); CI != SI->case_end();) { + if (FeasibleSuccessors.contains(CI->getCaseSuccessor())) { + ++CI; + continue; + } + + BasicBlock *Succ = CI->getCaseSuccessor(); + Succ->removePredecessor(BB); + Updates.push_back({DominatorTree::Delete, BB, Succ}); + SI.removeCase(CI); + // Don't increment CI, as we removed a case. + } + + DTU.applyUpdatesPermissive(Updates); + } else { + llvm_unreachable("Must have at least one feasible successor"); + } + return true; +} /// Helper class for SCCPSolver. This implements the instruction visitor and /// holds all the state. diff --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/IPO/BUILD.gn @@ -14,7 +14,6 @@ "//llvm/lib/Transforms/AggressiveInstCombine", "//llvm/lib/Transforms/InstCombine", "//llvm/lib/Transforms/Instrumentation", - "//llvm/lib/Transforms/Scalar", "//llvm/lib/Transforms/Utils", "//llvm/lib/Transforms/Vectorize", ]