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"
3206c3fb27SDimitry Andric #include "llvm/Support/Debug.h"
338bcb0991SDimitry Andric #include "llvm/Transforms/Scalar.h"
348bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
35bdd1243dSDimitry Andric #include <optional>
368bcb0991SDimitry Andric
378bcb0991SDimitry Andric using namespace llvm;
388bcb0991SDimitry Andric using namespace llvm::PatternMatch;
398bcb0991SDimitry Andric
408bcb0991SDimitry Andric #define DEBUG_TYPE "lower-is-constant-intrinsic"
418bcb0991SDimitry Andric
428bcb0991SDimitry Andric STATISTIC(IsConstantIntrinsicsHandled,
438bcb0991SDimitry Andric "Number of 'is.constant' intrinsic calls handled");
448bcb0991SDimitry Andric STATISTIC(ObjectSizeIntrinsicsHandled,
458bcb0991SDimitry Andric "Number of 'objectsize' intrinsic calls handled");
468bcb0991SDimitry Andric
lowerIsConstantIntrinsic(IntrinsicInst * II)478bcb0991SDimitry Andric static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) {
4823408297SDimitry Andric if (auto *C = dyn_cast<Constant>(II->getOperand(0)))
4923408297SDimitry Andric if (C->isManifestConstant())
5023408297SDimitry Andric return ConstantInt::getTrue(II->getType());
5123408297SDimitry Andric return ConstantInt::getFalse(II->getType());
528bcb0991SDimitry Andric }
538bcb0991SDimitry Andric
replaceConditionalBranchesOnConstant(Instruction * II,Value * NewValue,DomTreeUpdater * DTU)548bcb0991SDimitry Andric static bool replaceConditionalBranchesOnConstant(Instruction *II,
55fe6060f1SDimitry Andric Value *NewValue,
56fe6060f1SDimitry Andric DomTreeUpdater *DTU) {
578bcb0991SDimitry Andric bool HasDeadBlocks = false;
58349cc55cSDimitry Andric SmallSetVector<Instruction *, 8> UnsimplifiedUsers;
598bcb0991SDimitry Andric replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr,
60349cc55cSDimitry Andric &UnsimplifiedUsers);
61349cc55cSDimitry Andric // UnsimplifiedUsers can contain PHI nodes that may be removed when
62349cc55cSDimitry Andric // replacing the branch instructions, so use a value handle worklist
63349cc55cSDimitry Andric // to handle those possibly removed instructions.
64349cc55cSDimitry Andric SmallVector<WeakVH, 8> Worklist(UnsimplifiedUsers.begin(),
65349cc55cSDimitry Andric UnsimplifiedUsers.end());
66349cc55cSDimitry Andric
67349cc55cSDimitry Andric for (auto &VH : Worklist) {
68349cc55cSDimitry Andric BranchInst *BI = dyn_cast_or_null<BranchInst>(VH);
698bcb0991SDimitry Andric if (!BI)
708bcb0991SDimitry Andric continue;
718bcb0991SDimitry Andric if (BI->isUnconditional())
728bcb0991SDimitry Andric continue;
738bcb0991SDimitry Andric
748bcb0991SDimitry Andric BasicBlock *Target, *Other;
758bcb0991SDimitry Andric if (match(BI->getOperand(0), m_Zero())) {
768bcb0991SDimitry Andric Target = BI->getSuccessor(1);
778bcb0991SDimitry Andric Other = BI->getSuccessor(0);
788bcb0991SDimitry Andric } else if (match(BI->getOperand(0), m_One())) {
798bcb0991SDimitry Andric Target = BI->getSuccessor(0);
808bcb0991SDimitry Andric Other = BI->getSuccessor(1);
818bcb0991SDimitry Andric } else {
828bcb0991SDimitry Andric Target = nullptr;
838bcb0991SDimitry Andric Other = nullptr;
848bcb0991SDimitry Andric }
858bcb0991SDimitry Andric if (Target && Target != Other) {
868bcb0991SDimitry Andric BasicBlock *Source = BI->getParent();
878bcb0991SDimitry Andric Other->removePredecessor(Source);
88*0fca6ea1SDimitry Andric
89*0fca6ea1SDimitry Andric Instruction *NewBI = BranchInst::Create(Target, Source);
90*0fca6ea1SDimitry Andric NewBI->setDebugLoc(BI->getDebugLoc());
918bcb0991SDimitry Andric BI->eraseFromParent();
92*0fca6ea1SDimitry Andric
93fe6060f1SDimitry Andric if (DTU)
94fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Delete, Source, Other}});
95e8d8bef9SDimitry Andric if (pred_empty(Other))
968bcb0991SDimitry Andric HasDeadBlocks = true;
978bcb0991SDimitry Andric }
988bcb0991SDimitry Andric }
998bcb0991SDimitry Andric return HasDeadBlocks;
1008bcb0991SDimitry Andric }
1018bcb0991SDimitry Andric
lowerConstantIntrinsics(Function & F,const TargetLibraryInfo & TLI,DominatorTree * DT)10281ad6265SDimitry Andric static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo &TLI,
103fe6060f1SDimitry Andric DominatorTree *DT) {
104bdd1243dSDimitry Andric std::optional<DomTreeUpdater> DTU;
105fe6060f1SDimitry Andric if (DT)
106fe6060f1SDimitry Andric DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);
107fe6060f1SDimitry Andric
1088bcb0991SDimitry Andric bool HasDeadBlocks = false;
109*0fca6ea1SDimitry Andric const auto &DL = F.getDataLayout();
1108bcb0991SDimitry Andric SmallVector<WeakTrackingVH, 8> Worklist;
1118bcb0991SDimitry Andric
1128bcb0991SDimitry Andric ReversePostOrderTraversal<Function *> RPOT(&F);
1138bcb0991SDimitry Andric for (BasicBlock *BB : RPOT) {
1148bcb0991SDimitry Andric for (Instruction &I: *BB) {
1158bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
1168bcb0991SDimitry Andric if (!II)
1178bcb0991SDimitry Andric continue;
1188bcb0991SDimitry Andric switch (II->getIntrinsicID()) {
1198bcb0991SDimitry Andric default:
1208bcb0991SDimitry Andric break;
1218bcb0991SDimitry Andric case Intrinsic::is_constant:
1228bcb0991SDimitry Andric case Intrinsic::objectsize:
1238bcb0991SDimitry Andric Worklist.push_back(WeakTrackingVH(&I));
1248bcb0991SDimitry Andric break;
1258bcb0991SDimitry Andric }
1268bcb0991SDimitry Andric }
1278bcb0991SDimitry Andric }
1288bcb0991SDimitry Andric for (WeakTrackingVH &VH: Worklist) {
1298bcb0991SDimitry Andric // Items on the worklist can be mutated by earlier recursive replaces.
1308bcb0991SDimitry Andric // This can remove the intrinsic as dead (VH == null), but also replace
1318bcb0991SDimitry Andric // the intrinsic in place.
1328bcb0991SDimitry Andric if (!VH)
1338bcb0991SDimitry Andric continue;
1348bcb0991SDimitry Andric IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH);
1358bcb0991SDimitry Andric if (!II)
1368bcb0991SDimitry Andric continue;
1378bcb0991SDimitry Andric Value *NewValue;
1388bcb0991SDimitry Andric switch (II->getIntrinsicID()) {
1398bcb0991SDimitry Andric default:
1408bcb0991SDimitry Andric continue;
1418bcb0991SDimitry Andric case Intrinsic::is_constant:
1428bcb0991SDimitry Andric NewValue = lowerIsConstantIntrinsic(II);
14306c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Folding " << *II << " to " << *NewValue << "\n");
1448bcb0991SDimitry Andric IsConstantIntrinsicsHandled++;
1458bcb0991SDimitry Andric break;
1468bcb0991SDimitry Andric case Intrinsic::objectsize:
14781ad6265SDimitry Andric NewValue = lowerObjectSizeCall(II, DL, &TLI, true);
14806c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Folding " << *II << " to " << *NewValue << "\n");
1498bcb0991SDimitry Andric ObjectSizeIntrinsicsHandled++;
1508bcb0991SDimitry Andric break;
1518bcb0991SDimitry Andric }
152fe6060f1SDimitry Andric HasDeadBlocks |= replaceConditionalBranchesOnConstant(
153bdd1243dSDimitry Andric II, NewValue, DTU ? &*DTU : nullptr);
1548bcb0991SDimitry Andric }
1558bcb0991SDimitry Andric if (HasDeadBlocks)
156bdd1243dSDimitry Andric removeUnreachableBlocks(F, DTU ? &*DTU : nullptr);
1578bcb0991SDimitry Andric return !Worklist.empty();
1588bcb0991SDimitry Andric }
1598bcb0991SDimitry Andric
1608bcb0991SDimitry Andric PreservedAnalyses
run(Function & F,FunctionAnalysisManager & AM)1618bcb0991SDimitry Andric LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) {
16281ad6265SDimitry Andric if (lowerConstantIntrinsics(F, AM.getResult<TargetLibraryAnalysis>(F),
163fe6060f1SDimitry Andric AM.getCachedResult<DominatorTreeAnalysis>(F))) {
1645ffd83dbSDimitry Andric PreservedAnalyses PA;
165fe6060f1SDimitry Andric PA.preserve<DominatorTreeAnalysis>();
1665ffd83dbSDimitry Andric return PA;
1675ffd83dbSDimitry Andric }
1688bcb0991SDimitry Andric
1698bcb0991SDimitry Andric return PreservedAnalyses::all();
1708bcb0991SDimitry Andric }
1718bcb0991SDimitry Andric
1728bcb0991SDimitry Andric namespace {
1738bcb0991SDimitry Andric /// Legacy pass for lowering is.constant intrinsics out of the IR.
1748bcb0991SDimitry Andric ///
1758bcb0991SDimitry Andric /// When this pass is run over a function it converts is.constant intrinsics
1765ffd83dbSDimitry Andric /// into 'true' or 'false'. This complements the normal constant folding
1778bcb0991SDimitry Andric /// to 'true' as part of Instruction Simplify passes.
1788bcb0991SDimitry Andric class LowerConstantIntrinsics : public FunctionPass {
1798bcb0991SDimitry Andric public:
1808bcb0991SDimitry Andric static char ID;
LowerConstantIntrinsics()1818bcb0991SDimitry Andric LowerConstantIntrinsics() : FunctionPass(ID) {
1828bcb0991SDimitry Andric initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry());
1838bcb0991SDimitry Andric }
1848bcb0991SDimitry Andric
runOnFunction(Function & F)1858bcb0991SDimitry Andric bool runOnFunction(Function &F) override {
18681ad6265SDimitry Andric const TargetLibraryInfo &TLI =
18781ad6265SDimitry Andric getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
188fe6060f1SDimitry Andric DominatorTree *DT = nullptr;
189fe6060f1SDimitry Andric if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
190fe6060f1SDimitry Andric DT = &DTWP->getDomTree();
191fe6060f1SDimitry Andric return lowerConstantIntrinsics(F, TLI, DT);
1928bcb0991SDimitry Andric }
1935ffd83dbSDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const1945ffd83dbSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
19581ad6265SDimitry Andric AU.addRequired<TargetLibraryInfoWrapperPass>();
1965ffd83dbSDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>();
197fe6060f1SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>();
1985ffd83dbSDimitry Andric }
1998bcb0991SDimitry Andric };
2008bcb0991SDimitry Andric } // namespace
2018bcb0991SDimitry Andric
2028bcb0991SDimitry Andric char LowerConstantIntrinsics::ID = 0;
203fe6060f1SDimitry Andric INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics",
204fe6060f1SDimitry Andric "Lower constant intrinsics", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)20581ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
206fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
207fe6060f1SDimitry Andric INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics",
2088bcb0991SDimitry Andric "Lower constant intrinsics", false, false)
2098bcb0991SDimitry Andric
2108bcb0991SDimitry Andric FunctionPass *llvm::createLowerConstantIntrinsicsPass() {
2118bcb0991SDimitry Andric return new LowerConstantIntrinsics();
2128bcb0991SDimitry Andric }
213