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