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
35using namespace llvm;
36using namespace llvm::PatternMatch;
37
38#define DEBUG_TYPE "lower-is-constant-intrinsic"
39
40STATISTIC(IsConstantIntrinsicsHandled,
41          "Number of 'is.constant' intrinsic calls handled");
42STATISTIC(ObjectSizeIntrinsicsHandled,
43          "Number of 'objectsize' intrinsic calls handled");
44
45static 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
52static 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_begin(Other) == pred_end(Other))
82        HasDeadBlocks = true;
83    }
84  }
85  return HasDeadBlocks;
86}
87
88static 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
138PreservedAnalyses
139LowerConstantIntrinsicsPass::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
150namespace {
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.
156class LowerConstantIntrinsics : public FunctionPass {
157public:
158  static char ID;
159  LowerConstantIntrinsics() : FunctionPass(ID) {
160    initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry());
161  }
162
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
169  void getAnalysisUsage(AnalysisUsage &AU) const override {
170    AU.addPreserved<GlobalsAAWrapperPass>();
171  }
172};
173} // namespace
174
175char LowerConstantIntrinsics::ID = 0;
176INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics",
177                "Lower constant intrinsics", false, false)
178
179FunctionPass *llvm::createLowerConstantIntrinsicsPass() {
180  return new LowerConstantIntrinsics();
181}
182