#ifndef LLVM_IR_INSTRTYPES_H
#define LLVM_IR_INSTRTYPES_H
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/IR/Attributes.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/OperandTraits.h"
return isUnsigned(getPredicate());
}
+ /// For example, ULT->SLT, ULE->SLE, UGT->SGT, UGE->SGE, SLT->Failed assert
+ /// @returns the signed version of the unsigned predicate pred.
+ /// @brief return the signed version of a predicate
+ static Predicate getSignedPredicate(Predicate pred);
+
+ /// For example, ULT->SLT, ULE->SLE, UGT->SGT, UGE->SGE, SLT->Failed assert
+ /// @returns the signed version of the predicate for this instruction (which
+ /// has to be an unsigned predicate).
+ /// @brief return the signed version of a predicate
+ Predicate getSignedPredicate() {
+ return getSignedPredicate(getPredicate());
+ }
+
/// This is just a convenience.
/// @brief Determine if this is true when both operands are the same.
bool isTrueWhenEqual() const {
/// \brief A lightweight accessor for an operand bundle meant to be passed
/// around by value.
struct OperandBundleUse {
- StringRef Tag;
ArrayRef<Use> Inputs;
OperandBundleUse() {}
- explicit OperandBundleUse(StringRef Tag, ArrayRef<Use> Inputs)
- : Tag(Tag), Inputs(Inputs) {}
+ explicit OperandBundleUse(StringMapEntry<uint32_t> *Tag, ArrayRef<Use> Inputs)
+ : Inputs(Inputs), Tag(Tag) {}
+
+ /// \brief Return true if all the operands in this operand bundle have the
+ /// attribute A.
+ ///
+ /// Currently there is no way to have attributes on operand bundles differ on
+ /// a per operand granularity.
+ bool operandsHaveAttr(Attribute::AttrKind A) const {
+ // Conservative answer: no operands have any attributes.
+ return false;
+ };
+
+ /// \brief Return the tag of this operand bundle as a string.
+ StringRef getTagName() const {
+ return Tag->getKey();
+ }
+
+ /// \brief Return the tag of this operand bundle as an integer.
+ ///
+ /// Operand bundle tags are interned by LLVMContextImpl::getOrInsertBundleTag,
+ /// and this function returns the unique integer getOrInsertBundleTag
+ /// associated the tag of this operand bundle to.
+ uint32_t getTagID() const {
+ return Tag->getValue();
+ }
+
+private:
+ /// \brief Pointer to an entry in LLVMContextImpl::getOrInsertBundleTag.
+ StringMapEntry<uint32_t> *Tag;
};
/// \brief A container for an operand bundle being viewed as a set of values
/// Unlike OperandBundleUse, OperandBundleDefT owns the memory it carries, and
/// so it is possible to create and pass around "self-contained" instances of
/// OperandBundleDef and ConstOperandBundleDef.
-template <typename InputTy> struct OperandBundleDefT {
+template <typename InputTy> class OperandBundleDefT {
std::string Tag;
std::vector<InputTy> Inputs;
- OperandBundleDefT() {}
- explicit OperandBundleDefT(StringRef Tag, const std::vector<InputTy> &Inputs)
+public:
+ explicit OperandBundleDefT(StringRef Tag, std::vector<InputTy> &&Inputs)
+ : Tag(Tag), Inputs(Inputs) {}
+
+ explicit OperandBundleDefT(std::string &&Tag, std::vector<InputTy> &&Inputs)
: Tag(Tag), Inputs(Inputs) {}
+
+ explicit OperandBundleDefT(const OperandBundleUse &OBU) {
+ Tag = OBU.getTagName();
+ Inputs.insert(Inputs.end(), OBU.Inputs.begin(), OBU.Inputs.end());
+ }
+
+ ArrayRef<InputTy> getInputs() const { return Inputs; }
+
+ typedef typename std::vector<InputTy>::const_iterator input_iterator;
+ size_t input_size() const { return Inputs.size(); }
+ input_iterator input_begin() const { return Inputs.begin(); }
+ input_iterator input_end() const { return Inputs.end(); }
+
+ StringRef getTag() const { return Tag; }
};
typedef OperandBundleDefT<Value *> OperandBundleDef;
/// \brief Return true if this User has any operand bundles.
bool hasOperandBundles() const { return getNumOperandBundles() != 0; }
+ /// \brief Return the index of the first bundle operand in the Use array.
+ unsigned getBundleOperandsStartIndex() const {
+ assert(hasOperandBundles() && "Don't call otherwise!");
+ return bundle_op_info_begin()->Begin;
+ }
+
+ /// \brief Return the index of the last bundle operand in the Use array.
+ unsigned getBundleOperandsEndIndex() const {
+ assert(hasOperandBundles() && "Don't call otherwise!");
+ return bundle_op_info_end()[-1].End;
+ }
+
/// \brief Return the total number operands (not operand bundles) used by
/// every operand bundle in this OperandBundleUser.
unsigned getNumTotalBundleOperands() const {
if (!hasOperandBundles())
return 0;
- auto *Begin = bundle_op_info_begin();
- auto *Back = bundle_op_info_end() - 1;
-
- assert(Begin <= Back && "hasOperandBundles() returned true!");
+ unsigned Begin = getBundleOperandsStartIndex();
+ unsigned End = getBundleOperandsEndIndex();
- return Back->End - Begin->Begin;
+ assert(Begin <= End && "Should be!");
+ return End - Begin;
}
/// \brief Return the operand bundle at a specific index.
- OperandBundleUse getOperandBundle(unsigned Index) const {
+ OperandBundleUse getOperandBundleAt(unsigned Index) const {
assert(Index < getNumOperandBundles() && "Index out of bounds!");
- auto *BOI = bundle_op_info_begin() + Index;
- auto op_begin = static_cast<const InstrTy *>(this)->op_begin();
- ArrayRef<Use> Inputs(op_begin + BOI->Begin, op_begin + BOI->End);
- return OperandBundleUse(BOI->Tag->getKey(), Inputs);
+ return operandBundleFromBundleOpInfo(*(bundle_op_info_begin() + Index));
+ }
+
+ /// \brief Return the number of operand bundles with the tag Name attached to
+ /// this instruction.
+ unsigned countOperandBundlesOfType(StringRef Name) const {
+ unsigned Count = 0;
+ for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i)
+ if (getOperandBundleAt(i).getTagName() == Name)
+ Count++;
+
+ return Count;
+ }
+
+ /// \brief Return the number of operand bundles with the tag ID attached to
+ /// this instruction.
+ unsigned countOperandBundlesOfType(uint32_t ID) const {
+ unsigned Count = 0;
+ for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i)
+ if (getOperandBundleAt(i).getTagID() == ID)
+ Count++;
+
+ return Count;
+ }
+
+ /// \brief Return an operand bundle by name, if present.
+ ///
+ /// It is an error to call this for operand bundle types that may have
+ /// multiple instances of them on the same instruction.
+ Optional<OperandBundleUse> getOperandBundle(StringRef Name) const {
+ assert(countOperandBundlesOfType(Name) < 2 && "Precondition violated!");
+
+ for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) {
+ OperandBundleUse U = getOperandBundleAt(i);
+ if (U.getTagName() == Name)
+ return U;
+ }
+
+ return None;
+ }
+
+ /// \brief Return an operand bundle by tag ID, if present.
+ ///
+ /// It is an error to call this for operand bundle types that may have
+ /// multiple instances of them on the same instruction.
+ Optional<OperandBundleUse> getOperandBundle(uint32_t ID) const {
+ assert(countOperandBundlesOfType(ID) < 2 && "Precondition violated!");
+
+ for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) {
+ OperandBundleUse U = getOperandBundleAt(i);
+ if (U.getTagID() == ID)
+ return U;
+ }
+
+ return None;
+ }
+
+ /// \brief Return the operand bundle for the operand at index OpIdx.
+ ///
+ /// It is an error to call this with an OpIdx that does not correspond to an
+ /// bundle operand.
+ OperandBundleUse getOperandBundleForOperand(unsigned OpIdx) const {
+ for (auto &BOI : bundle_op_infos())
+ if (BOI.Begin <= OpIdx && OpIdx < BOI.End)
+ return operandBundleFromBundleOpInfo(BOI);
+
+ llvm_unreachable("Did not find operand bundle for operand!");
+ }
+
+ /// \brief Return true if this operand bundle user has operand bundles that
+ /// may read from the heap.
+ bool hasReadingOperandBundles() const {
+ // Implementation note: this is a conservative implementation of operand
+ // bundle semantics, where *any* operand bundle forces a callsite to be at
+ // least readonly.
+ return hasOperandBundles();
+ }
+
+ /// \brief Return true if this operand bundle user has operand bundles that
+ /// may write to the heap.
+ bool hasClobberingOperandBundles() const {
+ // Implementation note: this is a conservative implementation of operand
+ // bundle semantics, where *any* operand bundle forces a callsite to be
+ // read-write.
+ return hasOperandBundles();
}
protected:
+ /// \brief Is the function attribute S disallowed by some operand bundle on
+ /// this operand bundle user?
+ bool isFnAttrDisallowedByOpBundle(StringRef S) const {
+ // Operand bundles only possibly disallow readnone, readonly and argmenonly
+ // attributes. All String attributes are fine.
+ return false;
+ }
+
+ /// \brief Is the function attribute A disallowed by some operand bundle on
+ /// this operand bundle user?
+ bool isFnAttrDisallowedByOpBundle(Attribute::AttrKind A) const {
+ switch (A) {
+ default:
+ return false;
+
+ case Attribute::ArgMemOnly:
+ return hasReadingOperandBundles();
+
+ case Attribute::ReadNone:
+ return hasReadingOperandBundles();
+
+ case Attribute::ReadOnly:
+ return hasClobberingOperandBundles();
+ }
+
+ llvm_unreachable("switch has a default case!");
+ }
+
/// \brief Used to keep track of an operand bundle. See the main comment on
/// OperandBundleUser above.
struct BundleOpInfo {
uint32_t End;
};
+ /// \brief Simple helper function to map a BundleOpInfo to an
+ /// OperandBundleUse.
+ OperandBundleUse
+ operandBundleFromBundleOpInfo(const BundleOpInfo &BOI) const {
+ auto op_begin = static_cast<const InstrTy *>(this)->op_begin();
+ ArrayRef<Use> Inputs(op_begin + BOI.Begin, op_begin + BOI.End);
+ return OperandBundleUse(BOI.Tag, Inputs);
+ }
+
typedef BundleOpInfo *bundle_op_iterator;
typedef const BundleOpInfo *const_bundle_op_iterator;
const unsigned BeginIndex) {
auto It = static_cast<InstrTy *>(this)->op_begin() + BeginIndex;
for (auto &B : Bundles)
- It = std::copy(B.Inputs.begin(), B.Inputs.end(), It);
+ It = std::copy(B.input_begin(), B.input_end(), It);
auto *ContextImpl = static_cast<InstrTy *>(this)->getContext().pImpl;
auto BI = Bundles.begin();
for (auto &BOI : bundle_op_infos()) {
assert(BI != Bundles.end() && "Incorrect allocation?");
- BOI.Tag = ContextImpl->getOrInsertBundleTag(BI->Tag);
+ BOI.Tag = ContextImpl->getOrInsertBundleTag(BI->getTag());
BOI.Begin = CurrentIndex;
- BOI.End = CurrentIndex + BI->Inputs.size();
+ BOI.End = CurrentIndex + BI->input_size();
CurrentIndex = BOI.End;
BI++;
}
static unsigned CountBundleInputs(ArrayRef<OperandBundleDef> Bundles) {
unsigned Total = 0;
for (auto &B : Bundles)
- Total += B.Inputs.size();
+ Total += B.input_size();
return Total;
}
};