Skip to content

Commit

Permalink
[IR] Lazily number instructions for local dominance queries
Browse files Browse the repository at this point in the history
Essentially, fold OrderedBasicBlock into BasicBlock, and make it
auto-invalidate the instruction ordering when new instructions are
added. Notably, we don't need to invalidate it when removing
instructions, which is helpful when a pass mostly delete dead
instructions rather than transforming them.

The downside is that Instruction grows from 56 bytes to 64 bytes.  The
resulting LLVM code is substantially simpler and automatically handles
invalidation, which makes me think that this is the right speed and size
tradeoff.

The important change is in SymbolTableTraitsImpl.h, where the numbering
is invalidated. Everything else should be straightforward.

We probably want to implement a fancier re-numbering scheme so that
local updates don't invalidate the ordering, but I plan for that to be
future work, maybe for someone else.

Reviewed By: lattner, vsk, fhahn, dexonsmith

Differential Revision: https://reviews.llvm.org/D51664
  • Loading branch information
rnk authored and epilk committed Apr 8, 2020
1 parent d02ff1a commit 7d0b07c
Show file tree
Hide file tree
Showing 26 changed files with 315 additions and 391 deletions.
12 changes: 4 additions & 8 deletions llvm/include/llvm/Analysis/AliasAnalysis.h
Expand Up @@ -59,7 +59,6 @@ class AnalysisUsage;
class BasicAAResult;
class BasicBlock;
class DominatorTree;
class OrderedBasicBlock;
class Value;

/// The possible results of an alias query.
Expand Down Expand Up @@ -643,19 +642,16 @@ class AAResults {

/// Return information about whether a particular call site modifies
/// or reads the specified memory location \p MemLoc before instruction \p I
/// in a BasicBlock. An ordered basic block \p OBB can be used to speed up
/// instruction ordering queries inside the BasicBlock containing \p I.
/// in a BasicBlock.
/// Early exits in callCapturesBefore may lead to ModRefInfo::Must not being
/// set.
ModRefInfo callCapturesBefore(const Instruction *I,
const MemoryLocation &MemLoc, DominatorTree *DT,
OrderedBasicBlock *OBB = nullptr);
const MemoryLocation &MemLoc, DominatorTree *DT);

/// A convenience wrapper to synthesize a memory location.
ModRefInfo callCapturesBefore(const Instruction *I, const Value *P,
LocationSize Size, DominatorTree *DT,
OrderedBasicBlock *OBB = nullptr) {
return callCapturesBefore(I, MemoryLocation(P, Size), DT, OBB);
LocationSize Size, DominatorTree *DT) {
return callCapturesBefore(I, MemoryLocation(P, Size), DT);
}

/// @}
Expand Down
5 changes: 1 addition & 4 deletions llvm/include/llvm/Analysis/CaptureTracking.h
Expand Up @@ -20,7 +20,6 @@ namespace llvm {
class DataLayout;
class Instruction;
class DominatorTree;
class OrderedBasicBlock;

/// The default value for MaxUsesToExplore argument. It's relatively small to
/// keep the cost of analysis reasonable for clients like BasicAliasAnalysis,
Expand Down Expand Up @@ -53,14 +52,12 @@ namespace llvm {
/// it or not. The boolean StoreCaptures specified whether storing the value
/// (or part of it) into memory anywhere automatically counts as capturing it
/// or not. Captures by the provided instruction are considered if the
/// final parameter is true. An ordered basic block in \p OBB could be used
/// to speed up capture-tracker queries.
/// final parameter is true.
/// MaxUsesToExplore specifies how many uses should the analysis explore for
/// one value before giving up due too "too many uses".
bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures,
bool StoreCaptures, const Instruction *I,
const DominatorTree *DT, bool IncludeI = false,
OrderedBasicBlock *OBB = nullptr,
unsigned MaxUsesToExplore = DefaultMaxUsesToExplore);

/// This callback is used in conjunction with PointerMayBeCaptured. In
Expand Down
9 changes: 3 additions & 6 deletions llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h
Expand Up @@ -384,8 +384,7 @@ class MemoryDependenceResults {
///
/// See the class comment for more details. It is illegal to call this on
/// non-memory instructions.
MemDepResult getDependency(Instruction *QueryInst,
OrderedBasicBlock *OBB = nullptr);
MemDepResult getDependency(Instruction *QueryInst);

/// Perform a full dependency query for the specified call, returning the set
/// of blocks that the value is potentially live across.
Expand Down Expand Up @@ -451,14 +450,12 @@ class MemoryDependenceResults {
BasicBlock::iterator ScanIt,
BasicBlock *BB,
Instruction *QueryInst = nullptr,
unsigned *Limit = nullptr,
OrderedBasicBlock *OBB = nullptr);
unsigned *Limit = nullptr);

MemDepResult
getSimplePointerDependencyFrom(const MemoryLocation &MemLoc, bool isLoad,
BasicBlock::iterator ScanIt, BasicBlock *BB,
Instruction *QueryInst, unsigned *Limit,
OrderedBasicBlock *OBB);
Instruction *QueryInst, unsigned *Limit);

