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