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" 18*fe6060f1SDimitry 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" 25*fe6060f1SDimitry 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/Intrinsics.h" 308bcb0991SDimitry Andric #include "llvm/IR/PatternMatch.h" 31480093f4SDimitry Andric #include "llvm/InitializePasses.h" 328bcb0991SDimitry Andric #include "llvm/Pass.h" 338bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 348bcb0991SDimitry Andric #include "llvm/Transforms/Scalar.h" 358bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 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, 55*fe6060f1SDimitry Andric Value *NewValue, 56*fe6060f1SDimitry Andric DomTreeUpdater *DTU) { 578bcb0991SDimitry Andric bool HasDeadBlocks = false; 588bcb0991SDimitry Andric SmallSetVector<Instruction *, 8> Worklist; 598bcb0991SDimitry Andric replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr, 608bcb0991SDimitry Andric &Worklist); 618bcb0991SDimitry Andric for (auto I : Worklist) { 628bcb0991SDimitry Andric BranchInst *BI = dyn_cast<BranchInst>(I); 638bcb0991SDimitry Andric if (!BI) 648bcb0991SDimitry Andric continue; 658bcb0991SDimitry Andric if (BI->isUnconditional()) 668bcb0991SDimitry Andric continue; 678bcb0991SDimitry Andric 688bcb0991SDimitry Andric BasicBlock *Target, *Other; 698bcb0991SDimitry Andric if (match(BI->getOperand(0), m_Zero())) { 708bcb0991SDimitry Andric Target = BI->getSuccessor(1); 718bcb0991SDimitry Andric Other = BI->getSuccessor(0); 728bcb0991SDimitry Andric } else if (match(BI->getOperand(0), m_One())) { 738bcb0991SDimitry Andric Target = BI->getSuccessor(0); 748bcb0991SDimitry Andric Other = BI->getSuccessor(1); 758bcb0991SDimitry Andric } else { 768bcb0991SDimitry Andric Target = nullptr; 778bcb0991SDimitry Andric Other = nullptr; 788bcb0991SDimitry Andric } 798bcb0991SDimitry Andric if (Target && Target != Other) { 808bcb0991SDimitry Andric BasicBlock *Source = BI->getParent(); 818bcb0991SDimitry Andric Other->removePredecessor(Source); 828bcb0991SDimitry Andric BI->eraseFromParent(); 838bcb0991SDimitry Andric BranchInst::Create(Target, Source); 84*fe6060f1SDimitry Andric if (DTU) 85*fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Delete, Source, Other}}); 86e8d8bef9SDimitry Andric if (pred_empty(Other)) 878bcb0991SDimitry Andric HasDeadBlocks = true; 888bcb0991SDimitry Andric } 898bcb0991SDimitry Andric } 908bcb0991SDimitry Andric return HasDeadBlocks; 918bcb0991SDimitry Andric } 928bcb0991SDimitry Andric 93*fe6060f1SDimitry Andric static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI, 94*fe6060f1SDimitry Andric DominatorTree *DT) { 95*fe6060f1SDimitry Andric Optional<DomTreeUpdater> DTU; 96*fe6060f1SDimitry Andric if (DT) 97*fe6060f1SDimitry Andric DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy); 98*fe6060f1SDimitry Andric 998bcb0991SDimitry Andric bool HasDeadBlocks = false; 1008bcb0991SDimitry Andric const auto &DL = F.getParent()->getDataLayout(); 1018bcb0991SDimitry Andric SmallVector<WeakTrackingVH, 8> Worklist; 1028bcb0991SDimitry Andric 1038bcb0991SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&F); 1048bcb0991SDimitry Andric for (BasicBlock *BB : RPOT) { 1058bcb0991SDimitry Andric for (Instruction &I: *BB) { 1068bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 1078bcb0991SDimitry Andric if (!II) 1088bcb0991SDimitry Andric continue; 1098bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1108bcb0991SDimitry Andric default: 1118bcb0991SDimitry Andric break; 1128bcb0991SDimitry Andric case Intrinsic::is_constant: 1138bcb0991SDimitry Andric case Intrinsic::objectsize: 1148bcb0991SDimitry Andric Worklist.push_back(WeakTrackingVH(&I)); 1158bcb0991SDimitry Andric break; 1168bcb0991SDimitry Andric } 1178bcb0991SDimitry Andric } 1188bcb0991SDimitry Andric } 1198bcb0991SDimitry Andric for (WeakTrackingVH &VH: Worklist) { 1208bcb0991SDimitry Andric // Items on the worklist can be mutated by earlier recursive replaces. 1218bcb0991SDimitry Andric // This can remove the intrinsic as dead (VH == null), but also replace 1228bcb0991SDimitry Andric // the intrinsic in place. 1238bcb0991SDimitry Andric if (!VH) 1248bcb0991SDimitry Andric continue; 1258bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH); 1268bcb0991SDimitry Andric if (!II) 1278bcb0991SDimitry Andric continue; 1288bcb0991SDimitry Andric Value *NewValue; 1298bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1308bcb0991SDimitry Andric default: 1318bcb0991SDimitry Andric continue; 1328bcb0991SDimitry Andric case Intrinsic::is_constant: 1338bcb0991SDimitry Andric NewValue = lowerIsConstantIntrinsic(II); 1348bcb0991SDimitry Andric IsConstantIntrinsicsHandled++; 1358bcb0991SDimitry Andric break; 1368bcb0991SDimitry Andric case Intrinsic::objectsize: 1378bcb0991SDimitry Andric NewValue = lowerObjectSizeCall(II, DL, TLI, true); 1388bcb0991SDimitry Andric ObjectSizeIntrinsicsHandled++; 1398bcb0991SDimitry Andric break; 1408bcb0991SDimitry Andric } 141*fe6060f1SDimitry Andric HasDeadBlocks |= replaceConditionalBranchesOnConstant( 142*fe6060f1SDimitry Andric II, NewValue, DTU.hasValue() ? DTU.getPointer() : nullptr); 1438bcb0991SDimitry Andric } 1448bcb0991SDimitry Andric if (HasDeadBlocks) 145*fe6060f1SDimitry Andric removeUnreachableBlocks(F, DTU.hasValue() ? DTU.getPointer() : nullptr); 1468bcb0991SDimitry Andric return !Worklist.empty(); 1478bcb0991SDimitry Andric } 1488bcb0991SDimitry Andric 1498bcb0991SDimitry Andric PreservedAnalyses 1508bcb0991SDimitry Andric LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) { 151*fe6060f1SDimitry Andric if (lowerConstantIntrinsics(F, AM.getCachedResult<TargetLibraryAnalysis>(F), 152*fe6060f1SDimitry Andric AM.getCachedResult<DominatorTreeAnalysis>(F))) { 1535ffd83dbSDimitry Andric PreservedAnalyses PA; 154*fe6060f1SDimitry Andric PA.preserve<DominatorTreeAnalysis>(); 1555ffd83dbSDimitry Andric return PA; 1565ffd83dbSDimitry Andric } 1578bcb0991SDimitry Andric 1588bcb0991SDimitry Andric return PreservedAnalyses::all(); 1598bcb0991SDimitry Andric } 1608bcb0991SDimitry Andric 1618bcb0991SDimitry Andric namespace { 1628bcb0991SDimitry Andric /// Legacy pass for lowering is.constant intrinsics out of the IR. 1638bcb0991SDimitry Andric /// 1648bcb0991SDimitry Andric /// When this pass is run over a function it converts is.constant intrinsics 1655ffd83dbSDimitry Andric /// into 'true' or 'false'. This complements the normal constant folding 1668bcb0991SDimitry Andric /// to 'true' as part of Instruction Simplify passes. 1678bcb0991SDimitry Andric class LowerConstantIntrinsics : public FunctionPass { 1688bcb0991SDimitry Andric public: 1698bcb0991SDimitry Andric static char ID; 1708bcb0991SDimitry Andric LowerConstantIntrinsics() : FunctionPass(ID) { 1718bcb0991SDimitry Andric initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry()); 1728bcb0991SDimitry Andric } 1738bcb0991SDimitry Andric 1748bcb0991SDimitry Andric bool runOnFunction(Function &F) override { 1758bcb0991SDimitry Andric auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>(); 1768bcb0991SDimitry Andric const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr; 177*fe6060f1SDimitry Andric DominatorTree *DT = nullptr; 178*fe6060f1SDimitry Andric if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) 179*fe6060f1SDimitry Andric DT = &DTWP->getDomTree(); 180*fe6060f1SDimitry Andric return lowerConstantIntrinsics(F, TLI, DT); 1818bcb0991SDimitry Andric } 1825ffd83dbSDimitry Andric 1835ffd83dbSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 1845ffd83dbSDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>(); 185*fe6060f1SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 1865ffd83dbSDimitry Andric } 1878bcb0991SDimitry Andric }; 1888bcb0991SDimitry Andric } // namespace 1898bcb0991SDimitry Andric 1908bcb0991SDimitry Andric char LowerConstantIntrinsics::ID = 0; 191*fe6060f1SDimitry Andric INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics", 192*fe6060f1SDimitry Andric "Lower constant intrinsics", false, false) 193*fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 194*fe6060f1SDimitry Andric INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics", 1958bcb0991SDimitry Andric "Lower constant intrinsics", false, false) 1968bcb0991SDimitry Andric 1978bcb0991SDimitry Andric FunctionPass *llvm::createLowerConstantIntrinsicsPass() { 1988bcb0991SDimitry Andric return new LowerConstantIntrinsics(); 1998bcb0991SDimitry Andric } 200