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