blob: d0fcf38b5a7bd54d9415248a378b4ecc8cd27969 [file] [log] [blame]
Joerg Sonnenberger9681ea92019-10-14 16:15:14 +00001//===- 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
32using namespace llvm;
33using namespace llvm::PatternMatch;
34
35#define DEBUG_TYPE "lower-is-constant-intrinsic"
36
37STATISTIC(IsConstantIntrinsicsHandled,
38 "Number of 'is.constant' intrinsic calls handled");
39STATISTIC(ObjectSizeIntrinsicsHandled,
40 "Number of 'objectsize' intrinsic calls handled");
41
42static 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
49static 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
85static 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
135PreservedAnalyses
136LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) {
137 if (lowerConstantIntrinsics(F, AM.getCachedResult<TargetLibraryAnalysis>(F)))
138 return PreservedAnalyses::none();
139
140 return PreservedAnalyses::all();
141}
142
143namespace {
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.
149class LowerConstantIntrinsics : public FunctionPass {
150public:
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
164char LowerConstantIntrinsics::ID = 0;
165INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics",
166 "Lower constant intrinsics", false, false)
167
168FunctionPass *llvm::createLowerConstantIntrinsicsPass() {
169 return new LowerConstantIntrinsics();
170}