170 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This pass lowers all remaining 'objectsize' 'is.constant' intrinsic calls10// 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/DomTreeUpdater.h"19#include "llvm/Analysis/GlobalsModRef.h"20#include "llvm/Analysis/InstructionSimplify.h"21#include "llvm/Analysis/MemoryBuiltins.h"22#include "llvm/Analysis/TargetLibraryInfo.h"23#include "llvm/IR/BasicBlock.h"24#include "llvm/IR/Constants.h"25#include "llvm/IR/Dominators.h"26#include "llvm/IR/Function.h"27#include "llvm/IR/Instructions.h"28#include "llvm/IR/IntrinsicInst.h"29#include "llvm/IR/PatternMatch.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#include <optional>35 36using namespace llvm;37using namespace llvm::PatternMatch;38 39#define DEBUG_TYPE "lower-is-constant-intrinsic"40 41STATISTIC(IsConstantIntrinsicsHandled,42 "Number of 'is.constant' intrinsic calls handled");43STATISTIC(ObjectSizeIntrinsicsHandled,44 "Number of 'objectsize' intrinsic calls handled");45 46static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) {47 if (auto *C = dyn_cast<Constant>(II->getOperand(0)))48 if (C->isManifestConstant())49 return ConstantInt::getTrue(II->getType());50 return ConstantInt::getFalse(II->getType());51}52 53static bool replaceConditionalBranchesOnConstant(Instruction *II,54 Value *NewValue,55 DomTreeUpdater *DTU) {56 bool HasDeadBlocks = false;57 SmallSetVector<Instruction *, 8> UnsimplifiedUsers;58 replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr,59 &UnsimplifiedUsers);60 // UnsimplifiedUsers can contain PHI nodes that may be removed when61 // replacing the branch instructions, so use a value handle worklist62 // to handle those possibly removed instructions.63 SmallVector<WeakVH, 8> Worklist(UnsimplifiedUsers.begin(),64 UnsimplifiedUsers.end());65 66 for (auto &VH : Worklist) {67 BranchInst *BI = dyn_cast_or_null<BranchInst>(VH);68 if (!BI)69 continue;70 if (BI->isUnconditional())71 continue;72 73 BasicBlock *Target, *Other;74 if (match(BI->getOperand(0), m_Zero())) {75 Target = BI->getSuccessor(1);76 Other = BI->getSuccessor(0);77 } else if (match(BI->getOperand(0), m_One())) {78 Target = BI->getSuccessor(0);79 Other = BI->getSuccessor(1);80 } else {81 Target = nullptr;82 Other = nullptr;83 }84 if (Target && Target != Other) {85 BasicBlock *Source = BI->getParent();86 Other->removePredecessor(Source);87 88 Instruction *NewBI = BranchInst::Create(Target, Source);89 NewBI->setDebugLoc(BI->getDebugLoc());90 BI->eraseFromParent();91 92 if (DTU)93 DTU->applyUpdates({{DominatorTree::Delete, Source, Other}});94 if (pred_empty(Other))95 HasDeadBlocks = true;96 }97 }98 return HasDeadBlocks;99}100 101bool llvm::lowerConstantIntrinsics(Function &F, const TargetLibraryInfo &TLI,102 DominatorTree *DT) {103 std::optional<DomTreeUpdater> DTU;104 if (DT)105 DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);106 107 bool HasDeadBlocks = false;108 const auto &DL = F.getDataLayout();109 SmallVector<WeakTrackingVH, 8> Worklist;110 111 ReversePostOrderTraversal<Function *> RPOT(&F);112 for (BasicBlock *BB : RPOT) {113 for (Instruction &I: *BB) {114 IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);115 if (!II)116 continue;117 switch (II->getIntrinsicID()) {118 default:119 break;120 case Intrinsic::is_constant:121 case Intrinsic::objectsize:122 Worklist.push_back(WeakTrackingVH(&I));123 break;124 }125 }126 }127 for (WeakTrackingVH &VH: Worklist) {128 // Items on the worklist can be mutated by earlier recursive replaces.129 // This can remove the intrinsic as dead (VH == null), but also replace130 // the intrinsic in place.131 if (!VH)132 continue;133 IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH);134 if (!II)135 continue;136 Value *NewValue;137 switch (II->getIntrinsicID()) {138 default:139 continue;140 case Intrinsic::is_constant:141 NewValue = lowerIsConstantIntrinsic(II);142 LLVM_DEBUG(dbgs() << "Folding " << *II << " to " << *NewValue << "\n");143 IsConstantIntrinsicsHandled++;144 break;145 case Intrinsic::objectsize:146 NewValue = lowerObjectSizeCall(II, DL, &TLI, true);147 LLVM_DEBUG(dbgs() << "Folding " << *II << " to " << *NewValue << "\n");148 ObjectSizeIntrinsicsHandled++;149 break;150 }151 HasDeadBlocks |= replaceConditionalBranchesOnConstant(152 II, NewValue, DTU ? &*DTU : nullptr);153 }154 if (HasDeadBlocks)155 removeUnreachableBlocks(F, DTU ? &*DTU : nullptr);156 return !Worklist.empty();157}158 159PreservedAnalyses160LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) {161 if (lowerConstantIntrinsics(F, AM.getResult<TargetLibraryAnalysis>(F),162 AM.getCachedResult<DominatorTreeAnalysis>(F))) {163 PreservedAnalyses PA;164 PA.preserve<DominatorTreeAnalysis>();165 return PA;166 }167 168 return PreservedAnalyses::all();169}170