/// This analysis looks for other loads and stores with invariant.group
/// metadata and the same pointer operand. Returns Unknown if it does not
Expand Down
74 changes: 0 additions & 74 deletions llvm/include/llvm/Analysis/OrderedBasicBlock.h

This file was deleted.

18 changes: 3 additions & 15 deletions llvm/include/llvm/Analysis/OrderedInstructions.h
Expand Up @@ -9,28 +9,22 @@
// This file defines an efficient way to check for dominance relation between 2
// instructions.
//
// This interface dispatches to appropriate dominance check given 2
// instructions, i.e. in case the instructions are in the same basic block,
// OrderedBasicBlock (with instruction numbering and caching) are used.
// Otherwise, dominator tree is used.
// FIXME: This is really just a convenience wrapper to check dominance between
// two arbitrary instructions in different basic blocks. We should fold it into
// DominatorTree, which is the more widely used interface.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_ORDEREDINSTRUCTIONS_H
#define LLVM_ANALYSIS_ORDEREDINSTRUCTIONS_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/Analysis/OrderedBasicBlock.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Operator.h"

namespace llvm {

class OrderedInstructions {
/// Used to check dominance for instructions in same basic block.
mutable DenseMap<const BasicBlock *, std::unique_ptr<OrderedBasicBlock>>
OBBMap;

/// The dominator tree of the parent function.
DominatorTree *DT;

Expand All @@ -51,12 +45,6 @@ class OrderedInstructions {
/// or if the first instruction comes before the second in the same basic
/// block.
bool dfsBefore(const Instruction *, const Instruction *) const;

/// Invalidate the OrderedBasicBlock cache when its basic block changes.
/// i.e. If an instruction is deleted or added to the basic block, the user
/// should call this function to invalidate the OrderedBasicBlock cache for
/// this basic block.
void invalidateBlock(const BasicBlock *BB) { OBBMap.erase(BB); }
};

} // end namespace llvm
Expand Down
61 changes: 57 additions & 4 deletions llvm/include/llvm/IR/BasicBlock.h
Expand Up @@ -393,7 +393,9 @@ class BasicBlock final : public Value, // Basic blocks are data objects also

/// Returns true if there are any uses of this basic block other than
/// direct branches, switches, etc. to it.
bool hasAddressTaken() const { return getSubclassDataFromValue() != 0; }
bool hasAddressTaken() const {
return getBasicBlockBits().BlockAddressRefCount != 0;
}

/// Update all phi nodes in this basic block to refer to basic block \p New
/// instead of basic block \p Old.
Expand Down Expand Up @@ -428,16 +430,61 @@ class BasicBlock final : public Value, // Basic blocks are data objects also

Optional<uint64_t> getIrrLoopHeaderWeight() const;

/// Returns true if the Order field of child Instructions is valid.
bool isInstrOrderValid() const {
return getBasicBlockBits().InstrOrderValid;
}

/// Mark instruction ordering invalid. Done on every instruction insert.
void invalidateOrders() {
validateInstrOrdering();
BasicBlockBits Bits = getBasicBlockBits();
Bits.InstrOrderValid = false;
setBasicBlockBits(Bits);
}

/// Renumber instructions and mark the ordering as valid.
void renumberInstructions();

/// Returns false if the instruction ordering is incorrect in an debug build.
/// Always returns true when assertions are disabled. The method does not
/// assert internally so that we get better location info.
void validateInstrOrdering() const;

private:
/// Bitfield to help interpret the bits in Value::SubclassData.
struct BasicBlockBits {
unsigned short BlockAddressRefCount : 15;
unsigned short InstrOrderValid : 1;
};

/// Safely reinterpret the subclass data bits to a more useful form.
BasicBlockBits getBasicBlockBits() const {
static_assert(sizeof(BasicBlockBits) == sizeof(unsigned short),
"too many bits for Value::SubclassData");
unsigned short ValueData = getSubclassDataFromValue();
BasicBlockBits AsBits;
memcpy(&AsBits, &ValueData, sizeof(AsBits));
return AsBits;
}

/// Reinterpret our subclass bits and store them back into Value.
void setBasicBlockBits(BasicBlockBits AsBits) {
unsigned short D;
memcpy(&D, &AsBits, sizeof(D));
Value::setValueSubclassData(D);
}

/// Increment the internal refcount of the number of BlockAddresses
/// referencing this BasicBlock by \p Amt.
///
/// This is almost always 0, sometimes one possibly, but almost never 2, and
/// inconceivably 3 or more.
void AdjustBlockAddressRefCount(int Amt) {
setValueSubclassData(getSubclassDataFromValue()+Amt);
assert((int)(signed char)getSubclassDataFromValue() >= 0 &&
"Refcount wrap-around");
BasicBlockBits Bits = getBasicBlockBits();
Bits.BlockAddressRefCount += Amt;
setBasicBlockBits(Bits);
assert(Bits.BlockAddressRefCount < 255 && "Refcount wrap-around");
}

/// Shadow Value::setValueSubclassData with a private forwarding method so
Expand All @@ -454,6 +501,12 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(BasicBlock, LLVMBasicBlockRef)
/// This assumes that \p It is not at the end of a block.
BasicBlock::iterator skipDebugIntrinsics(BasicBlock::iterator It);

#ifdef NDEBUG
/// In release builds, this is a no-op. For !NDEBUG builds, the checks are
/// implemented in the .cpp file to avoid circular header deps.
inline void Instruction::validateInstrOrdering() const {}
#endif

} // end namespace llvm

