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" 185ffd83dbSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 198bcb0991SDimitry Andric #include "llvm/Analysis/InstructionSimplify.h" 208bcb0991SDimitry Andric #include "llvm/Analysis/MemoryBuiltins.h" 218bcb0991SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 228bcb0991SDimitry Andric #include "llvm/IR/BasicBlock.h" 238bcb0991SDimitry Andric #include "llvm/IR/Constants.h" 248bcb0991SDimitry Andric #include "llvm/IR/Function.h" 258bcb0991SDimitry Andric #include "llvm/IR/Instructions.h" 268bcb0991SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 278bcb0991SDimitry Andric #include "llvm/IR/Intrinsics.h" 288bcb0991SDimitry Andric #include "llvm/IR/PatternMatch.h" 29480093f4SDimitry Andric #include "llvm/InitializePasses.h" 308bcb0991SDimitry Andric #include "llvm/Pass.h" 318bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 328bcb0991SDimitry Andric #include "llvm/Transforms/Scalar.h" 338bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 348bcb0991SDimitry Andric 358bcb0991SDimitry Andric using namespace llvm; 368bcb0991SDimitry Andric using namespace llvm::PatternMatch; 378bcb0991SDimitry Andric 388bcb0991SDimitry Andric #define DEBUG_TYPE "lower-is-constant-intrinsic" 398bcb0991SDimitry Andric 408bcb0991SDimitry Andric STATISTIC(IsConstantIntrinsicsHandled, 418bcb0991SDimitry Andric "Number of 'is.constant' intrinsic calls handled"); 428bcb0991SDimitry Andric STATISTIC(ObjectSizeIntrinsicsHandled, 438bcb0991SDimitry Andric "Number of 'objectsize' intrinsic calls handled"); 448bcb0991SDimitry Andric 458bcb0991SDimitry Andric static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) { 468bcb0991SDimitry Andric Value *Op = II->getOperand(0); 478bcb0991SDimitry Andric 488bcb0991SDimitry Andric return isa<Constant>(Op) ? ConstantInt::getTrue(II->getType()) 498bcb0991SDimitry Andric : ConstantInt::getFalse(II->getType()); 508bcb0991SDimitry Andric } 518bcb0991SDimitry Andric 528bcb0991SDimitry Andric static bool replaceConditionalBranchesOnConstant(Instruction *II, 538bcb0991SDimitry Andric Value *NewValue) { 548bcb0991SDimitry Andric bool HasDeadBlocks = false; 558bcb0991SDimitry Andric SmallSetVector<Instruction *, 8> Worklist; 568bcb0991SDimitry Andric replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr, 578bcb0991SDimitry Andric &Worklist); 588bcb0991SDimitry Andric for (auto I : Worklist) { 598bcb0991SDimitry Andric BranchInst *BI = dyn_cast<BranchInst>(I); 608bcb0991SDimitry Andric if (!BI) 618bcb0991SDimitry Andric continue; 628bcb0991SDimitry Andric if (BI->isUnconditional()) 638bcb0991SDimitry Andric continue; 648bcb0991SDimitry Andric 658bcb0991SDimitry Andric BasicBlock *Target, *Other; 668bcb0991SDimitry Andric if (match(BI->getOperand(0), m_Zero())) { 678bcb0991SDimitry Andric Target = BI->getSuccessor(1); 688bcb0991SDimitry Andric Other = BI->getSuccessor(0); 698bcb0991SDimitry Andric } else if (match(BI->getOperand(0), m_One())) { 708bcb0991SDimitry Andric Target = BI->getSuccessor(0); 718bcb0991SDimitry Andric Other = BI->getSuccessor(1); 728bcb0991SDimitry Andric } else { 738bcb0991SDimitry Andric Target = nullptr; 748bcb0991SDimitry Andric Other = nullptr; 758bcb0991SDimitry Andric } 768bcb0991SDimitry Andric if (Target && Target != Other) { 778bcb0991SDimitry Andric BasicBlock *Source = BI->getParent(); 788bcb0991SDimitry Andric Other->removePredecessor(Source); 798bcb0991SDimitry Andric BI->eraseFromParent(); 808bcb0991SDimitry Andric BranchInst::Create(Target, Source); 81*e8d8bef9SDimitry Andric if (pred_empty(Other)) 828bcb0991SDimitry Andric HasDeadBlocks = true; 838bcb0991SDimitry Andric } 848bcb0991SDimitry Andric } 858bcb0991SDimitry Andric return HasDeadBlocks; 868bcb0991SDimitry Andric } 878bcb0991SDimitry Andric 888bcb0991SDimitry Andric static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI) { 898bcb0991SDimitry Andric bool HasDeadBlocks = false; 908bcb0991SDimitry Andric const auto &DL = F.getParent()->getDataLayout(); 918bcb0991SDimitry Andric SmallVector<WeakTrackingVH, 8> Worklist; 928bcb0991SDimitry Andric 938bcb0991SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&F); 948bcb0991SDimitry Andric for (BasicBlock *BB : RPOT) { 958bcb0991SDimitry Andric for (Instruction &I: *BB) { 968bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 978bcb0991SDimitry Andric if (!II) 988bcb0991SDimitry Andric continue; 998bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1008bcb0991SDimitry Andric default: 1018bcb0991SDimitry Andric break; 1028bcb0991SDimitry Andric case Intrinsic::is_constant: 1038bcb0991SDimitry Andric case Intrinsic::objectsize: 1048bcb0991SDimitry Andric Worklist.push_back(WeakTrackingVH(&I)); 1058bcb0991SDimitry Andric break; 1068bcb0991SDimitry Andric } 1078bcb0991SDimitry Andric } 1088bcb0991SDimitry Andric } 1098bcb0991SDimitry Andric for (WeakTrackingVH &VH: Worklist) { 1108bcb0991SDimitry Andric // Items on the worklist can be mutated by earlier recursive replaces. 1118bcb0991SDimitry Andric // This can remove the intrinsic as dead (VH == null), but also replace 1128bcb0991SDimitry Andric // the intrinsic in place. 1138bcb0991SDimitry Andric if (!VH) 1148bcb0991SDimitry Andric continue; 1158bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH); 1168bcb0991SDimitry Andric if (!II) 1178bcb0991SDimitry Andric continue; 1188bcb0991SDimitry Andric Value *NewValue; 1198bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 1208bcb0991SDimitry Andric default: 1218bcb0991SDimitry Andric continue; 1228bcb0991SDimitry Andric case Intrinsic::is_constant: 1238bcb0991SDimitry Andric NewValue = lowerIsConstantIntrinsic(II); 1248bcb0991SDimitry Andric IsConstantIntrinsicsHandled++; 1258bcb0991SDimitry Andric break; 1268bcb0991SDimitry Andric case Intrinsic::objectsize: 1278bcb0991SDimitry Andric NewValue = lowerObjectSizeCall(II, DL, TLI, true); 1288bcb0991SDimitry Andric ObjectSizeIntrinsicsHandled++; 1298bcb0991SDimitry Andric break; 1308bcb0991SDimitry Andric } 1318bcb0991SDimitry Andric HasDeadBlocks |= replaceConditionalBranchesOnConstant(II, NewValue); 1328bcb0991SDimitry Andric } 1338bcb0991SDimitry Andric if (HasDeadBlocks) 1348bcb0991SDimitry Andric removeUnreachableBlocks(F); 1358bcb0991SDimitry Andric return !Worklist.empty(); 1368bcb0991SDimitry Andric } 1378bcb0991SDimitry Andric 1388bcb0991SDimitry Andric PreservedAnalyses 1398bcb0991SDimitry Andric LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) { 1405ffd83dbSDimitry Andric if (lowerConstantIntrinsics(F, 1415ffd83dbSDimitry Andric AM.getCachedResult<TargetLibraryAnalysis>(F))) { 1425ffd83dbSDimitry Andric PreservedAnalyses PA; 1435ffd83dbSDimitry Andric PA.preserve<GlobalsAA>(); 1445ffd83dbSDimitry Andric return PA; 1455ffd83dbSDimitry Andric } 1468bcb0991SDimitry Andric 1478bcb0991SDimitry Andric return PreservedAnalyses::all(); 1488bcb0991SDimitry Andric } 1498bcb0991SDimitry Andric 1508bcb0991SDimitry Andric namespace { 1518bcb0991SDimitry Andric /// Legacy pass for lowering is.constant intrinsics out of the IR. 1528bcb0991SDimitry Andric /// 1538bcb0991SDimitry Andric /// When this pass is run over a function it converts is.constant intrinsics 1545ffd83dbSDimitry Andric /// into 'true' or 'false'. This complements the normal constant folding 1558bcb0991SDimitry Andric /// to 'true' as part of Instruction Simplify passes. 1568bcb0991SDimitry Andric class LowerConstantIntrinsics : public FunctionPass { 1578bcb0991SDimitry Andric public: 1588bcb0991SDimitry Andric static char ID; 1598bcb0991SDimitry Andric LowerConstantIntrinsics() : FunctionPass(ID) { 1608bcb0991SDimitry Andric initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry()); 1618bcb0991SDimitry Andric } 1628bcb0991SDimitry Andric 1638bcb0991SDimitry Andric bool runOnFunction(Function &F) override { 1648bcb0991SDimitry Andric auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>(); 1658bcb0991SDimitry Andric const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr; 1668bcb0991SDimitry Andric return lowerConstantIntrinsics(F, TLI); 1678bcb0991SDimitry Andric } 1685ffd83dbSDimitry Andric 1695ffd83dbSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 1705ffd83dbSDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>(); 1715ffd83dbSDimitry Andric } 1728bcb0991SDimitry Andric }; 1738bcb0991SDimitry Andric } // namespace 1748bcb0991SDimitry Andric 1758bcb0991SDimitry Andric char LowerConstantIntrinsics::ID = 0; 1768bcb0991SDimitry Andric INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics", 1778bcb0991SDimitry Andric "Lower constant intrinsics", false, false) 1788bcb0991SDimitry Andric 1798bcb0991SDimitry Andric FunctionPass *llvm::createLowerConstantIntrinsicsPass() { 1808bcb0991SDimitry Andric return new LowerConstantIntrinsics(); 1818bcb0991SDimitry Andric } 182