[OperandBundles] Treat "deopt" operand bundles specially
[oota-llvm.git] / include / llvm / IR / InstrTypes.h
index f0035ca3d4270e24e524beb8c3bb642af1d6b0e0..81de6999cdb180849d7b677c4f8dc756956ab10c 100644 (file)
@@ -21,6 +21,7 @@
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/OperandTraits.h"
 
 namespace llvm {
@@ -1126,6 +1127,9 @@ struct OperandBundleUse {
   /// Currently there is no way to have attributes on operand bundles differ on
   /// a per operand granularity.
   bool operandsHaveAttr(Attribute::AttrKind A) const {
+    if (isDeoptOperandBundle())
+      return A == Attribute::ReadOnly || A == Attribute::NoCapture;
+
     // Conservative answer:  no operands have any attributes.
     return false;
   };
@@ -1144,6 +1148,11 @@ struct OperandBundleUse {
     return Tag->getValue();
   }
 
+  /// \brief Return true if this is a "deopt" operand bundle.
+  bool isDeoptOperandBundle() const {
+    return getTagID() == LLVMContext::OB_deopt;
+  }
+
 private:
   /// \brief Pointer to an entry in LLVMContextImpl::getOrInsertBundleTag.
   StringMapEntry<uint32_t> *Tag;
@@ -1155,21 +1164,30 @@ private:
 /// 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)
-      : Tag(Tag), Inputs(Inputs) {}
+public:
+  explicit OperandBundleDefT(StringRef Tag, std::vector<InputTy> Inputs)
+      : Tag(Tag), Inputs(std::move(Inputs)) {}
 
-  explicit OperandBundleDefT(StringRef Tag, std::vector<InputTy> &&Inputs)
-      : Tag(Tag), Inputs(Inputs) {}
+  explicit OperandBundleDefT(std::string Tag, std::vector<InputTy> Inputs)
+      : Tag(std::move(Tag)), Inputs(std::move(Inputs)) {}
 
   explicit OperandBundleDefT(const OperandBundleUse &OBU) {
     Tag = OBU.getTagName();
     Inputs.insert(Inputs.end(), OBU.Inputs.begin(), OBU.Inputs.end());
   }
+
+  ArrayRef<InputTy> inputs() 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;
@@ -1316,6 +1334,18 @@ public:
     return None;
   }
 
+  /// \brief Return the list of operand bundles attached to this instruction as
+  /// a vector of OperandBundleDefs.
+  ///
+  /// This function copies the OperandBundeUse instances associated with this
+  /// OperandBundleUser to a vector of OperandBundleDefs.  Note:
+  /// OperandBundeUses and OperandBundleDefs are non-trivially *different*
+  /// representations of operand bundles (see documentation above).
+  void getOperandBundlesAsDefs(SmallVectorImpl<OperandBundleDef> &Defs) const {
+    for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i)
+      Defs.emplace_back(getOperandBundleAt(i));
+  }
+
   /// \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
@@ -1340,10 +1370,16 @@ public:
   /// \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();
+    for (auto &BOI : bundle_op_infos()) {
+      if (BOI.Tag->second == LLVMContext::OB_deopt)
+        continue;
+
+      // This instruction has an operand bundle that is not a "deopt" operand
+      // bundle.  Assume the worst.
+      return true;
+    }
+
+    return false;
   }
 
 protected:
@@ -1461,7 +1497,7 @@ protected:
                                           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();
@@ -1470,9 +1506,9 @@ protected:
     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++;
     }
@@ -1486,7 +1522,7 @@ protected:
   static unsigned CountBundleInputs(ArrayRef<OperandBundleDef> Bundles) {
     unsigned Total = 0;
     for (auto &B : Bundles)
-      Total += B.Inputs.size();
+      Total += B.input_size();
     return Total;
   }
 };