forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			161 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- InstructionPrecedenceTracking.cpp -----------------------*- C++ -*-===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// Implements a class that is able to define some instructions as "special"
 | 
						|
// (e.g. as having implicit control flow, or writing memory, or having another
 | 
						|
// interesting property) and then efficiently answers queries of the types:
 | 
						|
// 1. Are there any special instructions in the block of interest?
 | 
						|
// 2. Return first of the special instructions in the given block;
 | 
						|
// 3. Check if the given instruction is preceeded by the first special
 | 
						|
//    instruction in the same block.
 | 
						|
// The class provides caching that allows to answer these queries quickly. The
 | 
						|
// user must make sure that the cached data is invalidated properly whenever
 | 
						|
// a content of some tracked block is changed.
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/Analysis/InstructionPrecedenceTracking.h"
 | 
						|
#include "llvm/Analysis/ValueTracking.h"
 | 
						|
#include "llvm/IR/PatternMatch.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
static cl::opt<bool> ExpensiveAsserts(
 | 
						|
    "ipt-expensive-asserts",
 | 
						|
    cl::desc("Perform expensive assert validation on every query to Instruction"
 | 
						|
             " Precedence Tracking"),
 | 
						|
    cl::init(false), cl::Hidden);
 | 
						|
#endif
 | 
						|
 | 
						|
const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction(
 | 
						|
    const BasicBlock *BB) {
 | 
						|
#ifndef NDEBUG
 | 
						|
  // If there is a bug connected to invalid cache, turn on ExpensiveAsserts to
 | 
						|
  // catch this situation as early as possible.
 | 
						|
  if (ExpensiveAsserts)
 | 
						|
    validateAll();
 | 
						|
  else
 | 
						|
    validate(BB);
 | 
						|
#endif
 | 
						|
 | 
						|
  if (FirstSpecialInsts.find(BB) == FirstSpecialInsts.end()) {
 | 
						|
    fill(BB);
 | 
						|
    assert(FirstSpecialInsts.find(BB) != FirstSpecialInsts.end() && "Must be!");
 | 
						|
  }
 | 
						|
  return FirstSpecialInsts[BB];
 | 
						|
}
 | 
						|
 | 
						|
bool InstructionPrecedenceTracking::hasSpecialInstructions(
 | 
						|
    const BasicBlock *BB) {
 | 
						|
  return getFirstSpecialInstruction(BB) != nullptr;
 | 
						|
}
 | 
						|
 | 
						|
bool InstructionPrecedenceTracking::isPreceededBySpecialInstruction(
 | 
						|
    const Instruction *Insn) {
 | 
						|
  const Instruction *MaybeFirstSpecial =
 | 
						|
      getFirstSpecialInstruction(Insn->getParent());
 | 
						|
  return MaybeFirstSpecial && OI.dominates(MaybeFirstSpecial, Insn);
 | 
						|
}
 | 
						|
 | 
						|
void InstructionPrecedenceTracking::fill(const BasicBlock *BB) {
 | 
						|
  FirstSpecialInsts.erase(BB);
 | 
						|
  for (auto &I : *BB)
 | 
						|
    if (isSpecialInstruction(&I)) {
 | 
						|
      FirstSpecialInsts[BB] = &I;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  // Mark this block as having no special instructions.
 | 
						|
  FirstSpecialInsts[BB] = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
void InstructionPrecedenceTracking::validate(const BasicBlock *BB) const {
 | 
						|
  auto It = FirstSpecialInsts.find(BB);
 | 
						|
  // Bail if we don't have anything cached for this block.
 | 
						|
  if (It == FirstSpecialInsts.end())
 | 
						|
    return;
 | 
						|
 | 
						|
  for (const Instruction &Insn : *BB)
 | 
						|
    if (isSpecialInstruction(&Insn)) {
 | 
						|
      assert(It->second == &Insn &&
 | 
						|
             "Cached first special instruction is wrong!");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  assert(It->second == nullptr &&
 | 
						|
         "Block is marked as having special instructions but in fact it  has "
 | 
						|
         "none!");
 | 
						|
}
 | 
						|
 | 
						|
void InstructionPrecedenceTracking::validateAll() const {
 | 
						|
  // Check that for every known block the cached value is correct.
 | 
						|
  for (auto &It : FirstSpecialInsts)
 | 
						|
    validate(It.first);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void InstructionPrecedenceTracking::insertInstructionTo(const Instruction *Inst,
 | 
						|
                                                        const BasicBlock *BB) {
 | 
						|
  if (isSpecialInstruction(Inst))
 | 
						|
    FirstSpecialInsts.erase(BB);
 | 
						|
  OI.invalidateBlock(BB);
 | 
						|
}
 | 
						|
 | 
						|
void InstructionPrecedenceTracking::removeInstruction(const Instruction *Inst) {
 | 
						|
  if (isSpecialInstruction(Inst))
 | 
						|
    FirstSpecialInsts.erase(Inst->getParent());
 | 
						|
  OI.invalidateBlock(Inst->getParent());
 | 
						|
}
 | 
						|
 | 
						|
void InstructionPrecedenceTracking::clear() {
 | 
						|
  for (auto It : FirstSpecialInsts)
 | 
						|
    OI.invalidateBlock(It.first);
 | 
						|
  FirstSpecialInsts.clear();
 | 
						|
#ifndef NDEBUG
 | 
						|
  // The map should be valid after clearing (at least empty).
 | 
						|
  validateAll();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool ImplicitControlFlowTracking::isSpecialInstruction(
 | 
						|
    const Instruction *Insn) const {
 | 
						|
  // If a block's instruction doesn't always pass the control to its successor
 | 
						|
  // instruction, mark the block as having implicit control flow. We use them
 | 
						|
  // to avoid wrong assumptions of sort "if A is executed and B post-dominates
 | 
						|
  // A, then B is also executed". This is not true is there is an implicit
 | 
						|
  // control flow instruction (e.g. a guard) between them.
 | 
						|
  //
 | 
						|
  // TODO: Currently, isGuaranteedToTransferExecutionToSuccessor returns false
 | 
						|
  // for volatile stores and loads because they can trap. The discussion on
 | 
						|
  // whether or not it is correct is still ongoing. We might want to get rid
 | 
						|
  // of this logic in the future. Anyways, trapping instructions shouldn't
 | 
						|
  // introduce implicit control flow, so we explicitly allow them here. This
 | 
						|
  // must be removed once isGuaranteedToTransferExecutionToSuccessor is fixed.
 | 
						|
  if (isGuaranteedToTransferExecutionToSuccessor(Insn))
 | 
						|
    return false;
 | 
						|
  if (isa<LoadInst>(Insn)) {
 | 
						|
    assert(cast<LoadInst>(Insn)->isVolatile() &&
 | 
						|
           "Non-volatile load should transfer execution to successor!");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if (isa<StoreInst>(Insn)) {
 | 
						|
    assert(cast<StoreInst>(Insn)->isVolatile() &&
 | 
						|
           "Non-volatile store should transfer execution to successor!");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool MemoryWriteTracking::isSpecialInstruction(
 | 
						|
    const Instruction *Insn) const {
 | 
						|
  using namespace PatternMatch;
 | 
						|
  if (match(Insn, m_Intrinsic<Intrinsic::experimental_widenable_condition>()))
 | 
						|
    return false;
 | 
						|
  return Insn->mayWriteToMemory();
 | 
						|
}
 |