#endif // LLVM_IR_BASICBLOCK_H
12 changes: 12 additions & 0 deletions llvm/include/llvm/IR/Instruction.h
Expand Up @@ -45,6 +45,10 @@ class Instruction : public User,
BasicBlock *Parent;
DebugLoc DbgLoc; // 'dbg' Metadata cache.

/// Relative order of this instruction in its parent basic block. Used for
/// O(1) local dominance checks between instructions.
mutable unsigned Order = 0;

enum {
/// This is a bit stored in the SubClassData field which indicates whether
/// this instruction has metadata attached to it or not.
Expand Down Expand Up @@ -117,6 +121,13 @@ class Instruction : public User,
/// the basic block that MovePos lives in, right after MovePos.
void moveAfter(Instruction *MovePos);

/// Given an instruction Other in the same basic block as this instruction,
/// return true if this instruction comes before Other. In this worst case,
/// this takes linear time in the number of instructions in the block. The
/// results are cached, so in common cases when the block remains unmodified,
/// it takes constant time.
bool comesBefore(const Instruction *Other) const;

//===--------------------------------------------------------------------===//
// Subclass classification.
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -738,6 +749,7 @@ class Instruction : public User,

private:
friend class SymbolTableListTraits<Instruction>;
friend class BasicBlock; // For renumbering.

// Shadow Value::setValueSubclassData with a private forwarding method so that
// subclasses cannot accidentally use it.
Expand Down
9 changes: 3 additions & 6 deletions llvm/lib/Analysis/AliasAnalysis.cpp
Expand Up @@ -631,16 +631,14 @@ ModRefInfo AAResults::getModRefInfo(const AtomicRMWInst *RMW,

/// Return information about whether a particular call site modifies
/// or reads the specified memory location \p MemLoc before instruction \p I
/// in a BasicBlock. An ordered basic block \p OBB can be used to speed up
/// instruction-ordering queries inside the BasicBlock containing \p I.
/// in a BasicBlock.
/// FIXME: this is really just shoring-up a deficiency in alias analysis.
/// BasicAA isn't willing to spend linear time determining whether an alloca
/// was captured before or after this particular call, while we are. However,
/// with a smarter AA in place, this test is just wasting compile time.
ModRefInfo AAResults::callCapturesBefore(const Instruction *I,
const MemoryLocation &MemLoc,
DominatorTree *DT,
OrderedBasicBlock *OBB) {
DominatorTree *DT) {
if (!DT)
return ModRefInfo::ModRef;

Expand All @@ -656,8 +654,7 @@ ModRefInfo AAResults::callCapturesBefore(const Instruction *I,

if (PointerMayBeCapturedBefore(Object, /* ReturnCaptures */ true,
/* StoreCaptures */ true, I, DT,
/* include Object */ true,
/* OrderedBasicBlock */ OBB))
/* include Object */ true))
return ModRefInfo::ModRef;

unsigned ArgNo = 0;
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Analysis/CMakeLists.txt
Expand Up @@ -70,7 +70,6 @@ add_llvm_component_library(LLVMAnalysis
ObjCARCAnalysisUtils.cpp
ObjCARCInstKind.cpp
OptimizationRemarkEmitter.cpp
OrderedBasicBlock.cpp
OrderedInstructions.cpp
PHITransAddr.cpp
PhiValues.cpp
Expand Down

0 comments on commit 7d0b07c

Please sign in to comment.