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