18bcb0991SDimitry Andric //===- LowerConstantIntrinsics.cpp - Lower constant intrinsic calls -------===// 28bcb0991SDimitry Andric // 38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68bcb0991SDimitry Andric // 78bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 88bcb0991SDimitry Andric // 98bcb0991SDimitry Andric // This pass lowers all remaining 'objectsize' 'is.constant' intrinsic calls 108bcb0991SDimitry Andric // and provides constant propagation and basic CFG cleanup on the result. 118bcb0991SDimitry Andric // 128bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 138bcb0991SDimitry Andric 148bcb0991SDimitry Andric #include "llvm/Transforms/Scalar/LowerConstantIntrinsics.h" 158bcb0991SDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 165ffd83dbSDimitry Andric #include "llvm/ADT/SetVector.h" 178bcb0991SDimitry Andric #include "llvm/ADT/Statistic.h" 18fe6060f1SDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h" 195ffd83dbSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 208bcb0991SDimitry Andric #include "llvm/Analysis/InstructionSimplify.h" 218bcb0991SDimitry Andric #include "llvm/Analysis/MemoryBuiltins.h" 228bcb0991SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 238bcb0991SDimitry Andric #include "llvm/IR/BasicBlock.h" 248bcb0991SDimitry Andric #include "llvm/IR/Constants.h" 25fe6060f1SDimitry Andric #include "llvm/IR/Dominators.h" 268bcb0991SDimitry Andric #include "llvm/IR/Function.h" 278bcb0991SDimitry Andric #include "llvm/IR/Instructions.h" 288bcb0991SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 298bcb0991SDimitry Andric #include "llvm/IR/PatternMatch.h" 30480093f4SDimitry Andric #include "llvm/InitializePasses.h" 318bcb0991SDimitry Andric #include "llvm/Pass.h" 3206c3fb27SDimitry Andric #include "llvm/Support/Debug.h" 338bcb0991SDimitry Andric #include "llvm/Transforms/Scalar.h" 348bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 35bdd1243dSDimitry Andric #include <optional> 368bcb0991SDimitry Andric 378bcb0991SDimitry Andric using namespace llvm; 388bcb0991SDimitry Andric using namespace llvm::PatternMatch; 398bcb0991SDimitry Andric 408bcb0991SDimitry Andric #define DEBUG_TYPE "lower-is-constant-intrinsic" 418bcb0991SDimitry Andric 428bcb0991SDimitry Andric STATISTIC(IsConstantIntrinsicsHandled, 438bcb0991SDimitry Andric "Number of 'is.constant' intrinsic calls handled"); 448bcb0991SDimitry Andric STATISTIC(ObjectSizeIntrinsicsHandled, 458bcb0991SDimitry Andric "Number of 'objectsize' intrinsic calls handled"); 468bcb0991SDimitry Andric 478bcb0991SDimitry Andric static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) { 4823408297SDimitry Andric if (auto *C = dyn_cast<Constant>(II->getOperand(0))) 4923408297SDimitry Andric if (C->isManifestConstant()) 5023408297SDimitry Andric return ConstantInt::getTrue(II->getType()); 5123408297SDimitry Andric return ConstantInt::getFalse(II->getType()); 528bcb0991SDimitry Andric } 538bcb0991SDimitry Andric 548bcb0991SDimitry Andric static bool replaceConditionalBranchesOnConstant(Instruction *II, 55fe6060f1SDimitry Andric Value *NewValue, 56fe6060f1SDimitry Andric DomTreeUpdater *DTU) { 578bcb0991SDimitry Andric bool HasDeadBlocks = false; 58349cc55cSDimitry Andric SmallSetVector<Instruction *, 8> UnsimplifiedUsers; 598bcb0991SDimitry Andric replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr, 60349cc55cSDimitry Andric &UnsimplifiedUsers); 61349cc55cSDimitry Andric // UnsimplifiedUsers can contain PHI nodes that may be removed when 62349cc55cSDimitry Andric // replacing the branch instructions, so use a value handle worklist 63349cc55cSDimitry Andric // to handle those possibly removed instructions. 64349cc55cSDimitry Andric SmallVector<WeakVH, 8> Worklist(UnsimplifiedUsers.begin(), 65349cc55cSDimitry Andric UnsimplifiedUsers.end()); 66349cc55cSDimitry Andric 67349cc55cSDimitry Andric for (auto &VH : Worklist) { 68349cc55cSDimitry Andric BranchInst *BI = dyn_cast_or_null<BranchInst>(VH); 698bcb0991SDimitry Andric if (!BI) 708bcb0991SDimitry Andric continue; 718bcb0991SDimitry Andric if (BI->isUnconditional()) 728bcb0991SDimitry Andric continue; 738bcb0991SDimitry Andric 748bcb0991SDimitry Andric BasicBlock *Target, *Other; 758bcb0991SDimitry Andric if (match(BI->getOperand(0), m_Zero())) { 768bcb0991SDimitry Andric Target = BI->getSuccessor(1); 778bcb0991SDimitry Andric Other = BI->getSuccessor(0); 788bcb0991SDimitry Andric } else if (match(BI->getOperand(0), m_One())) { 798bcb0991SDimitry Andric Target = BI->getSuccessor(0); 808bcb0991SDimitry Andric Other = BI->getSuccessor(1); 818bcb0991SDimitry Andric } else { 828bcb0991SDimitry Andric Target = nullptr; 838bcb0991SDimitry Andric Other = nullptr; 848bcb0991SDimitry Andric } 858bcb0991SDimitry Andric if (Target && Target != Other) { 868bcb0991SDimitry Andric BasicBlock *Source = BI->getParent(); 878bcb0991SDimitry Andric Other->removePredecessor(Source); 88*0fca6ea1SDimitry Andric 89*0fca6ea1SDimitry Andric Instruction *NewBI = BranchInst::Create(Target, Source); 90*0fca6ea1SDimitry Andric NewBI->setDebugLoc(BI->getDebugLoc()); 918bcb0991SDimitry Andric BI->eraseFromParent(); 92*0fca6ea1SDimitry Andric 93fe6060f1SDimitry Andric if (DTU) 94fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Delete, Source, Other}}); 95e8d8bef9SDimitry Andric if (pred_empty(Other)) 968bcb0991SDimitry Andric HasDeadBlocks = true; 978bcb0991SDimitry Andric } 988bcb0991SDimitry Andric } 998bcb0991SDimitry Andric return HasDeadBlocks; 1008bcb0991SDimitry Andric } 1018bcb0991SDimitry Andric 10281ad6265SDimitry Andric static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo &TLI, 103fe6060f1SDimitry Andric DominatorTree *DT) { 104bdd1243dSDimitry Andric std::optional<DomTreeUpdater> DTU; 105fe6060f1SDimitry Andric if (DT) 106fe6060f1SDimitry Andric DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy); 107fe6060f1SDimitry Andric 1088bcb0991SDimitry Andric bool HasDeadBlocks = false; 109*0fca6ea1SDimitry Andric const auto &DL = F.getDataLayout(); 1108bcb0991SDimitry Andric SmallVector<WeakTrackingVH, 8> Worklist; 1118bcb0991SDimitry Andric 1128bcb0991SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&F); 1138bcb0991SDimitry Andric for (BasicBlock *BB : RPOT) { 1148bcb0991SDimitry Andric for (Instruction &I: *BB) { 1158bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 1168bcb0991SDimitry Andric if (!II) 1178bcb0991SDimitry Andric continue; 1188bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1198bcb0991SDimitry Andric default: 1208bcb0991SDimitry Andric break; 1218bcb0991SDimitry Andric case Intrinsic::is_constant: 1228bcb0991SDimitry Andric case Intrinsic::objectsize: 1238bcb0991SDimitry Andric Worklist.push_back(WeakTrackingVH(&I)); 1248bcb0991SDimitry Andric break; 1258bcb0991SDimitry Andric } 1268bcb0991SDimitry Andric } 1278bcb0991SDimitry Andric } 1288bcb0991SDimitry Andric for (WeakTrackingVH &VH: Worklist) { 1298bcb0991SDimitry Andric // Items on the worklist can be mutated by earlier recursive replaces. 1308bcb0991SDimitry Andric // This can remove the intrinsic as dead (VH == null), but also replace 1318bcb0991SDimitry Andric // the intrinsic in place. 1328bcb0991SDimitry Andric if (!VH) 1338bcb0991SDimitry Andric continue; 1348bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH); 1358bcb0991SDimitry Andric if (!II) 1368bcb0991SDimitry Andric continue; 1378bcb0991SDimitry Andric Value *NewValue; 1388bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1398bcb0991SDimitry Andric default: 1408bcb0991SDimitry Andric continue; 1418bcb0991SDimitry Andric case Intrinsic::is_constant: 1428bcb0991SDimitry Andric NewValue = lowerIsConstantIntrinsic(II); 14306c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Folding " << *II << " to " << *NewValue << "\n"); 1448bcb0991SDimitry Andric IsConstantIntrinsicsHandled++; 1458bcb0991SDimitry Andric break; 1468bcb0991SDimitry Andric case Intrinsic::objectsize: 14781ad6265SDimitry Andric NewValue = lowerObjectSizeCall(II, DL, &TLI, true); 14806c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Folding " << *II << " to " << *NewValue << "\n"); 1498bcb0991SDimitry Andric ObjectSizeIntrinsicsHandled++; 1508bcb0991SDimitry Andric break; 1518bcb0991SDimitry Andric } 152fe6060f1SDimitry Andric HasDeadBlocks |= replaceConditionalBranchesOnConstant( 153bdd1243dSDimitry Andric II, NewValue, DTU ? &*DTU : nullptr); 1548bcb0991SDimitry Andric } 1558bcb0991SDimitry Andric if (HasDeadBlocks) 156bdd1243dSDimitry Andric removeUnreachableBlocks(F, DTU ? &*DTU : nullptr); 1578bcb0991SDimitry Andric return !Worklist.empty(); 1588bcb0991SDimitry Andric } 1598bcb0991SDimitry Andric 1608bcb0991SDimitry Andric PreservedAnalyses 1618bcb0991SDimitry Andric LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) { 16281ad6265SDimitry Andric if (lowerConstantIntrinsics(F, AM.getResult<TargetLibraryAnalysis>(F), 163fe6060f1SDimitry Andric AM.getCachedResult<DominatorTreeAnalysis>(F))) { 1645ffd83dbSDimitry Andric PreservedAnalyses PA; 165fe6060f1SDimitry Andric PA.preserve<DominatorTreeAnalysis>(); 1665ffd83dbSDimitry Andric return PA; 1675ffd83dbSDimitry Andric } 1688bcb0991SDimitry Andric 1698bcb0991SDimitry Andric return PreservedAnalyses::all(); 1708bcb0991SDimitry Andric } 1718bcb0991SDimitry Andric 1728bcb0991SDimitry Andric namespace { 1738bcb0991SDimitry Andric /// Legacy pass for lowering is.constant intrinsics out of the IR. 1748bcb0991SDimitry Andric /// 1758bcb0991SDimitry Andric /// When this pass is run over a function it converts is.constant intrinsics 1765ffd83dbSDimitry Andric /// into 'true' or 'false'. This complements the normal constant folding 1778bcb0991SDimitry Andric /// to 'true' as part of Instruction Simplify passes. 1788bcb0991SDimitry Andric class LowerConstantIntrinsics : public FunctionPass { 1798bcb0991SDimitry Andric public: 1808bcb0991SDimitry Andric static char ID; 1818bcb0991SDimitry Andric LowerConstantIntrinsics() : FunctionPass(ID) { 1828bcb0991SDimitry Andric initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry()); 1838bcb0991SDimitry Andric } 1848bcb0991SDimitry Andric 1858bcb0991SDimitry Andric bool runOnFunction(Function &F) override { 18681ad6265SDimitry Andric const TargetLibraryInfo &TLI = 18781ad6265SDimitry Andric getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); 188fe6060f1SDimitry Andric DominatorTree *DT = nullptr; 189fe6060f1SDimitry Andric if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) 190fe6060f1SDimitry Andric DT = &DTWP->getDomTree(); 191fe6060f1SDimitry Andric return lowerConstantIntrinsics(F, TLI, DT); 1928bcb0991SDimitry Andric } 1935ffd83dbSDimitry Andric 1945ffd83dbSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 19581ad6265SDimitry Andric AU.addRequired<TargetLibraryInfoWrapperPass>(); 1965ffd83dbSDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>(); 197fe6060f1SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 1985ffd83dbSDimitry Andric } 1998bcb0991SDimitry Andric }; 2008bcb0991SDimitry Andric } // namespace 2018bcb0991SDimitry Andric 2028bcb0991SDimitry Andric char LowerConstantIntrinsics::ID = 0; 203fe6060f1SDimitry Andric INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics", 204fe6060f1SDimitry Andric "Lower constant intrinsics", false, false) 20581ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) 206fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 207fe6060f1SDimitry Andric INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics", 2088bcb0991SDimitry Andric "Lower constant intrinsics", false, false) 2098bcb0991SDimitry Andric 2108bcb0991SDimitry Andric FunctionPass *llvm::createLowerConstantIntrinsicsPass() { 2118bcb0991SDimitry Andric return new LowerConstantIntrinsics(); 2128bcb0991SDimitry Andric } 213