10b57cec5SDimitry Andric //===-- InstructionPrecedenceTracking.cpp -----------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // Implements a class that is able to define some instructions as "special" 90b57cec5SDimitry Andric // (e.g. as having implicit control flow, or writing memory, or having another 100b57cec5SDimitry Andric // interesting property) and then efficiently answers queries of the types: 110b57cec5SDimitry Andric // 1. Are there any special instructions in the block of interest? 120b57cec5SDimitry Andric // 2. Return first of the special instructions in the given block; 130b57cec5SDimitry Andric // 3. Check if the given instruction is preceeded by the first special 140b57cec5SDimitry Andric // instruction in the same block. 150b57cec5SDimitry Andric // The class provides caching that allows to answer these queries quickly. The 160b57cec5SDimitry Andric // user must make sure that the cached data is invalidated properly whenever 170b57cec5SDimitry Andric // a content of some tracked block is changed. 180b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "llvm/Analysis/InstructionPrecedenceTracking.h" 210b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 22*349cc55cSDimitry Andric #include "llvm/ADT/Statistic.h" 230b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h" 24480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 28*349cc55cSDimitry Andric #define DEBUG_TYPE "ipt" 29*349cc55cSDimitry Andric STATISTIC(NumInstScanned, "Number of insts scanned while updating ibt"); 30*349cc55cSDimitry Andric 310b57cec5SDimitry Andric #ifndef NDEBUG 320b57cec5SDimitry Andric static cl::opt<bool> ExpensiveAsserts( 330b57cec5SDimitry Andric "ipt-expensive-asserts", 340b57cec5SDimitry Andric cl::desc("Perform expensive assert validation on every query to Instruction" 350b57cec5SDimitry Andric " Precedence Tracking"), 360b57cec5SDimitry Andric cl::init(false), cl::Hidden); 370b57cec5SDimitry Andric #endif 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction( 400b57cec5SDimitry Andric const BasicBlock *BB) { 410b57cec5SDimitry Andric #ifndef NDEBUG 420b57cec5SDimitry Andric // If there is a bug connected to invalid cache, turn on ExpensiveAsserts to 430b57cec5SDimitry Andric // catch this situation as early as possible. 440b57cec5SDimitry Andric if (ExpensiveAsserts) 450b57cec5SDimitry Andric validateAll(); 460b57cec5SDimitry Andric else 470b57cec5SDimitry Andric validate(BB); 480b57cec5SDimitry Andric #endif 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric if (FirstSpecialInsts.find(BB) == FirstSpecialInsts.end()) { 510b57cec5SDimitry Andric fill(BB); 520b57cec5SDimitry Andric assert(FirstSpecialInsts.find(BB) != FirstSpecialInsts.end() && "Must be!"); 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric return FirstSpecialInsts[BB]; 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric bool InstructionPrecedenceTracking::hasSpecialInstructions( 580b57cec5SDimitry Andric const BasicBlock *BB) { 590b57cec5SDimitry Andric return getFirstSpecialInstruction(BB) != nullptr; 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric bool InstructionPrecedenceTracking::isPreceededBySpecialInstruction( 630b57cec5SDimitry Andric const Instruction *Insn) { 640b57cec5SDimitry Andric const Instruction *MaybeFirstSpecial = 650b57cec5SDimitry Andric getFirstSpecialInstruction(Insn->getParent()); 665ffd83dbSDimitry Andric return MaybeFirstSpecial && MaybeFirstSpecial->comesBefore(Insn); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric void InstructionPrecedenceTracking::fill(const BasicBlock *BB) { 700b57cec5SDimitry Andric FirstSpecialInsts.erase(BB); 71*349cc55cSDimitry Andric for (auto &I : *BB) { 72*349cc55cSDimitry Andric NumInstScanned++; 730b57cec5SDimitry Andric if (isSpecialInstruction(&I)) { 740b57cec5SDimitry Andric FirstSpecialInsts[BB] = &I; 750b57cec5SDimitry Andric return; 760b57cec5SDimitry Andric } 77*349cc55cSDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric // Mark this block as having no special instructions. 800b57cec5SDimitry Andric FirstSpecialInsts[BB] = nullptr; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric #ifndef NDEBUG 840b57cec5SDimitry Andric void InstructionPrecedenceTracking::validate(const BasicBlock *BB) const { 850b57cec5SDimitry Andric auto It = FirstSpecialInsts.find(BB); 860b57cec5SDimitry Andric // Bail if we don't have anything cached for this block. 870b57cec5SDimitry Andric if (It == FirstSpecialInsts.end()) 880b57cec5SDimitry Andric return; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric for (const Instruction &Insn : *BB) 910b57cec5SDimitry Andric if (isSpecialInstruction(&Insn)) { 920b57cec5SDimitry Andric assert(It->second == &Insn && 930b57cec5SDimitry Andric "Cached first special instruction is wrong!"); 940b57cec5SDimitry Andric return; 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric assert(It->second == nullptr && 980b57cec5SDimitry Andric "Block is marked as having special instructions but in fact it has " 990b57cec5SDimitry Andric "none!"); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric void InstructionPrecedenceTracking::validateAll() const { 1030b57cec5SDimitry Andric // Check that for every known block the cached value is correct. 1040b57cec5SDimitry Andric for (auto &It : FirstSpecialInsts) 1050b57cec5SDimitry Andric validate(It.first); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric #endif 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric void InstructionPrecedenceTracking::insertInstructionTo(const Instruction *Inst, 1100b57cec5SDimitry Andric const BasicBlock *BB) { 1110b57cec5SDimitry Andric if (isSpecialInstruction(Inst)) 1120b57cec5SDimitry Andric FirstSpecialInsts.erase(BB); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric void InstructionPrecedenceTracking::removeInstruction(const Instruction *Inst) { 116*349cc55cSDimitry Andric auto *BB = Inst->getParent(); 117*349cc55cSDimitry Andric assert(BB && "must be called before instruction is actually removed"); 118*349cc55cSDimitry Andric if (FirstSpecialInsts.count(BB) && FirstSpecialInsts[BB] == Inst) 119*349cc55cSDimitry Andric FirstSpecialInsts.erase(BB); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 122fe6060f1SDimitry Andric void InstructionPrecedenceTracking::removeUsersOf(const Instruction *Inst) { 123fe6060f1SDimitry Andric for (const auto *U : Inst->users()) { 124fe6060f1SDimitry Andric if (const auto *UI = dyn_cast<Instruction>(U)) 125fe6060f1SDimitry Andric removeInstruction(UI); 126fe6060f1SDimitry Andric } 127fe6060f1SDimitry Andric } 128fe6060f1SDimitry Andric 1290b57cec5SDimitry Andric void InstructionPrecedenceTracking::clear() { 1300b57cec5SDimitry Andric FirstSpecialInsts.clear(); 1310b57cec5SDimitry Andric #ifndef NDEBUG 1320b57cec5SDimitry Andric // The map should be valid after clearing (at least empty). 1330b57cec5SDimitry Andric validateAll(); 1340b57cec5SDimitry Andric #endif 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric bool ImplicitControlFlowTracking::isSpecialInstruction( 1380b57cec5SDimitry Andric const Instruction *Insn) const { 1390b57cec5SDimitry Andric // If a block's instruction doesn't always pass the control to its successor 1400b57cec5SDimitry Andric // instruction, mark the block as having implicit control flow. We use them 1410b57cec5SDimitry Andric // to avoid wrong assumptions of sort "if A is executed and B post-dominates 1420b57cec5SDimitry Andric // A, then B is also executed". This is not true is there is an implicit 1430b57cec5SDimitry Andric // control flow instruction (e.g. a guard) between them. 1445ffd83dbSDimitry Andric return !isGuaranteedToTransferExecutionToSuccessor(Insn); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric bool MemoryWriteTracking::isSpecialInstruction( 1480b57cec5SDimitry Andric const Instruction *Insn) const { 1490b57cec5SDimitry Andric using namespace PatternMatch; 1500b57cec5SDimitry Andric if (match(Insn, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) 1510b57cec5SDimitry Andric return false; 1520b57cec5SDimitry Andric return Insn->mayWriteToMemory(); 1530b57cec5SDimitry Andric } 154