Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp
35234 views
//===-- InstructionPrecedenceTracking.cpp -----------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7// Implements a class that is able to define some instructions as "special"8// (e.g. as having implicit control flow, or writing memory, or having another9// interesting property) and then efficiently answers queries of the types:10// 1. Are there any special instructions in the block of interest?11// 2. Return first of the special instructions in the given block;12// 3. Check if the given instruction is preceeded by the first special13// instruction in the same block.14// The class provides caching that allows to answer these queries quickly. The15// user must make sure that the cached data is invalidated properly whenever16// a content of some tracked block is changed.17//===----------------------------------------------------------------------===//1819#include "llvm/Analysis/InstructionPrecedenceTracking.h"20#include "llvm/Analysis/ValueTracking.h"21#include "llvm/ADT/Statistic.h"22#include "llvm/IR/PatternMatch.h"23#include "llvm/Support/CommandLine.h"2425using namespace llvm;2627#define DEBUG_TYPE "ipt"28STATISTIC(NumInstScanned, "Number of insts scanned while updating ibt");2930#ifndef NDEBUG31static cl::opt<bool> ExpensiveAsserts(32"ipt-expensive-asserts",33cl::desc("Perform expensive assert validation on every query to Instruction"34" Precedence Tracking"),35cl::init(false), cl::Hidden);36#endif3738const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction(39const BasicBlock *BB) {40#ifndef NDEBUG41// If there is a bug connected to invalid cache, turn on ExpensiveAsserts to42// catch this situation as early as possible.43if (ExpensiveAsserts)44validateAll();45else46validate(BB);47#endif4849if (!FirstSpecialInsts.contains(BB)) {50fill(BB);51assert(FirstSpecialInsts.contains(BB) && "Must be!");52}53return FirstSpecialInsts[BB];54}5556bool InstructionPrecedenceTracking::hasSpecialInstructions(57const BasicBlock *BB) {58return getFirstSpecialInstruction(BB) != nullptr;59}6061bool InstructionPrecedenceTracking::isPreceededBySpecialInstruction(62const Instruction *Insn) {63const Instruction *MaybeFirstSpecial =64getFirstSpecialInstruction(Insn->getParent());65return MaybeFirstSpecial && MaybeFirstSpecial->comesBefore(Insn);66}6768void InstructionPrecedenceTracking::fill(const BasicBlock *BB) {69FirstSpecialInsts.erase(BB);70for (const auto &I : *BB) {71NumInstScanned++;72if (isSpecialInstruction(&I)) {73FirstSpecialInsts[BB] = &I;74return;75}76}7778// Mark this block as having no special instructions.79FirstSpecialInsts[BB] = nullptr;80}8182#ifndef NDEBUG83void InstructionPrecedenceTracking::validate(const BasicBlock *BB) const {84auto It = FirstSpecialInsts.find(BB);85// Bail if we don't have anything cached for this block.86if (It == FirstSpecialInsts.end())87return;8889for (const Instruction &Insn : *BB)90if (isSpecialInstruction(&Insn)) {91assert(It->second == &Insn &&92"Cached first special instruction is wrong!");93return;94}9596assert(It->second == nullptr &&97"Block is marked as having special instructions but in fact it has "98"none!");99}100101void InstructionPrecedenceTracking::validateAll() const {102// Check that for every known block the cached value is correct.103for (const auto &It : FirstSpecialInsts)104validate(It.first);105}106#endif107108void InstructionPrecedenceTracking::insertInstructionTo(const Instruction *Inst,109const BasicBlock *BB) {110if (isSpecialInstruction(Inst))111FirstSpecialInsts.erase(BB);112}113114void InstructionPrecedenceTracking::removeInstruction(const Instruction *Inst) {115auto *BB = Inst->getParent();116assert(BB && "must be called before instruction is actually removed");117if (FirstSpecialInsts.count(BB) && FirstSpecialInsts[BB] == Inst)118FirstSpecialInsts.erase(BB);119}120121void InstructionPrecedenceTracking::removeUsersOf(const Instruction *Inst) {122for (const auto *U : Inst->users()) {123if (const auto *UI = dyn_cast<Instruction>(U))124removeInstruction(UI);125}126}127128void InstructionPrecedenceTracking::clear() {129FirstSpecialInsts.clear();130#ifndef NDEBUG131// The map should be valid after clearing (at least empty).132validateAll();133#endif134}135136bool ImplicitControlFlowTracking::isSpecialInstruction(137const Instruction *Insn) const {138// If a block's instruction doesn't always pass the control to its successor139// instruction, mark the block as having implicit control flow. We use them140// to avoid wrong assumptions of sort "if A is executed and B post-dominates141// A, then B is also executed". This is not true is there is an implicit142// control flow instruction (e.g. a guard) between them.143return !isGuaranteedToTransferExecutionToSuccessor(Insn);144}145146bool MemoryWriteTracking::isSpecialInstruction(147const Instruction *Insn) const {148using namespace PatternMatch;149if (match(Insn, m_Intrinsic<Intrinsic::experimental_widenable_condition>()))150return false;151return Insn->mayWriteToMemory();152}153154155