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