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