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