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