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/DomTreeUpdater.h" 19 #include "llvm/Analysis/GlobalsModRef.h" 20 #include "llvm/Analysis/InstructionSimplify.h" 21 #include "llvm/Analysis/MemoryBuiltins.h" 22 #include "llvm/Analysis/TargetLibraryInfo.h" 23 #include "llvm/IR/BasicBlock.h" 24 #include "llvm/IR/Constants.h" 25 #include "llvm/IR/Dominators.h" 26 #include "llvm/IR/Function.h" 27 #include "llvm/IR/Instructions.h" 28 #include "llvm/IR/IntrinsicInst.h" 29 #include "llvm/IR/PatternMatch.h" 30 #include "llvm/InitializePasses.h" 31 #include "llvm/Pass.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 if (auto *C = dyn_cast<Constant>(II->getOperand(0))) 47 if (C->isManifestConstant()) 48 return ConstantInt::getTrue(II->getType()); 49 return ConstantInt::getFalse(II->getType()); 50 } 51 52 static bool replaceConditionalBranchesOnConstant(Instruction *II, 53 Value *NewValue, 54 DomTreeUpdater *DTU) { 55 bool HasDeadBlocks = false; 56 SmallSetVector<Instruction *, 8> UnsimplifiedUsers; 57 replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr, 58 &UnsimplifiedUsers); 59 // UnsimplifiedUsers can contain PHI nodes that may be removed when 60 // replacing the branch instructions, so use a value handle worklist 61 // to handle those possibly removed instructions. 62 SmallVector<WeakVH, 8> Worklist(UnsimplifiedUsers.begin(), 63 UnsimplifiedUsers.end()); 64 65 for (auto &VH : Worklist) { 66 BranchInst *BI = dyn_cast_or_null<BranchInst>(VH); 67 if (!BI) 68 continue; 69 if (BI->isUnconditional()) 70 continue; 71 72 BasicBlock *Target, *Other; 73 if (match(BI->getOperand(0), m_Zero())) { 74 Target = BI->getSuccessor(1); 75 Other = BI->getSuccessor(0); 76 } else if (match(BI->getOperand(0), m_One())) { 77 Target = BI->getSuccessor(0); 78 Other = BI->getSuccessor(1); 79 } else { 80 Target = nullptr; 81 Other = nullptr; 82 } 83 if (Target && Target != Other) { 84 BasicBlock *Source = BI->getParent(); 85 Other->removePredecessor(Source); 86 BI->eraseFromParent(); 87 BranchInst::Create(Target, Source); 88 if (DTU) 89 DTU->applyUpdates({{DominatorTree::Delete, Source, Other}}); 90 if (pred_empty(Other)) 91 HasDeadBlocks = true; 92 } 93 } 94 return HasDeadBlocks; 95 } 96 97 static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo &TLI, 98 DominatorTree *DT) { 99 Optional<DomTreeUpdater> DTU; 100 if (DT) 101 DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy); 102 103 bool HasDeadBlocks = false; 104 const auto &DL = F.getParent()->getDataLayout(); 105 SmallVector<WeakTrackingVH, 8> Worklist; 106 107 ReversePostOrderTraversal<Function *> RPOT(&F); 108 for (BasicBlock *BB : RPOT) { 109 for (Instruction &I: *BB) { 110 IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 111 if (!II) 112 continue; 113 switch (II->getIntrinsicID()) { 114 default: 115 break; 116 case Intrinsic::is_constant: 117 case Intrinsic::objectsize: 118 Worklist.push_back(WeakTrackingVH(&I)); 119 break; 120 } 121 } 122 } 123 for (WeakTrackingVH &VH: Worklist) { 124 // Items on the worklist can be mutated by earlier recursive replaces. 125 // This can remove the intrinsic as dead (VH == null), but also replace 126 // the intrinsic in place. 127 if (!VH) 128 continue; 129 IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH); 130 if (!II) 131 continue; 132 Value *NewValue; 133 switch (II->getIntrinsicID()) { 134 default: 135 continue; 136 case Intrinsic::is_constant: 137 NewValue = lowerIsConstantIntrinsic(II); 138 IsConstantIntrinsicsHandled++; 139 break; 140 case Intrinsic::objectsize: 141 NewValue = lowerObjectSizeCall(II, DL, &TLI, true); 142 ObjectSizeIntrinsicsHandled++; 143 break; 144 } 145 HasDeadBlocks |= replaceConditionalBranchesOnConstant( 146 II, NewValue, DTU ? DTU.getPointer() : nullptr); 147 } 148 if (HasDeadBlocks) 149 removeUnreachableBlocks(F, DTU ? DTU.getPointer() : nullptr); 150 return !Worklist.empty(); 151 } 152 153 PreservedAnalyses 154 LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) { 155 if (lowerConstantIntrinsics(F, AM.getResult<TargetLibraryAnalysis>(F), 156 AM.getCachedResult<DominatorTreeAnalysis>(F))) { 157 PreservedAnalyses PA; 158 PA.preserve<DominatorTreeAnalysis>(); 159 return PA; 160 } 161 162 return PreservedAnalyses::all(); 163 } 164 165 namespace { 166 /// Legacy pass for lowering is.constant intrinsics out of the IR. 167 /// 168 /// When this pass is run over a function it converts is.constant intrinsics 169 /// into 'true' or 'false'. This complements the normal constant folding 170 /// to 'true' as part of Instruction Simplify passes. 171 class LowerConstantIntrinsics : public FunctionPass { 172 public: 173 static char ID; 174 LowerConstantIntrinsics() : FunctionPass(ID) { 175 initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry()); 176 } 177 178 bool runOnFunction(Function &F) override { 179 const TargetLibraryInfo &TLI = 180 getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); 181 DominatorTree *DT = nullptr; 182 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) 183 DT = &DTWP->getDomTree(); 184 return lowerConstantIntrinsics(F, TLI, DT); 185 } 186 187 void getAnalysisUsage(AnalysisUsage &AU) const override { 188 AU.addRequired<TargetLibraryInfoWrapperPass>(); 189 AU.addPreserved<GlobalsAAWrapperPass>(); 190 AU.addPreserved<DominatorTreeWrapperPass>(); 191 } 192 }; 193 } // namespace 194 195 char LowerConstantIntrinsics::ID = 0; 196 INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics", 197 "Lower constant intrinsics", false, false) 198 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) 199 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 200 INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics", 201 "Lower constant intrinsics", false, false) 202 203 FunctionPass *llvm::createLowerConstantIntrinsicsPass() { 204 return new LowerConstantIntrinsics(); 205 } 206