1*8bcb0991SDimitry Andric //===- LowerConstantIntrinsics.cpp - Lower constant intrinsic calls -------===// 2*8bcb0991SDimitry Andric // 3*8bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*8bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*8bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*8bcb0991SDimitry Andric // 7*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 8*8bcb0991SDimitry Andric // 9*8bcb0991SDimitry Andric // This pass lowers all remaining 'objectsize' 'is.constant' intrinsic calls 10*8bcb0991SDimitry Andric // and provides constant propagation and basic CFG cleanup on the result. 11*8bcb0991SDimitry Andric // 12*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 13*8bcb0991SDimitry Andric 14*8bcb0991SDimitry Andric #include "llvm/Transforms/Scalar/LowerConstantIntrinsics.h" 15*8bcb0991SDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 16*8bcb0991SDimitry Andric #include "llvm/ADT/Statistic.h" 17*8bcb0991SDimitry Andric #include "llvm/Analysis/InstructionSimplify.h" 18*8bcb0991SDimitry Andric #include "llvm/Analysis/MemoryBuiltins.h" 19*8bcb0991SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 20*8bcb0991SDimitry Andric #include "llvm/IR/BasicBlock.h" 21*8bcb0991SDimitry Andric #include "llvm/IR/Constants.h" 22*8bcb0991SDimitry Andric #include "llvm/IR/Function.h" 23*8bcb0991SDimitry Andric #include "llvm/IR/Instructions.h" 24*8bcb0991SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 25*8bcb0991SDimitry Andric #include "llvm/IR/Intrinsics.h" 26*8bcb0991SDimitry Andric #include "llvm/IR/PatternMatch.h" 27*8bcb0991SDimitry Andric #include "llvm/Pass.h" 28*8bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 29*8bcb0991SDimitry Andric #include "llvm/Transforms/Scalar.h" 30*8bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 31*8bcb0991SDimitry Andric 32*8bcb0991SDimitry Andric using namespace llvm; 33*8bcb0991SDimitry Andric using namespace llvm::PatternMatch; 34*8bcb0991SDimitry Andric 35*8bcb0991SDimitry Andric #define DEBUG_TYPE "lower-is-constant-intrinsic" 36*8bcb0991SDimitry Andric 37*8bcb0991SDimitry Andric STATISTIC(IsConstantIntrinsicsHandled, 38*8bcb0991SDimitry Andric "Number of 'is.constant' intrinsic calls handled"); 39*8bcb0991SDimitry Andric STATISTIC(ObjectSizeIntrinsicsHandled, 40*8bcb0991SDimitry Andric "Number of 'objectsize' intrinsic calls handled"); 41*8bcb0991SDimitry Andric 42*8bcb0991SDimitry Andric static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) { 43*8bcb0991SDimitry Andric Value *Op = II->getOperand(0); 44*8bcb0991SDimitry Andric 45*8bcb0991SDimitry Andric return isa<Constant>(Op) ? ConstantInt::getTrue(II->getType()) 46*8bcb0991SDimitry Andric : ConstantInt::getFalse(II->getType()); 47*8bcb0991SDimitry Andric } 48*8bcb0991SDimitry Andric 49*8bcb0991SDimitry Andric static bool replaceConditionalBranchesOnConstant(Instruction *II, 50*8bcb0991SDimitry Andric Value *NewValue) { 51*8bcb0991SDimitry Andric bool HasDeadBlocks = false; 52*8bcb0991SDimitry Andric SmallSetVector<Instruction *, 8> Worklist; 53*8bcb0991SDimitry Andric replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr, 54*8bcb0991SDimitry Andric &Worklist); 55*8bcb0991SDimitry Andric for (auto I : Worklist) { 56*8bcb0991SDimitry Andric BranchInst *BI = dyn_cast<BranchInst>(I); 57*8bcb0991SDimitry Andric if (!BI) 58*8bcb0991SDimitry Andric continue; 59*8bcb0991SDimitry Andric if (BI->isUnconditional()) 60*8bcb0991SDimitry Andric continue; 61*8bcb0991SDimitry Andric 62*8bcb0991SDimitry Andric BasicBlock *Target, *Other; 63*8bcb0991SDimitry Andric if (match(BI->getOperand(0), m_Zero())) { 64*8bcb0991SDimitry Andric Target = BI->getSuccessor(1); 65*8bcb0991SDimitry Andric Other = BI->getSuccessor(0); 66*8bcb0991SDimitry Andric } else if (match(BI->getOperand(0), m_One())) { 67*8bcb0991SDimitry Andric Target = BI->getSuccessor(0); 68*8bcb0991SDimitry Andric Other = BI->getSuccessor(1); 69*8bcb0991SDimitry Andric } else { 70*8bcb0991SDimitry Andric Target = nullptr; 71*8bcb0991SDimitry Andric Other = nullptr; 72*8bcb0991SDimitry Andric } 73*8bcb0991SDimitry Andric if (Target && Target != Other) { 74*8bcb0991SDimitry Andric BasicBlock *Source = BI->getParent(); 75*8bcb0991SDimitry Andric Other->removePredecessor(Source); 76*8bcb0991SDimitry Andric BI->eraseFromParent(); 77*8bcb0991SDimitry Andric BranchInst::Create(Target, Source); 78*8bcb0991SDimitry Andric if (pred_begin(Other) == pred_end(Other)) 79*8bcb0991SDimitry Andric HasDeadBlocks = true; 80*8bcb0991SDimitry Andric } 81*8bcb0991SDimitry Andric } 82*8bcb0991SDimitry Andric return HasDeadBlocks; 83*8bcb0991SDimitry Andric } 84*8bcb0991SDimitry Andric 85*8bcb0991SDimitry Andric static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI) { 86*8bcb0991SDimitry Andric bool HasDeadBlocks = false; 87*8bcb0991SDimitry Andric const auto &DL = F.getParent()->getDataLayout(); 88*8bcb0991SDimitry Andric SmallVector<WeakTrackingVH, 8> Worklist; 89*8bcb0991SDimitry Andric 90*8bcb0991SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&F); 91*8bcb0991SDimitry Andric for (BasicBlock *BB : RPOT) { 92*8bcb0991SDimitry Andric for (Instruction &I: *BB) { 93*8bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 94*8bcb0991SDimitry Andric if (!II) 95*8bcb0991SDimitry Andric continue; 96*8bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 97*8bcb0991SDimitry Andric default: 98*8bcb0991SDimitry Andric break; 99*8bcb0991SDimitry Andric case Intrinsic::is_constant: 100*8bcb0991SDimitry Andric case Intrinsic::objectsize: 101*8bcb0991SDimitry Andric Worklist.push_back(WeakTrackingVH(&I)); 102*8bcb0991SDimitry Andric break; 103*8bcb0991SDimitry Andric } 104*8bcb0991SDimitry Andric } 105*8bcb0991SDimitry Andric } 106*8bcb0991SDimitry Andric for (WeakTrackingVH &VH: Worklist) { 107*8bcb0991SDimitry Andric // Items on the worklist can be mutated by earlier recursive replaces. 108*8bcb0991SDimitry Andric // This can remove the intrinsic as dead (VH == null), but also replace 109*8bcb0991SDimitry Andric // the intrinsic in place. 110*8bcb0991SDimitry Andric if (!VH) 111*8bcb0991SDimitry Andric continue; 112*8bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH); 113*8bcb0991SDimitry Andric if (!II) 114*8bcb0991SDimitry Andric continue; 115*8bcb0991SDimitry Andric Value *NewValue; 116*8bcb0991SDimitry Andric switch (II->getIntrinsicID()) { 117*8bcb0991SDimitry Andric default: 118*8bcb0991SDimitry Andric continue; 119*8bcb0991SDimitry Andric case Intrinsic::is_constant: 120*8bcb0991SDimitry Andric NewValue = lowerIsConstantIntrinsic(II); 121*8bcb0991SDimitry Andric IsConstantIntrinsicsHandled++; 122*8bcb0991SDimitry Andric break; 123*8bcb0991SDimitry Andric case Intrinsic::objectsize: 124*8bcb0991SDimitry Andric NewValue = lowerObjectSizeCall(II, DL, TLI, true); 125*8bcb0991SDimitry Andric ObjectSizeIntrinsicsHandled++; 126*8bcb0991SDimitry Andric break; 127*8bcb0991SDimitry Andric } 128*8bcb0991SDimitry Andric HasDeadBlocks |= replaceConditionalBranchesOnConstant(II, NewValue); 129*8bcb0991SDimitry Andric } 130*8bcb0991SDimitry Andric if (HasDeadBlocks) 131*8bcb0991SDimitry Andric removeUnreachableBlocks(F); 132*8bcb0991SDimitry Andric return !Worklist.empty(); 133*8bcb0991SDimitry Andric } 134*8bcb0991SDimitry Andric 135*8bcb0991SDimitry Andric PreservedAnalyses 136*8bcb0991SDimitry Andric LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) { 137*8bcb0991SDimitry Andric if (lowerConstantIntrinsics(F, AM.getCachedResult<TargetLibraryAnalysis>(F))) 138*8bcb0991SDimitry Andric return PreservedAnalyses::none(); 139*8bcb0991SDimitry Andric 140*8bcb0991SDimitry Andric return PreservedAnalyses::all(); 141*8bcb0991SDimitry Andric } 142*8bcb0991SDimitry Andric 143*8bcb0991SDimitry Andric namespace { 144*8bcb0991SDimitry Andric /// Legacy pass for lowering is.constant intrinsics out of the IR. 145*8bcb0991SDimitry Andric /// 146*8bcb0991SDimitry Andric /// When this pass is run over a function it converts is.constant intrinsics 147*8bcb0991SDimitry Andric /// into 'true' or 'false'. This is completements the normal constand folding 148*8bcb0991SDimitry Andric /// to 'true' as part of Instruction Simplify passes. 149*8bcb0991SDimitry Andric class LowerConstantIntrinsics : public FunctionPass { 150*8bcb0991SDimitry Andric public: 151*8bcb0991SDimitry Andric static char ID; 152*8bcb0991SDimitry Andric LowerConstantIntrinsics() : FunctionPass(ID) { 153*8bcb0991SDimitry Andric initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry()); 154*8bcb0991SDimitry Andric } 155*8bcb0991SDimitry Andric 156*8bcb0991SDimitry Andric bool runOnFunction(Function &F) override { 157*8bcb0991SDimitry Andric auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>(); 158*8bcb0991SDimitry Andric const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr; 159*8bcb0991SDimitry Andric return lowerConstantIntrinsics(F, TLI); 160*8bcb0991SDimitry Andric } 161*8bcb0991SDimitry Andric }; 162*8bcb0991SDimitry Andric } // namespace 163*8bcb0991SDimitry Andric 164*8bcb0991SDimitry Andric char LowerConstantIntrinsics::ID = 0; 165*8bcb0991SDimitry Andric INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics", 166*8bcb0991SDimitry Andric "Lower constant intrinsics", false, false) 167*8bcb0991SDimitry Andric 168*8bcb0991SDimitry Andric FunctionPass *llvm::createLowerConstantIntrinsicsPass() { 169*8bcb0991SDimitry Andric return new LowerConstantIntrinsics(); 170*8bcb0991SDimitry Andric } 171