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