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