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" 220b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h" 23*480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #ifndef NDEBUG 280b57cec5SDimitry Andric static cl::opt<bool> ExpensiveAsserts( 290b57cec5SDimitry Andric "ipt-expensive-asserts", 300b57cec5SDimitry Andric cl::desc("Perform expensive assert validation on every query to Instruction" 310b57cec5SDimitry Andric " Precedence Tracking"), 320b57cec5SDimitry Andric cl::init(false), cl::Hidden); 330b57cec5SDimitry Andric #endif 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction( 360b57cec5SDimitry Andric const BasicBlock *BB) { 370b57cec5SDimitry Andric #ifndef NDEBUG 380b57cec5SDimitry Andric // If there is a bug connected to invalid cache, turn on ExpensiveAsserts to 390b57cec5SDimitry Andric // catch this situation as early as possible. 400b57cec5SDimitry Andric if (ExpensiveAsserts) 410b57cec5SDimitry Andric validateAll(); 420b57cec5SDimitry Andric else 430b57cec5SDimitry Andric validate(BB); 440b57cec5SDimitry Andric #endif 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric if (FirstSpecialInsts.find(BB) == FirstSpecialInsts.end()) { 470b57cec5SDimitry Andric fill(BB); 480b57cec5SDimitry Andric assert(FirstSpecialInsts.find(BB) != FirstSpecialInsts.end() && "Must be!"); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric return FirstSpecialInsts[BB]; 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric bool InstructionPrecedenceTracking::hasSpecialInstructions( 540b57cec5SDimitry Andric const BasicBlock *BB) { 550b57cec5SDimitry Andric return getFirstSpecialInstruction(BB) != nullptr; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric bool InstructionPrecedenceTracking::isPreceededBySpecialInstruction( 590b57cec5SDimitry Andric const Instruction *Insn) { 600b57cec5SDimitry Andric const Instruction *MaybeFirstSpecial = 610b57cec5SDimitry Andric getFirstSpecialInstruction(Insn->getParent()); 620b57cec5SDimitry Andric return MaybeFirstSpecial && OI.dominates(MaybeFirstSpecial, Insn); 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric void InstructionPrecedenceTracking::fill(const BasicBlock *BB) { 660b57cec5SDimitry Andric FirstSpecialInsts.erase(BB); 670b57cec5SDimitry Andric for (auto &I : *BB) 680b57cec5SDimitry Andric if (isSpecialInstruction(&I)) { 690b57cec5SDimitry Andric FirstSpecialInsts[BB] = &I; 700b57cec5SDimitry Andric return; 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric // Mark this block as having no special instructions. 740b57cec5SDimitry Andric FirstSpecialInsts[BB] = nullptr; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric #ifndef NDEBUG 780b57cec5SDimitry Andric void InstructionPrecedenceTracking::validate(const BasicBlock *BB) const { 790b57cec5SDimitry Andric auto It = FirstSpecialInsts.find(BB); 800b57cec5SDimitry Andric // Bail if we don't have anything cached for this block. 810b57cec5SDimitry Andric if (It == FirstSpecialInsts.end()) 820b57cec5SDimitry Andric return; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric for (const Instruction &Insn : *BB) 850b57cec5SDimitry Andric if (isSpecialInstruction(&Insn)) { 860b57cec5SDimitry Andric assert(It->second == &Insn && 870b57cec5SDimitry Andric "Cached first special instruction is wrong!"); 880b57cec5SDimitry Andric return; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric assert(It->second == nullptr && 920b57cec5SDimitry Andric "Block is marked as having special instructions but in fact it has " 930b57cec5SDimitry Andric "none!"); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric void InstructionPrecedenceTracking::validateAll() const { 970b57cec5SDimitry Andric // Check that for every known block the cached value is correct. 980b57cec5SDimitry Andric for (auto &It : FirstSpecialInsts) 990b57cec5SDimitry Andric validate(It.first); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric #endif 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric void InstructionPrecedenceTracking::insertInstructionTo(const Instruction *Inst, 1040b57cec5SDimitry Andric const BasicBlock *BB) { 1050b57cec5SDimitry Andric if (isSpecialInstruction(Inst)) 1060b57cec5SDimitry Andric FirstSpecialInsts.erase(BB); 1070b57cec5SDimitry Andric OI.invalidateBlock(BB); 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric void InstructionPrecedenceTracking::removeInstruction(const Instruction *Inst) { 1110b57cec5SDimitry Andric if (isSpecialInstruction(Inst)) 1120b57cec5SDimitry Andric FirstSpecialInsts.erase(Inst->getParent()); 1130b57cec5SDimitry Andric OI.invalidateBlock(Inst->getParent()); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric void InstructionPrecedenceTracking::clear() { 1170b57cec5SDimitry Andric for (auto It : FirstSpecialInsts) 1180b57cec5SDimitry Andric OI.invalidateBlock(It.first); 1190b57cec5SDimitry Andric FirstSpecialInsts.clear(); 1200b57cec5SDimitry Andric #ifndef NDEBUG 1210b57cec5SDimitry Andric // The map should be valid after clearing (at least empty). 1220b57cec5SDimitry Andric validateAll(); 1230b57cec5SDimitry Andric #endif 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric bool ImplicitControlFlowTracking::isSpecialInstruction( 1270b57cec5SDimitry Andric const Instruction *Insn) const { 1280b57cec5SDimitry Andric // If a block's instruction doesn't always pass the control to its successor 1290b57cec5SDimitry Andric // instruction, mark the block as having implicit control flow. We use them 1300b57cec5SDimitry Andric // to avoid wrong assumptions of sort "if A is executed and B post-dominates 1310b57cec5SDimitry Andric // A, then B is also executed". This is not true is there is an implicit 1320b57cec5SDimitry Andric // control flow instruction (e.g. a guard) between them. 1330b57cec5SDimitry Andric // 1340b57cec5SDimitry Andric // TODO: Currently, isGuaranteedToTransferExecutionToSuccessor returns false 1350b57cec5SDimitry Andric // for volatile stores and loads because they can trap. The discussion on 1360b57cec5SDimitry Andric // whether or not it is correct is still ongoing. We might want to get rid 1370b57cec5SDimitry Andric // of this logic in the future. Anyways, trapping instructions shouldn't 1380b57cec5SDimitry Andric // introduce implicit control flow, so we explicitly allow them here. This 1390b57cec5SDimitry Andric // must be removed once isGuaranteedToTransferExecutionToSuccessor is fixed. 1400b57cec5SDimitry Andric if (isGuaranteedToTransferExecutionToSuccessor(Insn)) 1410b57cec5SDimitry Andric return false; 1420b57cec5SDimitry Andric if (isa<LoadInst>(Insn)) { 1430b57cec5SDimitry Andric assert(cast<LoadInst>(Insn)->isVolatile() && 1440b57cec5SDimitry Andric "Non-volatile load should transfer execution to successor!"); 1450b57cec5SDimitry Andric return false; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric if (isa<StoreInst>(Insn)) { 1480b57cec5SDimitry Andric assert(cast<StoreInst>(Insn)->isVolatile() && 1490b57cec5SDimitry Andric "Non-volatile store should transfer execution to successor!"); 1500b57cec5SDimitry Andric return false; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric return true; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric bool MemoryWriteTracking::isSpecialInstruction( 1560b57cec5SDimitry Andric const Instruction *Insn) const { 1570b57cec5SDimitry Andric using namespace PatternMatch; 1580b57cec5SDimitry Andric if (match(Insn, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) 1590b57cec5SDimitry Andric return false; 1600b57cec5SDimitry Andric return Insn->mayWriteToMemory(); 1610b57cec5SDimitry Andric } 162