1d3a4cbe1SMax Kazantsev //===-- InstructionPrecedenceTracking.cpp -----------------------*- C++ -*-===//
2d3a4cbe1SMax Kazantsev //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d3a4cbe1SMax Kazantsev //
7d3a4cbe1SMax Kazantsev //===----------------------------------------------------------------------===//
8d3a4cbe1SMax Kazantsev // Implements a class that is able to define some instructions as "special"
9d3a4cbe1SMax Kazantsev // (e.g. as having implicit control flow, or writing memory, or having another
10d3a4cbe1SMax Kazantsev // interesting property) and then efficiently answers queries of the types:
11d3a4cbe1SMax Kazantsev // 1. Are there any special instructions in the block of interest?
12d3a4cbe1SMax Kazantsev // 2. Return first of the special instructions in the given block;
13d3a4cbe1SMax Kazantsev // 3. Check if the given instruction is preceeded by the first special
14d3a4cbe1SMax Kazantsev // instruction in the same block.
15d3a4cbe1SMax Kazantsev // The class provides caching that allows to answer these queries quickly. The
16d3a4cbe1SMax Kazantsev // user must make sure that the cached data is invalidated properly whenever
17d3a4cbe1SMax Kazantsev // a content of some tracked block is changed.
18d3a4cbe1SMax Kazantsev //===----------------------------------------------------------------------===//
19d3a4cbe1SMax Kazantsev
20d3a4cbe1SMax Kazantsev #include "llvm/Analysis/InstructionPrecedenceTracking.h"
21d3a4cbe1SMax Kazantsev #include "llvm/Analysis/ValueTracking.h"
22edf31b4dSPhilip Reames #include "llvm/ADT/Statistic.h"
2324383cd7SMax Kazantsev #include "llvm/IR/PatternMatch.h"
244c1a1d3cSReid Kleckner #include "llvm/Support/CommandLine.h"
25d3a4cbe1SMax Kazantsev
26d3a4cbe1SMax Kazantsev using namespace llvm;
27d3a4cbe1SMax Kazantsev
28edf31b4dSPhilip Reames #define DEBUG_TYPE "ipt"
29edf31b4dSPhilip Reames STATISTIC(NumInstScanned, "Number of insts scanned while updating ibt");
30edf31b4dSPhilip Reames
318a9e059eSMax Kazantsev #ifndef NDEBUG
328a9e059eSMax Kazantsev static cl::opt<bool> ExpensiveAsserts(
338a9e059eSMax Kazantsev "ipt-expensive-asserts",
348a9e059eSMax Kazantsev cl::desc("Perform expensive assert validation on every query to Instruction"
358a9e059eSMax Kazantsev " Precedence Tracking"),
368a9e059eSMax Kazantsev cl::init(false), cl::Hidden);
378a9e059eSMax Kazantsev #endif
388a9e059eSMax Kazantsev
getFirstSpecialInstruction(const BasicBlock * BB)39d3a4cbe1SMax Kazantsev const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction(
40d3a4cbe1SMax Kazantsev const BasicBlock *BB) {
418a9e059eSMax Kazantsev #ifndef NDEBUG
428a9e059eSMax Kazantsev // If there is a bug connected to invalid cache, turn on ExpensiveAsserts to
438a9e059eSMax Kazantsev // catch this situation as early as possible.
448a9e059eSMax Kazantsev if (ExpensiveAsserts)
458a9e059eSMax Kazantsev validateAll();
468a9e059eSMax Kazantsev else
478a9e059eSMax Kazantsev validate(BB);
488a9e059eSMax Kazantsev #endif
498a9e059eSMax Kazantsev
503781a46cSArthur Eubanks if (FirstSpecialInsts.find(BB) == FirstSpecialInsts.end()) {
513781a46cSArthur Eubanks fill(BB);
523781a46cSArthur Eubanks assert(FirstSpecialInsts.find(BB) != FirstSpecialInsts.end() && "Must be!");
536afebe1dSMax Kazantsev }
543781a46cSArthur Eubanks return FirstSpecialInsts[BB];
55d3a4cbe1SMax Kazantsev }
56d3a4cbe1SMax Kazantsev
hasSpecialInstructions(const BasicBlock * BB)57d3a4cbe1SMax Kazantsev bool InstructionPrecedenceTracking::hasSpecialInstructions(
58d3a4cbe1SMax Kazantsev const BasicBlock *BB) {
59d3a4cbe1SMax Kazantsev return getFirstSpecialInstruction(BB) != nullptr;
60d3a4cbe1SMax Kazantsev }
61d3a4cbe1SMax Kazantsev
isPreceededBySpecialInstruction(const Instruction * Insn)62d3a4cbe1SMax Kazantsev bool InstructionPrecedenceTracking::isPreceededBySpecialInstruction(
63d3a4cbe1SMax Kazantsev const Instruction *Insn) {
6490edc98cSMax Kazantsev const Instruction *MaybeFirstSpecial =
65d3a4cbe1SMax Kazantsev getFirstSpecialInstruction(Insn->getParent());
6654d01cbcSNikita Popov return MaybeFirstSpecial && MaybeFirstSpecial->comesBefore(Insn);
67d3a4cbe1SMax Kazantsev }
68d3a4cbe1SMax Kazantsev
fill(const BasicBlock * BB)693781a46cSArthur Eubanks void InstructionPrecedenceTracking::fill(const BasicBlock *BB) {
703781a46cSArthur Eubanks FirstSpecialInsts.erase(BB);
71*601b3a13SKazu Hirata for (const auto &I : *BB) {
723781a46cSArthur Eubanks NumInstScanned++;
733781a46cSArthur Eubanks if (isSpecialInstruction(&I)) {
743781a46cSArthur Eubanks FirstSpecialInsts[BB] = &I;
753781a46cSArthur Eubanks return;
763781a46cSArthur Eubanks }
773781a46cSArthur Eubanks }
783781a46cSArthur Eubanks
793781a46cSArthur Eubanks // Mark this block as having no special instructions.
803781a46cSArthur Eubanks FirstSpecialInsts[BB] = nullptr;
813781a46cSArthur Eubanks }
823781a46cSArthur Eubanks
838a9e059eSMax Kazantsev #ifndef NDEBUG
validate(const BasicBlock * BB) const848a9e059eSMax Kazantsev void InstructionPrecedenceTracking::validate(const BasicBlock *BB) const {
856afebe1dSMax Kazantsev auto It = FirstSpecialInsts.find(BB);
866afebe1dSMax Kazantsev // Bail if we don't have anything cached for this block.
876afebe1dSMax Kazantsev if (It == FirstSpecialInsts.end())
886afebe1dSMax Kazantsev return;
896afebe1dSMax Kazantsev
903781a46cSArthur Eubanks for (const Instruction &Insn : *BB)
913781a46cSArthur Eubanks if (isSpecialInstruction(&Insn)) {
923781a46cSArthur Eubanks assert(It->second == &Insn &&
93baea663aSPhilip Reames "Cached first special instruction is wrong!");
943781a46cSArthur Eubanks return;
958a9e059eSMax Kazantsev }
968a9e059eSMax Kazantsev
976afebe1dSMax Kazantsev assert(It->second == nullptr &&
986afebe1dSMax Kazantsev "Block is marked as having special instructions but in fact it has "
996afebe1dSMax Kazantsev "none!");
1008a9e059eSMax Kazantsev }
1018a9e059eSMax Kazantsev
validateAll() const1028a9e059eSMax Kazantsev void InstructionPrecedenceTracking::validateAll() const {
1038a9e059eSMax Kazantsev // Check that for every known block the cached value is correct.
104*601b3a13SKazu Hirata for (const auto &It : FirstSpecialInsts)
1056afebe1dSMax Kazantsev validate(It.first);
1068a9e059eSMax Kazantsev }
1078a9e059eSMax Kazantsev #endif
1088a9e059eSMax Kazantsev
insertInstructionTo(const Instruction * Inst,const BasicBlock * BB)1094615a505SMax Kazantsev void InstructionPrecedenceTracking::insertInstructionTo(const Instruction *Inst,
1104615a505SMax Kazantsev const BasicBlock *BB) {
1114615a505SMax Kazantsev if (isSpecialInstruction(Inst))
112d3487bdbSMax Kazantsev FirstSpecialInsts.erase(BB);
1134615a505SMax Kazantsev }
1144615a505SMax Kazantsev
removeInstruction(const Instruction * Inst)1154615a505SMax Kazantsev void InstructionPrecedenceTracking::removeInstruction(const Instruction *Inst) {
116b4498e6bSPhilip Reames auto *BB = Inst->getParent();
117b4498e6bSPhilip Reames assert(BB && "must be called before instruction is actually removed");
1183781a46cSArthur Eubanks if (FirstSpecialInsts.count(BB) && FirstSpecialInsts[BB] == Inst)
1193781a46cSArthur Eubanks FirstSpecialInsts.erase(BB);
120d3a4cbe1SMax Kazantsev }
121d3a4cbe1SMax Kazantsev
removeUsersOf(const Instruction * Inst)122c5d1ccbcSArthur Eubanks void InstructionPrecedenceTracking::removeUsersOf(const Instruction *Inst) {
123c5d1ccbcSArthur Eubanks for (const auto *U : Inst->users()) {
124c5d1ccbcSArthur Eubanks if (const auto *UI = dyn_cast<Instruction>(U))
125c5d1ccbcSArthur Eubanks removeInstruction(UI);
126c5d1ccbcSArthur Eubanks }
127c5d1ccbcSArthur Eubanks }
128c5d1ccbcSArthur Eubanks
clear()129d3a4cbe1SMax Kazantsev void InstructionPrecedenceTracking::clear() {
130d3487bdbSMax Kazantsev FirstSpecialInsts.clear();
1318a9e059eSMax Kazantsev #ifndef NDEBUG
1328a9e059eSMax Kazantsev // The map should be valid after clearing (at least empty).
1338a9e059eSMax Kazantsev validateAll();
1348a9e059eSMax Kazantsev #endif
135d3a4cbe1SMax Kazantsev }
136d3a4cbe1SMax Kazantsev
isSpecialInstruction(const Instruction * Insn) const137d3a4cbe1SMax Kazantsev bool ImplicitControlFlowTracking::isSpecialInstruction(
138d3a4cbe1SMax Kazantsev const Instruction *Insn) const {
139d3a4cbe1SMax Kazantsev // If a block's instruction doesn't always pass the control to its successor
140d3a4cbe1SMax Kazantsev // instruction, mark the block as having implicit control flow. We use them
141d3a4cbe1SMax Kazantsev // to avoid wrong assumptions of sort "if A is executed and B post-dominates
142d3a4cbe1SMax Kazantsev // A, then B is also executed". This is not true is there is an implicit
143d3a4cbe1SMax Kazantsev // control flow instruction (e.g. a guard) between them.
1444e0d9925SMax Kazantsev return !isGuaranteedToTransferExecutionToSuccessor(Insn);
145d3a4cbe1SMax Kazantsev }
1467d49a3a8SMax Kazantsev
isSpecialInstruction(const Instruction * Insn) const1477d49a3a8SMax Kazantsev bool MemoryWriteTracking::isSpecialInstruction(
1487d49a3a8SMax Kazantsev const Instruction *Insn) const {
14924383cd7SMax Kazantsev using namespace PatternMatch;
15024383cd7SMax Kazantsev if (match(Insn, m_Intrinsic<Intrinsic::experimental_widenable_condition>()))
15124383cd7SMax Kazantsev return false;
1527d49a3a8SMax Kazantsev return Insn->mayWriteToMemory();
1537d49a3a8SMax Kazantsev }
154