blob: 48f2a4020c666a5351191f9145f5ed99772c43ac [file] [log] [blame]
//===- OrderedBasicBlock.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
//
//===----------------------------------------------------------------------===//
//
// This file implements the OrderedBasicBlock class. OrderedBasicBlock
// maintains an interface where clients can query if one instruction comes
// before another in a BasicBlock. Since BasicBlock currently lacks a reliable
// way to query relative position between instructions one can use
// OrderedBasicBlock to do such queries. OrderedBasicBlock is lazily built on a
// source BasicBlock and maintains an internal Instruction -> Position map. A
// OrderedBasicBlock instance should be discarded whenever the source
// BasicBlock changes.
//
// It's currently used by the CaptureTracker in order to find relative
// positions of a pair of instructions inside a BasicBlock.
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/OrderedBasicBlock.h"
#include "llvm/IR/Instruction.h"
using namespace llvm;
OrderedBasicBlock::OrderedBasicBlock(const BasicBlock *BasicB)
: NextInstPos(0), BB(BasicB) {
LastInstFound = BB->end();
}
/// Given no cached results, find if \p A comes before \p B in \p BB.
/// Cache and number out instruction while walking \p BB.
bool OrderedBasicBlock::comesBefore(const Instruction *A,
const Instruction *B) {
const Instruction *Inst = nullptr;
assert(!(LastInstFound == BB->end() && NextInstPos != 0) &&
"Instruction supposed to be in NumberedInsts");
assert(A->getParent() == BB && "Instruction supposed to be in the block!");
assert(B->getParent() == BB && "Instruction supposed to be in the block!");
// Start the search with the instruction found in the last lookup round.
auto II = BB->begin();
auto IE = BB->end();
if (LastInstFound != IE)
II = std::next(LastInstFound);
// Number all instructions up to the point where we find 'A' or 'B'.
for (; II != IE; ++II) {
Inst = cast<Instruction>(II);
NumberedInsts[Inst] = NextInstPos++;
if (Inst == A || Inst == B)
break;
}
assert(II != IE && "Instruction not found?");
assert((Inst == A || Inst == B) && "Should find A or B");
LastInstFound = II;
return Inst != B;
}
/// Find out whether \p A dominates \p B, meaning whether \p A
/// comes before \p B in \p BB. This is a simplification that considers
/// cached instruction positions and ignores other basic blocks, being
/// only relevant to compare relative instructions positions inside \p BB.
bool OrderedBasicBlock::dominates(const Instruction *A, const Instruction *B) {
assert(A->getParent() == B->getParent() &&
"Instructions must be in the same basic block!");
assert(A->getParent() == BB && "Instructions must be in the tracked block!");
// First we lookup the instructions. If they don't exist, lookup will give us
// back ::end(). If they both exist, we compare the numbers. Otherwise, if NA
// exists and NB doesn't, it means NA must come before NB because we would
// have numbered NB as well if it didn't. The same is true for NB. If it
// exists, but NA does not, NA must come after it. If neither exist, we need
// to number the block and cache the results (by calling comesBefore).
auto NAI = NumberedInsts.find(A);
auto NBI = NumberedInsts.find(B);
if (NAI != NumberedInsts.end() && NBI != NumberedInsts.end())
return NAI->second < NBI->second;
if (NAI != NumberedInsts.end())
return true;
if (NBI != NumberedInsts.end())
return false;
return comesBefore(A, B);
}
void OrderedBasicBlock::eraseInstruction(const Instruction *I) {
if (LastInstFound != BB->end() && I == &*LastInstFound) {
if (LastInstFound == BB->begin()) {
LastInstFound = BB->end();
NextInstPos = 0;
} else
LastInstFound--;
}
NumberedInsts.erase(I);
}
void OrderedBasicBlock::replaceInstruction(const Instruction *Old,
const Instruction *New) {
auto OI = NumberedInsts.find(Old);
if (OI == NumberedInsts.end())
return;
NumberedInsts.insert({New, OI->second});
if (LastInstFound != BB->end() && Old == &*LastInstFound)
LastInstFound = New->getIterator();
NumberedInsts.erase(Old);
}