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