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