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 35 using namespace llvm; 36 using namespace llvm::PatternMatch; 37 38 #define DEBUG_TYPE "lower-is-constant-intrinsic" 39 40 STATISTIC(IsConstantIntrinsicsHandled, 41 "Number of 'is.constant' intrinsic calls handled"); 42 STATISTIC(ObjectSizeIntrinsicsHandled, 43 "Number of 'objectsize' intrinsic calls handled"); 44 45 static 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 52 static 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 88 static 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 138 PreservedAnalyses 139 LowerConstantIntrinsicsPass::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 150 namespace { 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. 156 class LowerConstantIntrinsics : public FunctionPass { 157 public: 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 175 char LowerConstantIntrinsics::ID = 0; 176 INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics", 177 "Lower constant intrinsics", false, false) 178 179 FunctionPass *llvm::createLowerConstantIntrinsicsPass() { 180 return new LowerConstantIntrinsics(); 181 } 182