mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 22:26:05 +00:00

This patch simplifies instruction creation by replacing all overloads of instruction constructors/Create methods that are identical other than the Instruction *InsertBefore/BasicBlock *InsertAtEnd/BasicBlock::iterator InsertBefore argument with a single version that takes an InsertPosition argument. The InsertPosition class can be implicitly constructed from any of the above, internally converting them to the appropriate BasicBlock::iterator value which can then be used to insert the instruction (or to not insert it if an invalid iterator is passed). The upshot of this is that code will be deduplicated, and all callsites will switch to calling the new unified version without any changes needed to make the compiler happy. There is at least one exception to this; the construction of InsertPosition is a user-defined conversion, so any caller that was already relying on a different user-defined conversion won't work. In all of LLVM and Clang this happens exactly once: at clang/lib/CodeGen/CGExpr.cpp:123 we try to construct an alloca with an AssertingVH<Instruction> argument, which must now be cast to an Instruction* by using `&*`. If this is more common elsewhere, it could be fixed by adding an appropriate constructor to InsertPosition.
1311 lines
45 KiB
C++
1311 lines
45 KiB
C++
//===-- Instruction.cpp - Implement the Instruction class -----------------===//
|
|
//
|
|
// 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 Instruction class for the IR library.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/IR/Instruction.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/IR/AttributeMask.h"
|
|
#include "llvm/IR/Attributes.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/InstrTypes.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/Intrinsics.h"
|
|
#include "llvm/IR/MemoryModelRelaxationAnnotations.h"
|
|
#include "llvm/IR/Operator.h"
|
|
#include "llvm/IR/ProfDataUtils.h"
|
|
#include "llvm/IR/Type.h"
|
|
using namespace llvm;
|
|
|
|
InsertPosition::InsertPosition(Instruction *InsertBefore)
|
|
: InsertAt(InsertBefore ? InsertBefore->getIterator()
|
|
: InstListType::iterator()) {}
|
|
InsertPosition::InsertPosition(BasicBlock *InsertAtEnd)
|
|
: InsertAt(InsertAtEnd ? InsertAtEnd->end() : InstListType::iterator()) {}
|
|
|
|
Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps,
|
|
InsertPosition InsertBefore)
|
|
: User(ty, Value::InstructionVal + it, Ops, NumOps) {
|
|
// When called with an iterator, there must be a block to insert into.
|
|
if (InstListType::iterator InsertIt = InsertBefore; InsertIt.isValid()) {
|
|
BasicBlock *BB = InsertIt.getNodeParent();
|
|
assert(BB && "Instruction to insert before is not in a basic block!");
|
|
insertInto(BB, InsertBefore);
|
|
}
|
|
}
|
|
|
|
Instruction::~Instruction() {
|
|
assert(!getParent() && "Instruction still linked in the program!");
|
|
|
|
// Replace any extant metadata uses of this instruction with undef to
|
|
// preserve debug info accuracy. Some alternatives include:
|
|
// - Treat Instruction like any other Value, and point its extant metadata
|
|
// uses to an empty ValueAsMetadata node. This makes extant dbg.value uses
|
|
// trivially dead (i.e. fair game for deletion in many passes), leading to
|
|
// stale dbg.values being in effect for too long.
|
|
// - Call salvageDebugInfoOrMarkUndef. Not needed to make instruction removal
|
|
// correct. OTOH results in wasted work in some common cases (e.g. when all
|
|
// instructions in a BasicBlock are deleted).
|
|
if (isUsedByMetadata())
|
|
ValueAsMetadata::handleRAUW(this, UndefValue::get(getType()));
|
|
|
|
// Explicitly remove DIAssignID metadata to clear up ID -> Instruction(s)
|
|
// mapping in LLVMContext.
|
|
setMetadata(LLVMContext::MD_DIAssignID, nullptr);
|
|
}
|
|
|
|
const Module *Instruction::getModule() const {
|
|
return getParent()->getModule();
|
|
}
|
|
|
|
const Function *Instruction::getFunction() const {
|
|
return getParent()->getParent();
|
|
}
|
|
|
|
void Instruction::removeFromParent() {
|
|
// Perform any debug-info maintenence required.
|
|
handleMarkerRemoval();
|
|
|
|
getParent()->getInstList().remove(getIterator());
|
|
}
|
|
|
|
void Instruction::handleMarkerRemoval() {
|
|
if (!getParent()->IsNewDbgInfoFormat || !DebugMarker)
|
|
return;
|
|
|
|
DebugMarker->removeMarker();
|
|
}
|
|
|
|
BasicBlock::iterator Instruction::eraseFromParent() {
|
|
handleMarkerRemoval();
|
|
return getParent()->getInstList().erase(getIterator());
|
|
}
|
|
|
|
void Instruction::insertBefore(Instruction *InsertPos) {
|
|
insertBefore(InsertPos->getIterator());
|
|
}
|
|
|
|
/// Insert an unlinked instruction into a basic block immediately before the
|
|
/// specified instruction.
|
|
void Instruction::insertBefore(BasicBlock::iterator InsertPos) {
|
|
insertBefore(*InsertPos->getParent(), InsertPos);
|
|
}
|
|
|
|
/// Insert an unlinked instruction into a basic block immediately after the
|
|
/// specified instruction.
|
|
void Instruction::insertAfter(Instruction *InsertPos) {
|
|
BasicBlock *DestParent = InsertPos->getParent();
|
|
|
|
DestParent->getInstList().insertAfter(InsertPos->getIterator(), this);
|
|
}
|
|
|
|
BasicBlock::iterator Instruction::insertInto(BasicBlock *ParentBB,
|
|
BasicBlock::iterator It) {
|
|
assert(getParent() == nullptr && "Expected detached instruction");
|
|
assert((It == ParentBB->end() || It->getParent() == ParentBB) &&
|
|
"It not in ParentBB");
|
|
insertBefore(*ParentBB, It);
|
|
return getIterator();
|
|
}
|
|
|
|
extern cl::opt<bool> UseNewDbgInfoFormat;
|
|
|
|
void Instruction::insertBefore(BasicBlock &BB,
|
|
InstListType::iterator InsertPos) {
|
|
assert(!DebugMarker);
|
|
|
|
BB.getInstList().insert(InsertPos, this);
|
|
|
|
if (!BB.IsNewDbgInfoFormat)
|
|
return;
|
|
|
|
// We've inserted "this": if InsertAtHead is set then it comes before any
|
|
// DbgVariableRecords attached to InsertPos. But if it's not set, then any
|
|
// DbgRecords should now come before "this".
|
|
bool InsertAtHead = InsertPos.getHeadBit();
|
|
if (!InsertAtHead) {
|
|
DbgMarker *SrcMarker = BB.getMarker(InsertPos);
|
|
if (SrcMarker && !SrcMarker->empty()) {
|
|
// If this assertion fires, the calling code is about to insert a PHI
|
|
// after debug-records, which would form a sequence like:
|
|
// %0 = PHI
|
|
// #dbg_value
|
|
// %1 = PHI
|
|
// Which is de-normalised and undesired -- hence the assertion. To avoid
|
|
// this, you must insert at that position using an iterator, and it must
|
|
// be aquired by calling getFirstNonPHIIt / begin or similar methods on
|
|
// the block. This will signal to this behind-the-scenes debug-info
|
|
// maintenence code that you intend the PHI to be ahead of everything,
|
|
// including any debug-info.
|
|
assert(!isa<PHINode>(this) && "Inserting PHI after debug-records!");
|
|
adoptDbgRecords(&BB, InsertPos, false);
|
|
}
|
|
}
|
|
|
|
// If we're inserting a terminator, check if we need to flush out
|
|
// TrailingDbgRecords. Inserting instructions at the end of an incomplete
|
|
// block is handled by the code block above.
|
|
if (isTerminator())
|
|
getParent()->flushTerminatorDbgRecords();
|
|
}
|
|
|
|
/// Unlink this instruction from its current basic block and insert it into the
|
|
/// basic block that MovePos lives in, right before MovePos.
|
|
void Instruction::moveBefore(Instruction *MovePos) {
|
|
moveBeforeImpl(*MovePos->getParent(), MovePos->getIterator(), false);
|
|
}
|
|
|
|
void Instruction::moveBeforePreserving(Instruction *MovePos) {
|
|
moveBeforeImpl(*MovePos->getParent(), MovePos->getIterator(), true);
|
|
}
|
|
|
|
void Instruction::moveAfter(Instruction *MovePos) {
|
|
auto NextIt = std::next(MovePos->getIterator());
|
|
// We want this instruction to be moved to before NextIt in the instruction
|
|
// list, but before NextIt's debug value range.
|
|
NextIt.setHeadBit(true);
|
|
moveBeforeImpl(*MovePos->getParent(), NextIt, false);
|
|
}
|
|
|
|
void Instruction::moveAfterPreserving(Instruction *MovePos) {
|
|
auto NextIt = std::next(MovePos->getIterator());
|
|
// We want this instruction and its debug range to be moved to before NextIt
|
|
// in the instruction list, but before NextIt's debug value range.
|
|
NextIt.setHeadBit(true);
|
|
moveBeforeImpl(*MovePos->getParent(), NextIt, true);
|
|
}
|
|
|
|
void Instruction::moveBefore(BasicBlock &BB, InstListType::iterator I) {
|
|
moveBeforeImpl(BB, I, false);
|
|
}
|
|
|
|
void Instruction::moveBeforePreserving(BasicBlock &BB,
|
|
InstListType::iterator I) {
|
|
moveBeforeImpl(BB, I, true);
|
|
}
|
|
|
|
void Instruction::moveBeforeImpl(BasicBlock &BB, InstListType::iterator I,
|
|
bool Preserve) {
|
|
assert(I == BB.end() || I->getParent() == &BB);
|
|
bool InsertAtHead = I.getHeadBit();
|
|
|
|
// If we've been given the "Preserve" flag, then just move the DbgRecords with
|
|
// the instruction, no more special handling needed.
|
|
if (BB.IsNewDbgInfoFormat && DebugMarker && !Preserve) {
|
|
if (I != this->getIterator() || InsertAtHead) {
|
|
// "this" is definitely moving in the list, or it's moving ahead of its
|
|
// attached DbgVariableRecords. Detach any existing DbgRecords.
|
|
handleMarkerRemoval();
|
|
}
|
|
}
|
|
|
|
// Move this single instruction. Use the list splice method directly, not
|
|
// the block splicer, which will do more debug-info things.
|
|
BB.getInstList().splice(I, getParent()->getInstList(), getIterator());
|
|
|
|
if (BB.IsNewDbgInfoFormat && !Preserve) {
|
|
DbgMarker *NextMarker = getParent()->getNextMarker(this);
|
|
|
|
// If we're inserting at point I, and not in front of the DbgRecords
|
|
// attached there, then we should absorb the DbgRecords attached to I.
|
|
if (!InsertAtHead && NextMarker && !NextMarker->empty()) {
|
|
adoptDbgRecords(&BB, I, false);
|
|
}
|
|
}
|
|
|
|
if (isTerminator())
|
|
getParent()->flushTerminatorDbgRecords();
|
|
}
|
|
|
|
iterator_range<DbgRecord::self_iterator> Instruction::cloneDebugInfoFrom(
|
|
const Instruction *From, std::optional<DbgRecord::self_iterator> FromHere,
|
|
bool InsertAtHead) {
|
|
if (!From->DebugMarker)
|
|
return DbgMarker::getEmptyDbgRecordRange();
|
|
|
|
assert(getParent()->IsNewDbgInfoFormat);
|
|
assert(getParent()->IsNewDbgInfoFormat ==
|
|
From->getParent()->IsNewDbgInfoFormat);
|
|
|
|
if (!DebugMarker)
|
|
getParent()->createMarker(this);
|
|
|
|
return DebugMarker->cloneDebugInfoFrom(From->DebugMarker, FromHere,
|
|
InsertAtHead);
|
|
}
|
|
|
|
std::optional<DbgRecord::self_iterator>
|
|
Instruction::getDbgReinsertionPosition() {
|
|
// Is there a marker on the next instruction?
|
|
DbgMarker *NextMarker = getParent()->getNextMarker(this);
|
|
if (!NextMarker)
|
|
return std::nullopt;
|
|
|
|
// Are there any DbgRecords in the next marker?
|
|
if (NextMarker->StoredDbgRecords.empty())
|
|
return std::nullopt;
|
|
|
|
return NextMarker->StoredDbgRecords.begin();
|
|
}
|
|
|
|
bool Instruction::hasDbgRecords() const { return !getDbgRecordRange().empty(); }
|
|
|
|
void Instruction::adoptDbgRecords(BasicBlock *BB, BasicBlock::iterator It,
|
|
bool InsertAtHead) {
|
|
DbgMarker *SrcMarker = BB->getMarker(It);
|
|
auto ReleaseTrailingDbgRecords = [BB, It, SrcMarker]() {
|
|
if (BB->end() == It) {
|
|
SrcMarker->eraseFromParent();
|
|
BB->deleteTrailingDbgRecords();
|
|
}
|
|
};
|
|
|
|
if (!SrcMarker || SrcMarker->StoredDbgRecords.empty()) {
|
|
ReleaseTrailingDbgRecords();
|
|
return;
|
|
}
|
|
|
|
// If we have DbgMarkers attached to this instruction, we have to honour the
|
|
// ordering of DbgRecords between this and the other marker. Fall back to just
|
|
// absorbing from the source.
|
|
if (DebugMarker || It == BB->end()) {
|
|
// Ensure we _do_ have a marker.
|
|
getParent()->createMarker(this);
|
|
DebugMarker->absorbDebugValues(*SrcMarker, InsertAtHead);
|
|
|
|
// Having transferred everything out of SrcMarker, we _could_ clean it up
|
|
// and free the marker now. However, that's a lot of heap-accounting for a
|
|
// small amount of memory with a good chance of re-use. Leave it for the
|
|
// moment. It will be released when the Instruction is freed in the worst
|
|
// case.
|
|
// However: if we transferred from a trailing marker off the end of the
|
|
// block, it's important to not leave the empty marker trailing. It will
|
|
// give a misleading impression that some debug records have been left
|
|
// trailing.
|
|
ReleaseTrailingDbgRecords();
|
|
} else {
|
|
// Optimisation: we're transferring all the DbgRecords from the source
|
|
// marker onto this empty location: just adopt the other instructions
|
|
// marker.
|
|
DebugMarker = SrcMarker;
|
|
DebugMarker->MarkedInstr = this;
|
|
It->DebugMarker = nullptr;
|
|
}
|
|
}
|
|
|
|
void Instruction::dropDbgRecords() {
|
|
if (DebugMarker)
|
|
DebugMarker->dropDbgRecords();
|
|
}
|
|
|
|
void Instruction::dropOneDbgRecord(DbgRecord *DVR) {
|
|
DebugMarker->dropOneDbgRecord(DVR);
|
|
}
|
|
|
|
bool Instruction::comesBefore(const Instruction *Other) const {
|
|
assert(getParent() && Other->getParent() &&
|
|
"instructions without BB parents have no order");
|
|
assert(getParent() == Other->getParent() &&
|
|
"cross-BB instruction order comparison");
|
|
if (!getParent()->isInstrOrderValid())
|
|
const_cast<BasicBlock *>(getParent())->renumberInstructions();
|
|
return Order < Other->Order;
|
|
}
|
|
|
|
std::optional<BasicBlock::iterator> Instruction::getInsertionPointAfterDef() {
|
|
assert(!getType()->isVoidTy() && "Instruction must define result");
|
|
BasicBlock *InsertBB;
|
|
BasicBlock::iterator InsertPt;
|
|
if (auto *PN = dyn_cast<PHINode>(this)) {
|
|
InsertBB = PN->getParent();
|
|
InsertPt = InsertBB->getFirstInsertionPt();
|
|
} else if (auto *II = dyn_cast<InvokeInst>(this)) {
|
|
InsertBB = II->getNormalDest();
|
|
InsertPt = InsertBB->getFirstInsertionPt();
|
|
} else if (isa<CallBrInst>(this)) {
|
|
// Def is available in multiple successors, there's no single dominating
|
|
// insertion point.
|
|
return std::nullopt;
|
|
} else {
|
|
assert(!isTerminator() && "Only invoke/callbr terminators return value");
|
|
InsertBB = getParent();
|
|
InsertPt = std::next(getIterator());
|
|
// Any instruction inserted immediately after "this" will come before any
|
|
// debug-info records take effect -- thus, set the head bit indicating that
|
|
// to debug-info-transfer code.
|
|
InsertPt.setHeadBit(true);
|
|
}
|
|
|
|
// catchswitch blocks don't have any legal insertion point (because they
|
|
// are both an exception pad and a terminator).
|
|
if (InsertPt == InsertBB->end())
|
|
return std::nullopt;
|
|
return InsertPt;
|
|
}
|
|
|
|
bool Instruction::isOnlyUserOfAnyOperand() {
|
|
return any_of(operands(), [](Value *V) { return V->hasOneUser(); });
|
|
}
|
|
|
|
void Instruction::setHasNoUnsignedWrap(bool b) {
|
|
if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
|
|
Inst->setHasNoUnsignedWrap(b);
|
|
else
|
|
cast<TruncInst>(this)->setHasNoUnsignedWrap(b);
|
|
}
|
|
|
|
void Instruction::setHasNoSignedWrap(bool b) {
|
|
if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
|
|
Inst->setHasNoSignedWrap(b);
|
|
else
|
|
cast<TruncInst>(this)->setHasNoSignedWrap(b);
|
|
}
|
|
|
|
void Instruction::setIsExact(bool b) {
|
|
cast<PossiblyExactOperator>(this)->setIsExact(b);
|
|
}
|
|
|
|
void Instruction::setNonNeg(bool b) {
|
|
assert(isa<PossiblyNonNegInst>(this) && "Must be zext/uitofp");
|
|
SubclassOptionalData = (SubclassOptionalData & ~PossiblyNonNegInst::NonNeg) |
|
|
(b * PossiblyNonNegInst::NonNeg);
|
|
}
|
|
|
|
bool Instruction::hasNoUnsignedWrap() const {
|
|
if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
|
|
return Inst->hasNoUnsignedWrap();
|
|
|
|
return cast<TruncInst>(this)->hasNoUnsignedWrap();
|
|
}
|
|
|
|
bool Instruction::hasNoSignedWrap() const {
|
|
if (auto *Inst = dyn_cast<OverflowingBinaryOperator>(this))
|
|
return Inst->hasNoSignedWrap();
|
|
|
|
return cast<TruncInst>(this)->hasNoSignedWrap();
|
|
}
|
|
|
|
bool Instruction::hasNonNeg() const {
|
|
assert(isa<PossiblyNonNegInst>(this) && "Must be zext/uitofp");
|
|
return (SubclassOptionalData & PossiblyNonNegInst::NonNeg) != 0;
|
|
}
|
|
|
|
bool Instruction::hasPoisonGeneratingFlags() const {
|
|
return cast<Operator>(this)->hasPoisonGeneratingFlags();
|
|
}
|
|
|
|
void Instruction::dropPoisonGeneratingFlags() {
|
|
switch (getOpcode()) {
|
|
case Instruction::Add:
|
|
case Instruction::Sub:
|
|
case Instruction::Mul:
|
|
case Instruction::Shl:
|
|
cast<OverflowingBinaryOperator>(this)->setHasNoUnsignedWrap(false);
|
|
cast<OverflowingBinaryOperator>(this)->setHasNoSignedWrap(false);
|
|
break;
|
|
|
|
case Instruction::UDiv:
|
|
case Instruction::SDiv:
|
|
case Instruction::AShr:
|
|
case Instruction::LShr:
|
|
cast<PossiblyExactOperator>(this)->setIsExact(false);
|
|
break;
|
|
|
|
case Instruction::Or:
|
|
cast<PossiblyDisjointInst>(this)->setIsDisjoint(false);
|
|
break;
|
|
|
|
case Instruction::GetElementPtr:
|
|
cast<GetElementPtrInst>(this)->setNoWrapFlags(GEPNoWrapFlags::none());
|
|
break;
|
|
|
|
case Instruction::UIToFP:
|
|
case Instruction::ZExt:
|
|
setNonNeg(false);
|
|
break;
|
|
|
|
case Instruction::Trunc:
|
|
cast<TruncInst>(this)->setHasNoUnsignedWrap(false);
|
|
cast<TruncInst>(this)->setHasNoSignedWrap(false);
|
|
break;
|
|
}
|
|
|
|
if (isa<FPMathOperator>(this)) {
|
|
setHasNoNaNs(false);
|
|
setHasNoInfs(false);
|
|
}
|
|
|
|
assert(!hasPoisonGeneratingFlags() && "must be kept in sync");
|
|
}
|
|
|
|
bool Instruction::hasPoisonGeneratingMetadata() const {
|
|
return hasMetadata(LLVMContext::MD_range) ||
|
|
hasMetadata(LLVMContext::MD_nonnull) ||
|
|
hasMetadata(LLVMContext::MD_align);
|
|
}
|
|
|
|
void Instruction::dropPoisonGeneratingMetadata() {
|
|
eraseMetadata(LLVMContext::MD_range);
|
|
eraseMetadata(LLVMContext::MD_nonnull);
|
|
eraseMetadata(LLVMContext::MD_align);
|
|
}
|
|
|
|
bool Instruction::hasPoisonGeneratingReturnAttributes() const {
|
|
if (const auto *CB = dyn_cast<CallBase>(this)) {
|
|
AttributeSet RetAttrs = CB->getAttributes().getRetAttrs();
|
|
return RetAttrs.hasAttribute(Attribute::Range) ||
|
|
RetAttrs.hasAttribute(Attribute::Alignment) ||
|
|
RetAttrs.hasAttribute(Attribute::NonNull);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Instruction::dropPoisonGeneratingReturnAttributes() {
|
|
if (auto *CB = dyn_cast<CallBase>(this)) {
|
|
AttributeMask AM;
|
|
AM.addAttribute(Attribute::Range);
|
|
AM.addAttribute(Attribute::Alignment);
|
|
AM.addAttribute(Attribute::NonNull);
|
|
CB->removeRetAttrs(AM);
|
|
}
|
|
assert(!hasPoisonGeneratingReturnAttributes() && "must be kept in sync");
|
|
}
|
|
|
|
void Instruction::dropUBImplyingAttrsAndUnknownMetadata(
|
|
ArrayRef<unsigned> KnownIDs) {
|
|
dropUnknownNonDebugMetadata(KnownIDs);
|
|
auto *CB = dyn_cast<CallBase>(this);
|
|
if (!CB)
|
|
return;
|
|
// For call instructions, we also need to drop parameter and return attributes
|
|
// that are can cause UB if the call is moved to a location where the
|
|
// attribute is not valid.
|
|
AttributeList AL = CB->getAttributes();
|
|
if (AL.isEmpty())
|
|
return;
|
|
AttributeMask UBImplyingAttributes =
|
|
AttributeFuncs::getUBImplyingAttributes();
|
|
for (unsigned ArgNo = 0; ArgNo < CB->arg_size(); ArgNo++)
|
|
CB->removeParamAttrs(ArgNo, UBImplyingAttributes);
|
|
CB->removeRetAttrs(UBImplyingAttributes);
|
|
}
|
|
|
|
void Instruction::dropUBImplyingAttrsAndMetadata() {
|
|
// !annotation metadata does not impact semantics.
|
|
// !range, !nonnull and !align produce poison, so they are safe to speculate.
|
|
// !noundef and various AA metadata must be dropped, as it generally produces
|
|
// immediate undefined behavior.
|
|
unsigned KnownIDs[] = {LLVMContext::MD_annotation, LLVMContext::MD_range,
|
|
LLVMContext::MD_nonnull, LLVMContext::MD_align};
|
|
dropUBImplyingAttrsAndUnknownMetadata(KnownIDs);
|
|
}
|
|
|
|
bool Instruction::isExact() const {
|
|
return cast<PossiblyExactOperator>(this)->isExact();
|
|
}
|
|
|
|
void Instruction::setFast(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setFast(B);
|
|
}
|
|
|
|
void Instruction::setHasAllowReassoc(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setHasAllowReassoc(B);
|
|
}
|
|
|
|
void Instruction::setHasNoNaNs(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setHasNoNaNs(B);
|
|
}
|
|
|
|
void Instruction::setHasNoInfs(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setHasNoInfs(B);
|
|
}
|
|
|
|
void Instruction::setHasNoSignedZeros(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setHasNoSignedZeros(B);
|
|
}
|
|
|
|
void Instruction::setHasAllowReciprocal(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setHasAllowReciprocal(B);
|
|
}
|
|
|
|
void Instruction::setHasAllowContract(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setHasAllowContract(B);
|
|
}
|
|
|
|
void Instruction::setHasApproxFunc(bool B) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setHasApproxFunc(B);
|
|
}
|
|
|
|
void Instruction::setFastMathFlags(FastMathFlags FMF) {
|
|
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->setFastMathFlags(FMF);
|
|
}
|
|
|
|
void Instruction::copyFastMathFlags(FastMathFlags FMF) {
|
|
assert(isa<FPMathOperator>(this) && "copying fast-math flag on invalid op");
|
|
cast<FPMathOperator>(this)->copyFastMathFlags(FMF);
|
|
}
|
|
|
|
bool Instruction::isFast() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->isFast();
|
|
}
|
|
|
|
bool Instruction::hasAllowReassoc() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->hasAllowReassoc();
|
|
}
|
|
|
|
bool Instruction::hasNoNaNs() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->hasNoNaNs();
|
|
}
|
|
|
|
bool Instruction::hasNoInfs() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->hasNoInfs();
|
|
}
|
|
|
|
bool Instruction::hasNoSignedZeros() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->hasNoSignedZeros();
|
|
}
|
|
|
|
bool Instruction::hasAllowReciprocal() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->hasAllowReciprocal();
|
|
}
|
|
|
|
bool Instruction::hasAllowContract() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->hasAllowContract();
|
|
}
|
|
|
|
bool Instruction::hasApproxFunc() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->hasApproxFunc();
|
|
}
|
|
|
|
FastMathFlags Instruction::getFastMathFlags() const {
|
|
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
|
|
return cast<FPMathOperator>(this)->getFastMathFlags();
|
|
}
|
|
|
|
void Instruction::copyFastMathFlags(const Instruction *I) {
|
|
copyFastMathFlags(I->getFastMathFlags());
|
|
}
|
|
|
|
void Instruction::copyIRFlags(const Value *V, bool IncludeWrapFlags) {
|
|
// Copy the wrapping flags.
|
|
if (IncludeWrapFlags && isa<OverflowingBinaryOperator>(this)) {
|
|
if (auto *OB = dyn_cast<OverflowingBinaryOperator>(V)) {
|
|
setHasNoSignedWrap(OB->hasNoSignedWrap());
|
|
setHasNoUnsignedWrap(OB->hasNoUnsignedWrap());
|
|
}
|
|
}
|
|
|
|
if (auto *TI = dyn_cast<TruncInst>(V)) {
|
|
if (isa<TruncInst>(this)) {
|
|
setHasNoSignedWrap(TI->hasNoSignedWrap());
|
|
setHasNoUnsignedWrap(TI->hasNoUnsignedWrap());
|
|
}
|
|
}
|
|
|
|
// Copy the exact flag.
|
|
if (auto *PE = dyn_cast<PossiblyExactOperator>(V))
|
|
if (isa<PossiblyExactOperator>(this))
|
|
setIsExact(PE->isExact());
|
|
|
|
if (auto *SrcPD = dyn_cast<PossiblyDisjointInst>(V))
|
|
if (auto *DestPD = dyn_cast<PossiblyDisjointInst>(this))
|
|
DestPD->setIsDisjoint(SrcPD->isDisjoint());
|
|
|
|
// Copy the fast-math flags.
|
|
if (auto *FP = dyn_cast<FPMathOperator>(V))
|
|
if (isa<FPMathOperator>(this))
|
|
copyFastMathFlags(FP->getFastMathFlags());
|
|
|
|
if (auto *SrcGEP = dyn_cast<GetElementPtrInst>(V))
|
|
if (auto *DestGEP = dyn_cast<GetElementPtrInst>(this))
|
|
DestGEP->setNoWrapFlags(SrcGEP->getNoWrapFlags() |
|
|
DestGEP->getNoWrapFlags());
|
|
|
|
if (auto *NNI = dyn_cast<PossiblyNonNegInst>(V))
|
|
if (isa<PossiblyNonNegInst>(this))
|
|
setNonNeg(NNI->hasNonNeg());
|
|
}
|
|
|
|
void Instruction::andIRFlags(const Value *V) {
|
|
if (auto *OB = dyn_cast<OverflowingBinaryOperator>(V)) {
|
|
if (isa<OverflowingBinaryOperator>(this)) {
|
|
setHasNoSignedWrap(hasNoSignedWrap() && OB->hasNoSignedWrap());
|
|
setHasNoUnsignedWrap(hasNoUnsignedWrap() && OB->hasNoUnsignedWrap());
|
|
}
|
|
}
|
|
|
|
if (auto *TI = dyn_cast<TruncInst>(V)) {
|
|
if (isa<TruncInst>(this)) {
|
|
setHasNoSignedWrap(hasNoSignedWrap() && TI->hasNoSignedWrap());
|
|
setHasNoUnsignedWrap(hasNoUnsignedWrap() && TI->hasNoUnsignedWrap());
|
|
}
|
|
}
|
|
|
|
if (auto *PE = dyn_cast<PossiblyExactOperator>(V))
|
|
if (isa<PossiblyExactOperator>(this))
|
|
setIsExact(isExact() && PE->isExact());
|
|
|
|
if (auto *SrcPD = dyn_cast<PossiblyDisjointInst>(V))
|
|
if (auto *DestPD = dyn_cast<PossiblyDisjointInst>(this))
|
|
DestPD->setIsDisjoint(DestPD->isDisjoint() && SrcPD->isDisjoint());
|
|
|
|
if (auto *FP = dyn_cast<FPMathOperator>(V)) {
|
|
if (isa<FPMathOperator>(this)) {
|
|
FastMathFlags FM = getFastMathFlags();
|
|
FM &= FP->getFastMathFlags();
|
|
copyFastMathFlags(FM);
|
|
}
|
|
}
|
|
|
|
if (auto *SrcGEP = dyn_cast<GetElementPtrInst>(V))
|
|
if (auto *DestGEP = dyn_cast<GetElementPtrInst>(this))
|
|
DestGEP->setNoWrapFlags(SrcGEP->getNoWrapFlags() &
|
|
DestGEP->getNoWrapFlags());
|
|
|
|
if (auto *NNI = dyn_cast<PossiblyNonNegInst>(V))
|
|
if (isa<PossiblyNonNegInst>(this))
|
|
setNonNeg(hasNonNeg() && NNI->hasNonNeg());
|
|
}
|
|
|
|
const char *Instruction::getOpcodeName(unsigned OpCode) {
|
|
switch (OpCode) {
|
|
// Terminators
|
|
case Ret: return "ret";
|
|
case Br: return "br";
|
|
case Switch: return "switch";
|
|
case IndirectBr: return "indirectbr";
|
|
case Invoke: return "invoke";
|
|
case Resume: return "resume";
|
|
case Unreachable: return "unreachable";
|
|
case CleanupRet: return "cleanupret";
|
|
case CatchRet: return "catchret";
|
|
case CatchPad: return "catchpad";
|
|
case CatchSwitch: return "catchswitch";
|
|
case CallBr: return "callbr";
|
|
|
|
// Standard unary operators...
|
|
case FNeg: return "fneg";
|
|
|
|
// Standard binary operators...
|
|
case Add: return "add";
|
|
case FAdd: return "fadd";
|
|
case Sub: return "sub";
|
|
case FSub: return "fsub";
|
|
case Mul: return "mul";
|
|
case FMul: return "fmul";
|
|
case UDiv: return "udiv";
|
|
case SDiv: return "sdiv";
|
|
case FDiv: return "fdiv";
|
|
case URem: return "urem";
|
|
case SRem: return "srem";
|
|
case FRem: return "frem";
|
|
|
|
// Logical operators...
|
|
case And: return "and";
|
|
case Or : return "or";
|
|
case Xor: return "xor";
|
|
|
|
// Memory instructions...
|
|
case Alloca: return "alloca";
|
|
case Load: return "load";
|
|
case Store: return "store";
|
|
case AtomicCmpXchg: return "cmpxchg";
|
|
case AtomicRMW: return "atomicrmw";
|
|
case Fence: return "fence";
|
|
case GetElementPtr: return "getelementptr";
|
|
|
|
// Convert instructions...
|
|
case Trunc: return "trunc";
|
|
case ZExt: return "zext";
|
|
case SExt: return "sext";
|
|
case FPTrunc: return "fptrunc";
|
|
case FPExt: return "fpext";
|
|
case FPToUI: return "fptoui";
|
|
case FPToSI: return "fptosi";
|
|
case UIToFP: return "uitofp";
|
|
case SIToFP: return "sitofp";
|
|
case IntToPtr: return "inttoptr";
|
|
case PtrToInt: return "ptrtoint";
|
|
case BitCast: return "bitcast";
|
|
case AddrSpaceCast: return "addrspacecast";
|
|
|
|
// Other instructions...
|
|
case ICmp: return "icmp";
|
|
case FCmp: return "fcmp";
|
|
case PHI: return "phi";
|
|
case Select: return "select";
|
|
case Call: return "call";
|
|
case Shl: return "shl";
|
|
case LShr: return "lshr";
|
|
case AShr: return "ashr";
|
|
case VAArg: return "va_arg";
|
|
case ExtractElement: return "extractelement";
|
|
case InsertElement: return "insertelement";
|
|
case ShuffleVector: return "shufflevector";
|
|
case ExtractValue: return "extractvalue";
|
|
case InsertValue: return "insertvalue";
|
|
case LandingPad: return "landingpad";
|
|
case CleanupPad: return "cleanuppad";
|
|
case Freeze: return "freeze";
|
|
|
|
default: return "<Invalid operator> ";
|
|
}
|
|
}
|
|
|
|
/// This must be kept in sync with FunctionComparator::cmpOperations in
|
|
/// lib/Transforms/IPO/MergeFunctions.cpp.
|
|
bool Instruction::hasSameSpecialState(const Instruction *I2,
|
|
bool IgnoreAlignment) const {
|
|
auto I1 = this;
|
|
assert(I1->getOpcode() == I2->getOpcode() &&
|
|
"Can not compare special state of different instructions");
|
|
|
|
if (const AllocaInst *AI = dyn_cast<AllocaInst>(I1))
|
|
return AI->getAllocatedType() == cast<AllocaInst>(I2)->getAllocatedType() &&
|
|
(AI->getAlign() == cast<AllocaInst>(I2)->getAlign() ||
|
|
IgnoreAlignment);
|
|
if (const LoadInst *LI = dyn_cast<LoadInst>(I1))
|
|
return LI->isVolatile() == cast<LoadInst>(I2)->isVolatile() &&
|
|
(LI->getAlign() == cast<LoadInst>(I2)->getAlign() ||
|
|
IgnoreAlignment) &&
|
|
LI->getOrdering() == cast<LoadInst>(I2)->getOrdering() &&
|
|
LI->getSyncScopeID() == cast<LoadInst>(I2)->getSyncScopeID();
|
|
if (const StoreInst *SI = dyn_cast<StoreInst>(I1))
|
|
return SI->isVolatile() == cast<StoreInst>(I2)->isVolatile() &&
|
|
(SI->getAlign() == cast<StoreInst>(I2)->getAlign() ||
|
|
IgnoreAlignment) &&
|
|
SI->getOrdering() == cast<StoreInst>(I2)->getOrdering() &&
|
|
SI->getSyncScopeID() == cast<StoreInst>(I2)->getSyncScopeID();
|
|
if (const CmpInst *CI = dyn_cast<CmpInst>(I1))
|
|
return CI->getPredicate() == cast<CmpInst>(I2)->getPredicate();
|
|
if (const CallInst *CI = dyn_cast<CallInst>(I1))
|
|
return CI->isTailCall() == cast<CallInst>(I2)->isTailCall() &&
|
|
CI->getCallingConv() == cast<CallInst>(I2)->getCallingConv() &&
|
|
CI->getAttributes() == cast<CallInst>(I2)->getAttributes() &&
|
|
CI->hasIdenticalOperandBundleSchema(*cast<CallInst>(I2));
|
|
if (const InvokeInst *CI = dyn_cast<InvokeInst>(I1))
|
|
return CI->getCallingConv() == cast<InvokeInst>(I2)->getCallingConv() &&
|
|
CI->getAttributes() == cast<InvokeInst>(I2)->getAttributes() &&
|
|
CI->hasIdenticalOperandBundleSchema(*cast<InvokeInst>(I2));
|
|
if (const CallBrInst *CI = dyn_cast<CallBrInst>(I1))
|
|
return CI->getCallingConv() == cast<CallBrInst>(I2)->getCallingConv() &&
|
|
CI->getAttributes() == cast<CallBrInst>(I2)->getAttributes() &&
|
|
CI->hasIdenticalOperandBundleSchema(*cast<CallBrInst>(I2));
|
|
if (const InsertValueInst *IVI = dyn_cast<InsertValueInst>(I1))
|
|
return IVI->getIndices() == cast<InsertValueInst>(I2)->getIndices();
|
|
if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(I1))
|
|
return EVI->getIndices() == cast<ExtractValueInst>(I2)->getIndices();
|
|
if (const FenceInst *FI = dyn_cast<FenceInst>(I1))
|
|
return FI->getOrdering() == cast<FenceInst>(I2)->getOrdering() &&
|
|
FI->getSyncScopeID() == cast<FenceInst>(I2)->getSyncScopeID();
|
|
if (const AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(I1))
|
|
return CXI->isVolatile() == cast<AtomicCmpXchgInst>(I2)->isVolatile() &&
|
|
CXI->isWeak() == cast<AtomicCmpXchgInst>(I2)->isWeak() &&
|
|
CXI->getSuccessOrdering() ==
|
|
cast<AtomicCmpXchgInst>(I2)->getSuccessOrdering() &&
|
|
CXI->getFailureOrdering() ==
|
|
cast<AtomicCmpXchgInst>(I2)->getFailureOrdering() &&
|
|
CXI->getSyncScopeID() ==
|
|
cast<AtomicCmpXchgInst>(I2)->getSyncScopeID();
|
|
if (const AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(I1))
|
|
return RMWI->getOperation() == cast<AtomicRMWInst>(I2)->getOperation() &&
|
|
RMWI->isVolatile() == cast<AtomicRMWInst>(I2)->isVolatile() &&
|
|
RMWI->getOrdering() == cast<AtomicRMWInst>(I2)->getOrdering() &&
|
|
RMWI->getSyncScopeID() == cast<AtomicRMWInst>(I2)->getSyncScopeID();
|
|
if (const ShuffleVectorInst *SVI = dyn_cast<ShuffleVectorInst>(I1))
|
|
return SVI->getShuffleMask() ==
|
|
cast<ShuffleVectorInst>(I2)->getShuffleMask();
|
|
if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(I1))
|
|
return GEP->getSourceElementType() ==
|
|
cast<GetElementPtrInst>(I2)->getSourceElementType();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Instruction::isIdenticalTo(const Instruction *I) const {
|
|
return isIdenticalToWhenDefined(I) &&
|
|
SubclassOptionalData == I->SubclassOptionalData;
|
|
}
|
|
|
|
bool Instruction::isIdenticalToWhenDefined(const Instruction *I) const {
|
|
if (getOpcode() != I->getOpcode() ||
|
|
getNumOperands() != I->getNumOperands() ||
|
|
getType() != I->getType())
|
|
return false;
|
|
|
|
// If both instructions have no operands, they are identical.
|
|
if (getNumOperands() == 0 && I->getNumOperands() == 0)
|
|
return this->hasSameSpecialState(I);
|
|
|
|
// We have two instructions of identical opcode and #operands. Check to see
|
|
// if all operands are the same.
|
|
if (!std::equal(op_begin(), op_end(), I->op_begin()))
|
|
return false;
|
|
|
|
// WARNING: this logic must be kept in sync with EliminateDuplicatePHINodes()!
|
|
if (const PHINode *thisPHI = dyn_cast<PHINode>(this)) {
|
|
const PHINode *otherPHI = cast<PHINode>(I);
|
|
return std::equal(thisPHI->block_begin(), thisPHI->block_end(),
|
|
otherPHI->block_begin());
|
|
}
|
|
|
|
return this->hasSameSpecialState(I);
|
|
}
|
|
|
|
// Keep this in sync with FunctionComparator::cmpOperations in
|
|
// lib/Transforms/IPO/MergeFunctions.cpp.
|
|
bool Instruction::isSameOperationAs(const Instruction *I,
|
|
unsigned flags) const {
|
|
bool IgnoreAlignment = flags & CompareIgnoringAlignment;
|
|
bool UseScalarTypes = flags & CompareUsingScalarTypes;
|
|
|
|
if (getOpcode() != I->getOpcode() ||
|
|
getNumOperands() != I->getNumOperands() ||
|
|
(UseScalarTypes ?
|
|
getType()->getScalarType() != I->getType()->getScalarType() :
|
|
getType() != I->getType()))
|
|
return false;
|
|
|
|
// We have two instructions of identical opcode and #operands. Check to see
|
|
// if all operands are the same type
|
|
for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
|
|
if (UseScalarTypes ?
|
|
getOperand(i)->getType()->getScalarType() !=
|
|
I->getOperand(i)->getType()->getScalarType() :
|
|
getOperand(i)->getType() != I->getOperand(i)->getType())
|
|
return false;
|
|
|
|
return this->hasSameSpecialState(I, IgnoreAlignment);
|
|
}
|
|
|
|
bool Instruction::isUsedOutsideOfBlock(const BasicBlock *BB) const {
|
|
for (const Use &U : uses()) {
|
|
// PHI nodes uses values in the corresponding predecessor block. For other
|
|
// instructions, just check to see whether the parent of the use matches up.
|
|
const Instruction *I = cast<Instruction>(U.getUser());
|
|
const PHINode *PN = dyn_cast<PHINode>(I);
|
|
if (!PN) {
|
|
if (I->getParent() != BB)
|
|
return true;
|
|
continue;
|
|
}
|
|
|
|
if (PN->getIncomingBlock(U) != BB)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Instruction::mayReadFromMemory() const {
|
|
switch (getOpcode()) {
|
|
default: return false;
|
|
case Instruction::VAArg:
|
|
case Instruction::Load:
|
|
case Instruction::Fence: // FIXME: refine definition of mayReadFromMemory
|
|
case Instruction::AtomicCmpXchg:
|
|
case Instruction::AtomicRMW:
|
|
case Instruction::CatchPad:
|
|
case Instruction::CatchRet:
|
|
return true;
|
|
case Instruction::Call:
|
|
case Instruction::Invoke:
|
|
case Instruction::CallBr:
|
|
return !cast<CallBase>(this)->onlyWritesMemory();
|
|
case Instruction::Store:
|
|
return !cast<StoreInst>(this)->isUnordered();
|
|
}
|
|
}
|
|
|
|
bool Instruction::mayWriteToMemory() const {
|
|
switch (getOpcode()) {
|
|
default: return false;
|
|
case Instruction::Fence: // FIXME: refine definition of mayWriteToMemory
|
|
case Instruction::Store:
|
|
case Instruction::VAArg:
|
|
case Instruction::AtomicCmpXchg:
|
|
case Instruction::AtomicRMW:
|
|
case Instruction::CatchPad:
|
|
case Instruction::CatchRet:
|
|
return true;
|
|
case Instruction::Call:
|
|
case Instruction::Invoke:
|
|
case Instruction::CallBr:
|
|
return !cast<CallBase>(this)->onlyReadsMemory();
|
|
case Instruction::Load:
|
|
return !cast<LoadInst>(this)->isUnordered();
|
|
}
|
|
}
|
|
|
|
bool Instruction::isAtomic() const {
|
|
switch (getOpcode()) {
|
|
default:
|
|
return false;
|
|
case Instruction::AtomicCmpXchg:
|
|
case Instruction::AtomicRMW:
|
|
case Instruction::Fence:
|
|
return true;
|
|
case Instruction::Load:
|
|
return cast<LoadInst>(this)->getOrdering() != AtomicOrdering::NotAtomic;
|
|
case Instruction::Store:
|
|
return cast<StoreInst>(this)->getOrdering() != AtomicOrdering::NotAtomic;
|
|
}
|
|
}
|
|
|
|
bool Instruction::hasAtomicLoad() const {
|
|
assert(isAtomic());
|
|
switch (getOpcode()) {
|
|
default:
|
|
return false;
|
|
case Instruction::AtomicCmpXchg:
|
|
case Instruction::AtomicRMW:
|
|
case Instruction::Load:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Instruction::hasAtomicStore() const {
|
|
assert(isAtomic());
|
|
switch (getOpcode()) {
|
|
default:
|
|
return false;
|
|
case Instruction::AtomicCmpXchg:
|
|
case Instruction::AtomicRMW:
|
|
case Instruction::Store:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Instruction::isVolatile() const {
|
|
switch (getOpcode()) {
|
|
default:
|
|
return false;
|
|
case Instruction::AtomicRMW:
|
|
return cast<AtomicRMWInst>(this)->isVolatile();
|
|
case Instruction::Store:
|
|
return cast<StoreInst>(this)->isVolatile();
|
|
case Instruction::Load:
|
|
return cast<LoadInst>(this)->isVolatile();
|
|
case Instruction::AtomicCmpXchg:
|
|
return cast<AtomicCmpXchgInst>(this)->isVolatile();
|
|
case Instruction::Call:
|
|
case Instruction::Invoke:
|
|
// There are a very limited number of intrinsics with volatile flags.
|
|
if (auto *II = dyn_cast<IntrinsicInst>(this)) {
|
|
if (auto *MI = dyn_cast<MemIntrinsic>(II))
|
|
return MI->isVolatile();
|
|
switch (II->getIntrinsicID()) {
|
|
default: break;
|
|
case Intrinsic::matrix_column_major_load:
|
|
return cast<ConstantInt>(II->getArgOperand(2))->isOne();
|
|
case Intrinsic::matrix_column_major_store:
|
|
return cast<ConstantInt>(II->getArgOperand(3))->isOne();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Type *Instruction::getAccessType() const {
|
|
switch (getOpcode()) {
|
|
case Instruction::Store:
|
|
return cast<StoreInst>(this)->getValueOperand()->getType();
|
|
case Instruction::Load:
|
|
case Instruction::AtomicRMW:
|
|
return getType();
|
|
case Instruction::AtomicCmpXchg:
|
|
return cast<AtomicCmpXchgInst>(this)->getNewValOperand()->getType();
|
|
case Instruction::Call:
|
|
case Instruction::Invoke:
|
|
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(this)) {
|
|
switch (II->getIntrinsicID()) {
|
|
case Intrinsic::masked_load:
|
|
case Intrinsic::masked_gather:
|
|
case Intrinsic::masked_expandload:
|
|
case Intrinsic::vp_load:
|
|
case Intrinsic::vp_gather:
|
|
case Intrinsic::experimental_vp_strided_load:
|
|
return II->getType();
|
|
case Intrinsic::masked_store:
|
|
case Intrinsic::masked_scatter:
|
|
case Intrinsic::masked_compressstore:
|
|
case Intrinsic::vp_store:
|
|
case Intrinsic::vp_scatter:
|
|
case Intrinsic::experimental_vp_strided_store:
|
|
return II->getOperand(0)->getType();
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static bool canUnwindPastLandingPad(const LandingPadInst *LP,
|
|
bool IncludePhaseOneUnwind) {
|
|
// Because phase one unwinding skips cleanup landingpads, we effectively
|
|
// unwind past this frame, and callers need to have valid unwind info.
|
|
if (LP->isCleanup())
|
|
return IncludePhaseOneUnwind;
|
|
|
|
for (unsigned I = 0; I < LP->getNumClauses(); ++I) {
|
|
Constant *Clause = LP->getClause(I);
|
|
// catch ptr null catches all exceptions.
|
|
if (LP->isCatch(I) && isa<ConstantPointerNull>(Clause))
|
|
return false;
|
|
// filter [0 x ptr] catches all exceptions.
|
|
if (LP->isFilter(I) && Clause->getType()->getArrayNumElements() == 0)
|
|
return false;
|
|
}
|
|
|
|
// May catch only some subset of exceptions, in which case other exceptions
|
|
// will continue unwinding.
|
|
return true;
|
|
}
|
|
|
|
bool Instruction::mayThrow(bool IncludePhaseOneUnwind) const {
|
|
switch (getOpcode()) {
|
|
case Instruction::Call:
|
|
return !cast<CallInst>(this)->doesNotThrow();
|
|
case Instruction::CleanupRet:
|
|
return cast<CleanupReturnInst>(this)->unwindsToCaller();
|
|
case Instruction::CatchSwitch:
|
|
return cast<CatchSwitchInst>(this)->unwindsToCaller();
|
|
case Instruction::Resume:
|
|
return true;
|
|
case Instruction::Invoke: {
|
|
// Landingpads themselves don't unwind -- however, an invoke of a skipped
|
|
// landingpad may continue unwinding.
|
|
BasicBlock *UnwindDest = cast<InvokeInst>(this)->getUnwindDest();
|
|
Instruction *Pad = UnwindDest->getFirstNonPHI();
|
|
if (auto *LP = dyn_cast<LandingPadInst>(Pad))
|
|
return canUnwindPastLandingPad(LP, IncludePhaseOneUnwind);
|
|
return false;
|
|
}
|
|
case Instruction::CleanupPad:
|
|
// Treat the same as cleanup landingpad.
|
|
return IncludePhaseOneUnwind;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Instruction::mayHaveSideEffects() const {
|
|
return mayWriteToMemory() || mayThrow() || !willReturn();
|
|
}
|
|
|
|
bool Instruction::isSafeToRemove() const {
|
|
return (!isa<CallInst>(this) || !this->mayHaveSideEffects()) &&
|
|
!this->isTerminator() && !this->isEHPad();
|
|
}
|
|
|
|
bool Instruction::willReturn() const {
|
|
// Volatile store isn't guaranteed to return; see LangRef.
|
|
if (auto *SI = dyn_cast<StoreInst>(this))
|
|
return !SI->isVolatile();
|
|
|
|
if (const auto *CB = dyn_cast<CallBase>(this))
|
|
return CB->hasFnAttr(Attribute::WillReturn);
|
|
return true;
|
|
}
|
|
|
|
bool Instruction::isLifetimeStartOrEnd() const {
|
|
auto *II = dyn_cast<IntrinsicInst>(this);
|
|
if (!II)
|
|
return false;
|
|
Intrinsic::ID ID = II->getIntrinsicID();
|
|
return ID == Intrinsic::lifetime_start || ID == Intrinsic::lifetime_end;
|
|
}
|
|
|
|
bool Instruction::isLaunderOrStripInvariantGroup() const {
|
|
auto *II = dyn_cast<IntrinsicInst>(this);
|
|
if (!II)
|
|
return false;
|
|
Intrinsic::ID ID = II->getIntrinsicID();
|
|
return ID == Intrinsic::launder_invariant_group ||
|
|
ID == Intrinsic::strip_invariant_group;
|
|
}
|
|
|
|
bool Instruction::isDebugOrPseudoInst() const {
|
|
return isa<DbgInfoIntrinsic>(this) || isa<PseudoProbeInst>(this);
|
|
}
|
|
|
|
const Instruction *
|
|
Instruction::getNextNonDebugInstruction(bool SkipPseudoOp) const {
|
|
for (const Instruction *I = getNextNode(); I; I = I->getNextNode())
|
|
if (!isa<DbgInfoIntrinsic>(I) && !(SkipPseudoOp && isa<PseudoProbeInst>(I)))
|
|
return I;
|
|
return nullptr;
|
|
}
|
|
|
|
const Instruction *
|
|
Instruction::getPrevNonDebugInstruction(bool SkipPseudoOp) const {
|
|
for (const Instruction *I = getPrevNode(); I; I = I->getPrevNode())
|
|
if (!isa<DbgInfoIntrinsic>(I) && !(SkipPseudoOp && isa<PseudoProbeInst>(I)))
|
|
return I;
|
|
return nullptr;
|
|
}
|
|
|
|
const DebugLoc &Instruction::getStableDebugLoc() const {
|
|
if (isa<DbgInfoIntrinsic>(this))
|
|
if (const Instruction *Next = getNextNonDebugInstruction())
|
|
return Next->getDebugLoc();
|
|
return getDebugLoc();
|
|
}
|
|
|
|
bool Instruction::isAssociative() const {
|
|
if (auto *II = dyn_cast<IntrinsicInst>(this))
|
|
return II->isAssociative();
|
|
unsigned Opcode = getOpcode();
|
|
if (isAssociative(Opcode))
|
|
return true;
|
|
|
|
switch (Opcode) {
|
|
case FMul:
|
|
case FAdd:
|
|
return cast<FPMathOperator>(this)->hasAllowReassoc() &&
|
|
cast<FPMathOperator>(this)->hasNoSignedZeros();
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Instruction::isCommutative() const {
|
|
if (auto *II = dyn_cast<IntrinsicInst>(this))
|
|
return II->isCommutative();
|
|
// TODO: Should allow icmp/fcmp?
|
|
return isCommutative(getOpcode());
|
|
}
|
|
|
|
unsigned Instruction::getNumSuccessors() const {
|
|
switch (getOpcode()) {
|
|
#define HANDLE_TERM_INST(N, OPC, CLASS) \
|
|
case Instruction::OPC: \
|
|
return static_cast<const CLASS *>(this)->getNumSuccessors();
|
|
#include "llvm/IR/Instruction.def"
|
|
default:
|
|
break;
|
|
}
|
|
llvm_unreachable("not a terminator");
|
|
}
|
|
|
|
BasicBlock *Instruction::getSuccessor(unsigned idx) const {
|
|
switch (getOpcode()) {
|
|
#define HANDLE_TERM_INST(N, OPC, CLASS) \
|
|
case Instruction::OPC: \
|
|
return static_cast<const CLASS *>(this)->getSuccessor(idx);
|
|
#include "llvm/IR/Instruction.def"
|
|
default:
|
|
break;
|
|
}
|
|
llvm_unreachable("not a terminator");
|
|
}
|
|
|
|
void Instruction::setSuccessor(unsigned idx, BasicBlock *B) {
|
|
switch (getOpcode()) {
|
|
#define HANDLE_TERM_INST(N, OPC, CLASS) \
|
|
case Instruction::OPC: \
|
|
return static_cast<CLASS *>(this)->setSuccessor(idx, B);
|
|
#include "llvm/IR/Instruction.def"
|
|
default:
|
|
break;
|
|
}
|
|
llvm_unreachable("not a terminator");
|
|
}
|
|
|
|
void Instruction::replaceSuccessorWith(BasicBlock *OldBB, BasicBlock *NewBB) {
|
|
for (unsigned Idx = 0, NumSuccessors = Instruction::getNumSuccessors();
|
|
Idx != NumSuccessors; ++Idx)
|
|
if (getSuccessor(Idx) == OldBB)
|
|
setSuccessor(Idx, NewBB);
|
|
}
|
|
|
|
Instruction *Instruction::cloneImpl() const {
|
|
llvm_unreachable("Subclass of Instruction failed to implement cloneImpl");
|
|
}
|
|
|
|
void Instruction::swapProfMetadata() {
|
|
MDNode *ProfileData = getBranchWeightMDNode(*this);
|
|
if (!ProfileData)
|
|
return;
|
|
unsigned FirstIdx = getBranchWeightOffset(ProfileData);
|
|
if (ProfileData->getNumOperands() != 2 + FirstIdx)
|
|
return;
|
|
|
|
unsigned SecondIdx = FirstIdx + 1;
|
|
SmallVector<Metadata *, 4> Ops;
|
|
// If there are more weights past the second, we can't swap them
|
|
if (ProfileData->getNumOperands() > SecondIdx + 1)
|
|
return;
|
|
for (unsigned Idx = 0; Idx < FirstIdx; ++Idx) {
|
|
Ops.push_back(ProfileData->getOperand(Idx));
|
|
}
|
|
// Switch the order of the weights
|
|
Ops.push_back(ProfileData->getOperand(SecondIdx));
|
|
Ops.push_back(ProfileData->getOperand(FirstIdx));
|
|
setMetadata(LLVMContext::MD_prof,
|
|
MDNode::get(ProfileData->getContext(), Ops));
|
|
}
|
|
|
|
void Instruction::copyMetadata(const Instruction &SrcInst,
|
|
ArrayRef<unsigned> WL) {
|
|
if (!SrcInst.hasMetadata())
|
|
return;
|
|
|
|
SmallDenseSet<unsigned, 4> WLS(WL.begin(), WL.end());
|
|
|
|
// Otherwise, enumerate and copy over metadata from the old instruction to the
|
|
// new one.
|
|
SmallVector<std::pair<unsigned, MDNode *>, 4> TheMDs;
|
|
SrcInst.getAllMetadataOtherThanDebugLoc(TheMDs);
|
|
for (const auto &MD : TheMDs) {
|
|
if (WL.empty() || WLS.count(MD.first))
|
|
setMetadata(MD.first, MD.second);
|
|
}
|
|
if (WL.empty() || WLS.count(LLVMContext::MD_dbg))
|
|
setDebugLoc(SrcInst.getDebugLoc());
|
|
}
|
|
|
|
Instruction *Instruction::clone() const {
|
|
Instruction *New = nullptr;
|
|
switch (getOpcode()) {
|
|
default:
|
|
llvm_unreachable("Unhandled Opcode.");
|
|
#define HANDLE_INST(num, opc, clas) \
|
|
case Instruction::opc: \
|
|
New = cast<clas>(this)->cloneImpl(); \
|
|
break;
|
|
#include "llvm/IR/Instruction.def"
|
|
#undef HANDLE_INST
|
|
}
|
|
|
|
New->SubclassOptionalData = SubclassOptionalData;
|
|
New->copyMetadata(*this);
|
|
return New;
|
|
}
|