xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
18bcb0991SDimitry Andric //===- LowerConstantIntrinsics.cpp - Lower constant intrinsic calls -------===//
28bcb0991SDimitry Andric //
38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68bcb0991SDimitry Andric //
78bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
88bcb0991SDimitry Andric //
98bcb0991SDimitry Andric // This pass lowers all remaining 'objectsize' 'is.constant' intrinsic calls
108bcb0991SDimitry Andric // and provides constant propagation and basic CFG cleanup on the result.
118bcb0991SDimitry Andric //
128bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
138bcb0991SDimitry Andric 
148bcb0991SDimitry Andric #include "llvm/Transforms/Scalar/LowerConstantIntrinsics.h"
158bcb0991SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
165ffd83dbSDimitry Andric #include "llvm/ADT/SetVector.h"
178bcb0991SDimitry Andric #include "llvm/ADT/Statistic.h"
18fe6060f1SDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h"
195ffd83dbSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
208bcb0991SDimitry Andric #include "llvm/Analysis/InstructionSimplify.h"
218bcb0991SDimitry Andric #include "llvm/Analysis/MemoryBuiltins.h"
228bcb0991SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h"
238bcb0991SDimitry Andric #include "llvm/IR/BasicBlock.h"
248bcb0991SDimitry Andric #include "llvm/IR/Constants.h"
25fe6060f1SDimitry Andric #include "llvm/IR/Dominators.h"
268bcb0991SDimitry Andric #include "llvm/IR/Function.h"
278bcb0991SDimitry Andric #include "llvm/IR/Instructions.h"
288bcb0991SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
298bcb0991SDimitry Andric #include "llvm/IR/PatternMatch.h"
30480093f4SDimitry Andric #include "llvm/InitializePasses.h"
318bcb0991SDimitry Andric #include "llvm/Pass.h"
328bcb0991SDimitry Andric #include "llvm/Transforms/Scalar.h"
338bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
34*bdd1243dSDimitry Andric #include <optional>
358bcb0991SDimitry Andric 
368bcb0991SDimitry Andric using namespace llvm;
378bcb0991SDimitry Andric using namespace llvm::PatternMatch;
388bcb0991SDimitry Andric 
398bcb0991SDimitry Andric #define DEBUG_TYPE "lower-is-constant-intrinsic"
408bcb0991SDimitry Andric 
418bcb0991SDimitry Andric STATISTIC(IsConstantIntrinsicsHandled,
428bcb0991SDimitry Andric           "Number of 'is.constant' intrinsic calls handled");
438bcb0991SDimitry Andric STATISTIC(ObjectSizeIntrinsicsHandled,
448bcb0991SDimitry Andric           "Number of 'objectsize' intrinsic calls handled");
458bcb0991SDimitry Andric 
468bcb0991SDimitry Andric static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) {
4723408297SDimitry Andric   if (auto *C = dyn_cast<Constant>(II->getOperand(0)))
4823408297SDimitry Andric     if (C->isManifestConstant())
4923408297SDimitry Andric       return ConstantInt::getTrue(II->getType());
5023408297SDimitry Andric   return ConstantInt::getFalse(II->getType());
518bcb0991SDimitry Andric }
528bcb0991SDimitry Andric 
538bcb0991SDimitry Andric static bool replaceConditionalBranchesOnConstant(Instruction *II,
54fe6060f1SDimitry Andric                                                  Value *NewValue,
55fe6060f1SDimitry Andric                                                  DomTreeUpdater *DTU) {
568bcb0991SDimitry Andric   bool HasDeadBlocks = false;
57349cc55cSDimitry Andric   SmallSetVector<Instruction *, 8> UnsimplifiedUsers;
588bcb0991SDimitry Andric   replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr,
59349cc55cSDimitry Andric                                 &UnsimplifiedUsers);
60349cc55cSDimitry Andric   // UnsimplifiedUsers can contain PHI nodes that may be removed when
61349cc55cSDimitry Andric   // replacing the branch instructions, so use a value handle worklist
62349cc55cSDimitry Andric   // to handle those possibly removed instructions.
63349cc55cSDimitry Andric   SmallVector<WeakVH, 8> Worklist(UnsimplifiedUsers.begin(),
64349cc55cSDimitry Andric                                   UnsimplifiedUsers.end());
65349cc55cSDimitry Andric 
66349cc55cSDimitry Andric   for (auto &VH : Worklist) {
67349cc55cSDimitry Andric     BranchInst *BI = dyn_cast_or_null<BranchInst>(VH);
688bcb0991SDimitry Andric     if (!BI)
698bcb0991SDimitry Andric       continue;
708bcb0991SDimitry Andric     if (BI->isUnconditional())
718bcb0991SDimitry Andric       continue;
728bcb0991SDimitry Andric 
738bcb0991SDimitry Andric     BasicBlock *Target, *Other;
748bcb0991SDimitry Andric     if (match(BI->getOperand(0), m_Zero())) {
758bcb0991SDimitry Andric       Target = BI->getSuccessor(1);
768bcb0991SDimitry Andric       Other = BI->getSuccessor(0);
778bcb0991SDimitry Andric     } else if (match(BI->getOperand(0), m_One())) {
788bcb0991SDimitry Andric       Target = BI->getSuccessor(0);
798bcb0991SDimitry Andric       Other = BI->getSuccessor(1);
808bcb0991SDimitry Andric     } else {
818bcb0991SDimitry Andric       Target = nullptr;
828bcb0991SDimitry Andric       Other = nullptr;
838bcb0991SDimitry Andric     }
848bcb0991SDimitry Andric     if (Target && Target != Other) {
858bcb0991SDimitry Andric       BasicBlock *Source = BI->getParent();
868bcb0991SDimitry Andric       Other->removePredecessor(Source);
878bcb0991SDimitry Andric       BI->eraseFromParent();
888bcb0991SDimitry Andric       BranchInst::Create(Target, Source);
89fe6060f1SDimitry Andric       if (DTU)
90fe6060f1SDimitry Andric         DTU->applyUpdates({{DominatorTree::Delete, Source, Other}});
91e8d8bef9SDimitry Andric       if (pred_empty(Other))
928bcb0991SDimitry Andric         HasDeadBlocks = true;
938bcb0991SDimitry Andric     }
948bcb0991SDimitry Andric   }
958bcb0991SDimitry Andric   return HasDeadBlocks;
968bcb0991SDimitry Andric }
978bcb0991SDimitry Andric 
9881ad6265SDimitry Andric static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo &TLI,
99fe6060f1SDimitry Andric                                     DominatorTree *DT) {
100*bdd1243dSDimitry Andric   std::optional<DomTreeUpdater> DTU;
101fe6060f1SDimitry Andric   if (DT)
102fe6060f1SDimitry Andric     DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);
103fe6060f1SDimitry Andric 
1048bcb0991SDimitry Andric   bool HasDeadBlocks = false;
1058bcb0991SDimitry Andric   const auto &DL = F.getParent()->getDataLayout();
1068bcb0991SDimitry Andric   SmallVector<WeakTrackingVH, 8> Worklist;
1078bcb0991SDimitry Andric 
1088bcb0991SDimitry Andric   ReversePostOrderTraversal<Function *> RPOT(&F);
1098bcb0991SDimitry Andric   for (BasicBlock *BB : RPOT) {
1108bcb0991SDimitry Andric     for (Instruction &I: *BB) {
1118bcb0991SDimitry Andric       IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
1128bcb0991SDimitry Andric       if (!II)
1138bcb0991SDimitry Andric         continue;
1148bcb0991SDimitry Andric       switch (II->getIntrinsicID()) {
1158bcb0991SDimitry Andric       default:
1168bcb0991SDimitry Andric         break;
1178bcb0991SDimitry Andric       case Intrinsic::is_constant:
1188bcb0991SDimitry Andric       case Intrinsic::objectsize:
1198bcb0991SDimitry Andric         Worklist.push_back(WeakTrackingVH(&I));
1208bcb0991SDimitry Andric         break;
1218bcb0991SDimitry Andric       }
1228bcb0991SDimitry Andric     }
1238bcb0991SDimitry Andric   }
1248bcb0991SDimitry Andric   for (WeakTrackingVH &VH: Worklist) {
1258bcb0991SDimitry Andric     // Items on the worklist can be mutated by earlier recursive replaces.
1268bcb0991SDimitry Andric     // This can remove the intrinsic as dead (VH == null), but also replace
1278bcb0991SDimitry Andric     // the intrinsic in place.
1288bcb0991SDimitry Andric     if (!VH)
1298bcb0991SDimitry Andric       continue;
1308bcb0991SDimitry Andric     IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH);
1318bcb0991SDimitry Andric     if (!II)
1328bcb0991SDimitry Andric       continue;
1338bcb0991SDimitry Andric     Value *NewValue;
1348bcb0991SDimitry Andric     switch (II->getIntrinsicID()) {
1358bcb0991SDimitry Andric     default:
1368bcb0991SDimitry Andric       continue;
1378bcb0991SDimitry Andric     case Intrinsic::is_constant:
1388bcb0991SDimitry Andric       NewValue = lowerIsConstantIntrinsic(II);
1398bcb0991SDimitry Andric       IsConstantIntrinsicsHandled++;
1408bcb0991SDimitry Andric       break;
1418bcb0991SDimitry Andric     case Intrinsic::objectsize:
14281ad6265SDimitry Andric       NewValue = lowerObjectSizeCall(II, DL, &TLI, true);
1438bcb0991SDimitry Andric       ObjectSizeIntrinsicsHandled++;
1448bcb0991SDimitry Andric       break;
1458bcb0991SDimitry Andric     }
146fe6060f1SDimitry Andric     HasDeadBlocks |= replaceConditionalBranchesOnConstant(
147*bdd1243dSDimitry Andric         II, NewValue, DTU ? &*DTU : nullptr);
1488bcb0991SDimitry Andric   }
1498bcb0991SDimitry Andric   if (HasDeadBlocks)
150*bdd1243dSDimitry Andric     removeUnreachableBlocks(F, DTU ? &*DTU : nullptr);
1518bcb0991SDimitry Andric   return !Worklist.empty();
1528bcb0991SDimitry Andric }
1538bcb0991SDimitry Andric 
1548bcb0991SDimitry Andric PreservedAnalyses
1558bcb0991SDimitry Andric LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) {
15681ad6265SDimitry Andric   if (lowerConstantIntrinsics(F, AM.getResult<TargetLibraryAnalysis>(F),
157fe6060f1SDimitry Andric                               AM.getCachedResult<DominatorTreeAnalysis>(F))) {
1585ffd83dbSDimitry Andric     PreservedAnalyses PA;
159fe6060f1SDimitry Andric     PA.preserve<DominatorTreeAnalysis>();
1605ffd83dbSDimitry Andric     return PA;
1615ffd83dbSDimitry Andric   }
1628bcb0991SDimitry Andric 
1638bcb0991SDimitry Andric   return PreservedAnalyses::all();
1648bcb0991SDimitry Andric }
1658bcb0991SDimitry Andric 
1668bcb0991SDimitry Andric namespace {
1678bcb0991SDimitry Andric /// Legacy pass for lowering is.constant intrinsics out of the IR.
1688bcb0991SDimitry Andric ///
1698bcb0991SDimitry Andric /// When this pass is run over a function it converts is.constant intrinsics
1705ffd83dbSDimitry Andric /// into 'true' or 'false'. This complements the normal constant folding
1718bcb0991SDimitry Andric /// to 'true' as part of Instruction Simplify passes.
1728bcb0991SDimitry Andric class LowerConstantIntrinsics : public FunctionPass {
1738bcb0991SDimitry Andric public:
1748bcb0991SDimitry Andric   static char ID;
1758bcb0991SDimitry Andric   LowerConstantIntrinsics() : FunctionPass(ID) {
1768bcb0991SDimitry Andric     initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry());
1778bcb0991SDimitry Andric   }
1788bcb0991SDimitry Andric 
1798bcb0991SDimitry Andric   bool runOnFunction(Function &F) override {
18081ad6265SDimitry Andric     const TargetLibraryInfo &TLI =
18181ad6265SDimitry Andric         getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
182fe6060f1SDimitry Andric     DominatorTree *DT = nullptr;
183fe6060f1SDimitry Andric     if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
184fe6060f1SDimitry Andric       DT = &DTWP->getDomTree();
185fe6060f1SDimitry Andric     return lowerConstantIntrinsics(F, TLI, DT);
1868bcb0991SDimitry Andric   }
1875ffd83dbSDimitry Andric 
1885ffd83dbSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
18981ad6265SDimitry Andric     AU.addRequired<TargetLibraryInfoWrapperPass>();
1905ffd83dbSDimitry Andric     AU.addPreserved<GlobalsAAWrapperPass>();
191fe6060f1SDimitry Andric     AU.addPreserved<DominatorTreeWrapperPass>();
1925ffd83dbSDimitry Andric   }
1938bcb0991SDimitry Andric };
1948bcb0991SDimitry Andric } // namespace
1958bcb0991SDimitry Andric 
1968bcb0991SDimitry Andric char LowerConstantIntrinsics::ID = 0;
197fe6060f1SDimitry Andric INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics",
198fe6060f1SDimitry Andric                       "Lower constant intrinsics", false, false)
19981ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
200fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
201fe6060f1SDimitry Andric INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics",
2028bcb0991SDimitry Andric                     "Lower constant intrinsics", false, false)
2038bcb0991SDimitry Andric 
2048bcb0991SDimitry Andric FunctionPass *llvm::createLowerConstantIntrinsicsPass() {
2058bcb0991SDimitry Andric   return new LowerConstantIntrinsics();
2068bcb0991SDimitry Andric }
207