2019-10-14 18:15:14 +02:00
|
|
|
//===- LowerConstantIntrinsics.cpp - Lower constant intrinsic calls -------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This pass lowers all remaining 'objectsize' 'is.constant' intrinsic calls
|
|
|
|
// and provides constant propagation and basic CFG cleanup on the result.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Transforms/Scalar/LowerConstantIntrinsics.h"
|
|
|
|
#include "llvm/ADT/PostOrderIterator.h"
|
2020-05-25 14:27:10 +02:00
|
|
|
#include "llvm/ADT/SetVector.h"
|
2019-10-14 18:15:14 +02:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2021-01-29 19:33:49 +01:00
|
|
|
#include "llvm/Analysis/DomTreeUpdater.h"
|
2020-07-02 14:53:20 +02:00
|
|
|
#include "llvm/Analysis/GlobalsModRef.h"
|
2019-10-14 18:15:14 +02:00
|
|
|
#include "llvm/Analysis/InstructionSimplify.h"
|
|
|
|
#include "llvm/Analysis/MemoryBuiltins.h"
|
|
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/Constants.h"
|
2021-01-29 19:33:49 +01:00
|
|
|
#include "llvm/IR/Dominators.h"
|
2019-10-14 18:15:14 +02:00
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
|
|
#include "llvm/IR/Intrinsics.h"
|
|
|
|
#include "llvm/IR/PatternMatch.h"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-13 22:15:01 +01:00
|
|
|
#include "llvm/InitializePasses.h"
|
2019-10-14 18:15:14 +02:00
|
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Transforms/Scalar.h"
|
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::PatternMatch;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "lower-is-constant-intrinsic"
|
|
|
|
|
|
|
|
STATISTIC(IsConstantIntrinsicsHandled,
|
|
|
|
"Number of 'is.constant' intrinsic calls handled");
|
|
|
|
STATISTIC(ObjectSizeIntrinsicsHandled,
|
|
|
|
"Number of 'objectsize' intrinsic calls handled");
|
|
|
|
|
|
|
|
static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) {
|
|
|
|
Value *Op = II->getOperand(0);
|
|
|
|
|
|
|
|
return isa<Constant>(Op) ? ConstantInt::getTrue(II->getType())
|
|
|
|
: ConstantInt::getFalse(II->getType());
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool replaceConditionalBranchesOnConstant(Instruction *II,
|
2021-01-29 19:33:49 +01:00
|
|
|
Value *NewValue,
|
|
|
|
DomTreeUpdater *DTU) {
|
2019-10-14 18:15:14 +02:00
|
|
|
bool HasDeadBlocks = false;
|
|
|
|
SmallSetVector<Instruction *, 8> Worklist;
|
|
|
|
replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr,
|
|
|
|
&Worklist);
|
|
|
|
for (auto I : Worklist) {
|
|
|
|
BranchInst *BI = dyn_cast<BranchInst>(I);
|
|
|
|
if (!BI)
|
|
|
|
continue;
|
|
|
|
if (BI->isUnconditional())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
BasicBlock *Target, *Other;
|
|
|
|
if (match(BI->getOperand(0), m_Zero())) {
|
|
|
|
Target = BI->getSuccessor(1);
|
|
|
|
Other = BI->getSuccessor(0);
|
|
|
|
} else if (match(BI->getOperand(0), m_One())) {
|
|
|
|
Target = BI->getSuccessor(0);
|
|
|
|
Other = BI->getSuccessor(1);
|
|
|
|
} else {
|
|
|
|
Target = nullptr;
|
|
|
|
Other = nullptr;
|
|
|
|
}
|
|
|
|
if (Target && Target != Other) {
|
|
|
|
BasicBlock *Source = BI->getParent();
|
|
|
|
Other->removePredecessor(Source);
|
|
|
|
BI->eraseFromParent();
|
|
|
|
BranchInst::Create(Target, Source);
|
2021-01-29 19:33:49 +01:00
|
|
|
if (DTU)
|
|
|
|
DTU->applyUpdates({{DominatorTree::Delete, Source, Other}});
|
2020-11-17 07:09:14 +01:00
|
|
|
if (pred_empty(Other))
|
2019-10-14 18:15:14 +02:00
|
|
|
HasDeadBlocks = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return HasDeadBlocks;
|
|
|
|
}
|
|
|
|
|
2021-01-29 19:33:49 +01:00
|
|
|
static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI,
|
|
|
|
DominatorTree *DT) {
|
|
|
|
Optional<DomTreeUpdater> DTU;
|
|
|
|
if (DT)
|
|
|
|
DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);
|
|
|
|
|
2019-10-14 18:15:14 +02:00
|
|
|
bool HasDeadBlocks = false;
|
|
|
|
const auto &DL = F.getParent()->getDataLayout();
|
|
|
|
SmallVector<WeakTrackingVH, 8> Worklist;
|
|
|
|
|
|
|
|
ReversePostOrderTraversal<Function *> RPOT(&F);
|
|
|
|
for (BasicBlock *BB : RPOT) {
|
|
|
|
for (Instruction &I: *BB) {
|
|
|
|
IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
|
|
|
|
if (!II)
|
|
|
|
continue;
|
|
|
|
switch (II->getIntrinsicID()) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case Intrinsic::is_constant:
|
|
|
|
case Intrinsic::objectsize:
|
|
|
|
Worklist.push_back(WeakTrackingVH(&I));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (WeakTrackingVH &VH: Worklist) {
|
|
|
|
// Items on the worklist can be mutated by earlier recursive replaces.
|
|
|
|
// This can remove the intrinsic as dead (VH == null), but also replace
|
|
|
|
// the intrinsic in place.
|
|
|
|
if (!VH)
|
|
|
|
continue;
|
|
|
|
IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH);
|
|
|
|
if (!II)
|
|
|
|
continue;
|
|
|
|
Value *NewValue;
|
|
|
|
switch (II->getIntrinsicID()) {
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
case Intrinsic::is_constant:
|
|
|
|
NewValue = lowerIsConstantIntrinsic(II);
|
|
|
|
IsConstantIntrinsicsHandled++;
|
|
|
|
break;
|
|
|
|
case Intrinsic::objectsize:
|
|
|
|
NewValue = lowerObjectSizeCall(II, DL, TLI, true);
|
|
|
|
ObjectSizeIntrinsicsHandled++;
|
|
|
|
break;
|
|
|
|
}
|
2021-01-29 19:33:49 +01:00
|
|
|
HasDeadBlocks |= replaceConditionalBranchesOnConstant(
|
|
|
|
II, NewValue, DTU.hasValue() ? DTU.getPointer() : nullptr);
|
2019-10-14 18:15:14 +02:00
|
|
|
}
|
|
|
|
if (HasDeadBlocks)
|
2021-01-29 19:33:49 +01:00
|
|
|
removeUnreachableBlocks(F, DTU.hasValue() ? DTU.getPointer() : nullptr);
|
2019-10-14 18:15:14 +02:00
|
|
|
return !Worklist.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
PreservedAnalyses
|
|
|
|
LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) {
|
2021-01-29 19:33:49 +01:00
|
|
|
if (lowerConstantIntrinsics(F, AM.getCachedResult<TargetLibraryAnalysis>(F),
|
|
|
|
AM.getCachedResult<DominatorTreeAnalysis>(F))) {
|
2020-07-02 14:53:20 +02:00
|
|
|
PreservedAnalyses PA;
|
|
|
|
PA.preserve<GlobalsAA>();
|
2021-01-29 19:33:49 +01:00
|
|
|
PA.preserve<DominatorTreeAnalysis>();
|
2020-07-02 14:53:20 +02:00
|
|
|
return PA;
|
|
|
|
}
|
2019-10-14 18:15:14 +02:00
|
|
|
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// Legacy pass for lowering is.constant intrinsics out of the IR.
|
|
|
|
///
|
|
|
|
/// When this pass is run over a function it converts is.constant intrinsics
|
2020-05-12 09:44:05 +02:00
|
|
|
/// into 'true' or 'false'. This complements the normal constant folding
|
2019-10-14 18:15:14 +02:00
|
|
|
/// to 'true' as part of Instruction Simplify passes.
|
|
|
|
class LowerConstantIntrinsics : public FunctionPass {
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
LowerConstantIntrinsics() : FunctionPass(ID) {
|
|
|
|
initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnFunction(Function &F) override {
|
|
|
|
auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>();
|
|
|
|
const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr;
|
2021-01-29 19:33:49 +01:00
|
|
|
DominatorTree *DT = nullptr;
|
|
|
|
if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
|
|
|
|
DT = &DTWP->getDomTree();
|
|
|
|
return lowerConstantIntrinsics(F, TLI, DT);
|
2019-10-14 18:15:14 +02:00
|
|
|
}
|
2020-07-02 14:53:20 +02:00
|
|
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
AU.addPreserved<GlobalsAAWrapperPass>();
|
2021-01-29 19:33:49 +01:00
|
|
|
AU.addPreserved<DominatorTreeWrapperPass>();
|
2020-07-02 14:53:20 +02:00
|
|
|
}
|
2019-10-14 18:15:14 +02:00
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
char LowerConstantIntrinsics::ID = 0;
|
2021-01-29 19:33:49 +01:00
|
|
|
INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics",
|
|
|
|
"Lower constant intrinsics", false, false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
|
|
INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics",
|
|
|
|
"Lower constant intrinsics", false, false)
|
2019-10-14 18:15:14 +02:00
|
|
|
|
|
|
|
FunctionPass *llvm::createLowerConstantIntrinsicsPass() {
|
|
|
|
return new LowerConstantIntrinsics();
|
|
|
|
}
|