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" 328bcb0991SDimitry Andric #include "llvm/Transforms/Scalar.h" 338bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 34*bdd1243dSDimitry Andric #include <optional> 358bcb0991SDimitry Andric 368bcb0991SDimitry Andric using namespace llvm; 378bcb0991SDimitry Andric using namespace llvm::PatternMatch; 388bcb0991SDimitry Andric 398bcb0991SDimitry Andric #define DEBUG_TYPE "lower-is-constant-intrinsic" 408bcb0991SDimitry Andric 418bcb0991SDimitry Andric STATISTIC(IsConstantIntrinsicsHandled, 428bcb0991SDimitry Andric "Number of 'is.constant' intrinsic calls handled"); 438bcb0991SDimitry Andric STATISTIC(ObjectSizeIntrinsicsHandled, 448bcb0991SDimitry Andric "Number of 'objectsize' intrinsic calls handled"); 458bcb0991SDimitry Andric 468bcb0991SDimitry Andric static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) { 4723408297SDimitry Andric if (auto *C = dyn_cast<Constant>(II->getOperand(0))) 4823408297SDimitry Andric if (C->isManifestConstant()) 4923408297SDimitry Andric return ConstantInt::getTrue(II->getType()); 5023408297SDimitry Andric return ConstantInt::getFalse(II->getType()); 518bcb0991SDimitry Andric } 528bcb0991SDimitry Andric 538bcb0991SDimitry Andric static bool replaceConditionalBranchesOnConstant(Instruction *II, 54fe6060f1SDimitry Andric Value *NewValue, 55fe6060f1SDimitry Andric DomTreeUpdater *DTU) { 568bcb0991SDimitry Andric bool HasDeadBlocks = false; 57349cc55cSDimitry Andric SmallSetVector<Instruction *, 8> UnsimplifiedUsers; 588bcb0991SDimitry Andric replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr, 59349cc55cSDimitry Andric &UnsimplifiedUsers); 60349cc55cSDimitry Andric // UnsimplifiedUsers can contain PHI nodes that may be removed when 61349cc55cSDimitry Andric // replacing the branch instructions, so use a value handle worklist 62349cc55cSDimitry Andric // to handle those possibly removed instructions. 63349cc55cSDimitry Andric SmallVector<WeakVH, 8> Worklist(UnsimplifiedUsers.begin(), 64349cc55cSDimitry Andric UnsimplifiedUsers.end()); 65349cc55cSDimitry Andric 66349cc55cSDimitry Andric for (auto &VH : Worklist) { 67349cc55cSDimitry Andric BranchInst *BI = dyn_cast_or_null<BranchInst>(VH); 688bcb0991SDimitry Andric if (!BI) 698bcb0991SDimitry Andric continue; 708bcb0991SDimitry Andric if (BI->isUnconditional()) 718bcb0991SDimitry Andric continue; 728bcb0991SDimitry Andric 738bcb0991SDimitry Andric BasicBlock *Target, *Other; 748bcb0991SDimitry Andric if (match(BI->getOperand(0), m_Zero())) { 758bcb0991SDimitry Andric Target = BI->getSuccessor(1); 768bcb0991SDimitry Andric Other = BI->getSuccessor(0); 778bcb0991SDimitry Andric } else if (match(BI->getOperand(0), m_One())) { 788bcb0991SDimitry Andric Target = BI->getSuccessor(0); 798bcb0991SDimitry Andric Other = BI->getSuccessor(1); 808bcb0991SDimitry Andric } else { 818bcb0991SDimitry Andric Target = nullptr; 828bcb0991SDimitry Andric Other = nullptr; 838bcb0991SDimitry Andric } 848bcb0991SDimitry Andric if (Target && Target != Other) { 858bcb0991SDimitry Andric BasicBlock *Source = BI->getParent(); 868bcb0991SDimitry Andric Other->removePredecessor(Source); 878bcb0991SDimitry Andric BI->eraseFromParent(); 888bcb0991SDimitry Andric BranchInst::Create(Target, Source); 89fe6060f1SDimitry Andric if (DTU) 90fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Delete, Source, Other}}); 91e8d8bef9SDimitry Andric if (pred_empty(Other)) 928bcb0991SDimitry Andric HasDeadBlocks = true; 938bcb0991SDimitry Andric } 948bcb0991SDimitry Andric } 958bcb0991SDimitry Andric return HasDeadBlocks; 968bcb0991SDimitry Andric } 978bcb0991SDimitry Andric 9881ad6265SDimitry Andric static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo &TLI, 99fe6060f1SDimitry Andric DominatorTree *DT) { 100*bdd1243dSDimitry Andric std::optional<DomTreeUpdater> DTU; 101fe6060f1SDimitry Andric if (DT) 102fe6060f1SDimitry Andric DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy); 103fe6060f1SDimitry Andric 1048bcb0991SDimitry Andric bool HasDeadBlocks = false; 1058bcb0991SDimitry Andric const auto &DL = F.getParent()->getDataLayout(); 1068bcb0991SDimitry Andric SmallVector<WeakTrackingVH, 8> Worklist; 1078bcb0991SDimitry Andric 1088bcb0991SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&F); 1098bcb0991SDimitry Andric for (BasicBlock *BB : RPOT) { 1108bcb0991SDimitry Andric for (Instruction &I: *BB) { 1118bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 1128bcb0991SDimitry Andric if (!II) 1138bcb0991SDimitry Andric continue; 1148bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1158bcb0991SDimitry Andric default: 1168bcb0991SDimitry Andric break; 1178bcb0991SDimitry Andric case Intrinsic::is_constant: 1188bcb0991SDimitry Andric case Intrinsic::objectsize: 1198bcb0991SDimitry Andric Worklist.push_back(WeakTrackingVH(&I)); 1208bcb0991SDimitry Andric break; 1218bcb0991SDimitry Andric } 1228bcb0991SDimitry Andric } 1238bcb0991SDimitry Andric } 1248bcb0991SDimitry Andric for (WeakTrackingVH &VH: Worklist) { 1258bcb0991SDimitry Andric // Items on the worklist can be mutated by earlier recursive replaces. 1268bcb0991SDimitry Andric // This can remove the intrinsic as dead (VH == null), but also replace 1278bcb0991SDimitry Andric // the intrinsic in place. 1288bcb0991SDimitry Andric if (!VH) 1298bcb0991SDimitry Andric continue; 1308bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH); 1318bcb0991SDimitry Andric if (!II) 1328bcb0991SDimitry Andric continue; 1338bcb0991SDimitry Andric Value *NewValue; 1348bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1358bcb0991SDimitry Andric default: 1368bcb0991SDimitry Andric continue; 1378bcb0991SDimitry Andric case Intrinsic::is_constant: 1388bcb0991SDimitry Andric NewValue = lowerIsConstantIntrinsic(II); 1398bcb0991SDimitry Andric IsConstantIntrinsicsHandled++; 1408bcb0991SDimitry Andric break; 1418bcb0991SDimitry Andric case Intrinsic::objectsize: 14281ad6265SDimitry Andric NewValue = lowerObjectSizeCall(II, DL, &TLI, true); 1438bcb0991SDimitry Andric ObjectSizeIntrinsicsHandled++; 1448bcb0991SDimitry Andric break; 1458bcb0991SDimitry Andric } 146fe6060f1SDimitry Andric HasDeadBlocks |= replaceConditionalBranchesOnConstant( 147*bdd1243dSDimitry Andric II, NewValue, DTU ? &*DTU : nullptr); 1488bcb0991SDimitry Andric } 1498bcb0991SDimitry Andric if (HasDeadBlocks) 150*bdd1243dSDimitry Andric removeUnreachableBlocks(F, DTU ? &*DTU : nullptr); 1518bcb0991SDimitry Andric return !Worklist.empty(); 1528bcb0991SDimitry Andric } 1538bcb0991SDimitry Andric 1548bcb0991SDimitry Andric PreservedAnalyses 1558bcb0991SDimitry Andric LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) { 15681ad6265SDimitry Andric if (lowerConstantIntrinsics(F, AM.getResult<TargetLibraryAnalysis>(F), 157fe6060f1SDimitry Andric AM.getCachedResult<DominatorTreeAnalysis>(F))) { 1585ffd83dbSDimitry Andric PreservedAnalyses PA; 159fe6060f1SDimitry Andric PA.preserve<DominatorTreeAnalysis>(); 1605ffd83dbSDimitry Andric return PA; 1615ffd83dbSDimitry Andric } 1628bcb0991SDimitry Andric 1638bcb0991SDimitry Andric return PreservedAnalyses::all(); 1648bcb0991SDimitry Andric } 1658bcb0991SDimitry Andric 1668bcb0991SDimitry Andric namespace { 1678bcb0991SDimitry Andric /// Legacy pass for lowering is.constant intrinsics out of the IR. 1688bcb0991SDimitry Andric /// 1698bcb0991SDimitry Andric /// When this pass is run over a function it converts is.constant intrinsics 1705ffd83dbSDimitry Andric /// into 'true' or 'false'. This complements the normal constant folding 1718bcb0991SDimitry Andric /// to 'true' as part of Instruction Simplify passes. 1728bcb0991SDimitry Andric class LowerConstantIntrinsics : public FunctionPass { 1738bcb0991SDimitry Andric public: 1748bcb0991SDimitry Andric static char ID; 1758bcb0991SDimitry Andric LowerConstantIntrinsics() : FunctionPass(ID) { 1768bcb0991SDimitry Andric initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry()); 1778bcb0991SDimitry Andric } 1788bcb0991SDimitry Andric 1798bcb0991SDimitry Andric bool runOnFunction(Function &F) override { 18081ad6265SDimitry Andric const TargetLibraryInfo &TLI = 18181ad6265SDimitry Andric getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); 182fe6060f1SDimitry Andric DominatorTree *DT = nullptr; 183fe6060f1SDimitry Andric if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) 184fe6060f1SDimitry Andric DT = &DTWP->getDomTree(); 185fe6060f1SDimitry Andric return lowerConstantIntrinsics(F, TLI, DT); 1868bcb0991SDimitry Andric } 1875ffd83dbSDimitry Andric 1885ffd83dbSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 18981ad6265SDimitry Andric AU.addRequired<TargetLibraryInfoWrapperPass>(); 1905ffd83dbSDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>(); 191fe6060f1SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 1925ffd83dbSDimitry Andric } 1938bcb0991SDimitry Andric }; 1948bcb0991SDimitry Andric } // namespace 1958bcb0991SDimitry Andric 1968bcb0991SDimitry Andric char LowerConstantIntrinsics::ID = 0; 197fe6060f1SDimitry Andric INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics", 198fe6060f1SDimitry Andric "Lower constant intrinsics", false, false) 19981ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) 200fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 201fe6060f1SDimitry Andric INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics", 2028bcb0991SDimitry Andric "Lower constant intrinsics", false, false) 2038bcb0991SDimitry Andric 2048bcb0991SDimitry Andric FunctionPass *llvm::createLowerConstantIntrinsicsPass() { 2058bcb0991SDimitry Andric return new LowerConstantIntrinsics(); 2068bcb0991SDimitry Andric } 207