1//===- llvm/IR/TrackingMDRef.h - Tracking Metadata references ---*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// References to metadata that track RAUW.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_IR_TRACKINGMDREF_H
15#define LLVM_IR_TRACKINGMDREF_H
16
17#include "llvm/IR/Metadata.h"
18
19namespace llvm {
20
21/// \brief Tracking metadata reference.
22///
23/// This class behaves like \a TrackingVH, but for metadata.
24class TrackingMDRef {
25  Metadata *MD;
26
27public:
28  TrackingMDRef() : MD(nullptr) {}
29  explicit TrackingMDRef(Metadata *MD) : MD(MD) { track(); }
30
31  TrackingMDRef(TrackingMDRef &&X) : MD(X.MD) { retrack(X); }
32  TrackingMDRef(const TrackingMDRef &X) : MD(X.MD) { track(); }
33  TrackingMDRef &operator=(TrackingMDRef &&X) {
34    if (&X == this)
35      return *this;
36
37    untrack();
38    MD = X.MD;
39    retrack(X);
40    return *this;
41  }
42  TrackingMDRef &operator=(const TrackingMDRef &X) {
43    if (&X == this)
44      return *this;
45
46    untrack();
47    MD = X.MD;
48    track();
49    return *this;
50  }
51  ~TrackingMDRef() { untrack(); }
52
53  Metadata *get() const { return MD; }
54  operator Metadata *() const { return get(); }
55  Metadata *operator->() const { return get(); }
56  Metadata &operator*() const { return *get(); }
57
58  void reset() {
59    untrack();
60    MD = nullptr;
61  }
62  void reset(Metadata *MD) {
63    untrack();
64    this->MD = MD;
65    track();
66  }
67
68  /// \brief Check whether this has a trivial destructor.
69  ///
70  /// If \c MD isn't replaceable, the destructor will be a no-op.
71  bool hasTrivialDestructor() const {
72    return !MD || !MetadataTracking::isReplaceable(*MD);
73  }
74
75  bool operator==(const TrackingMDRef &X) const { return MD == X.MD; }
76  bool operator!=(const TrackingMDRef &X) const { return MD != X.MD; }
77
78private:
79  void track() {
80    if (MD)
81      MetadataTracking::track(MD);
82  }
83  void untrack() {
84    if (MD)
85      MetadataTracking::untrack(MD);
86  }
87  void retrack(TrackingMDRef &X) {
88    assert(MD == X.MD && "Expected values to match");
89    if (X.MD) {
90      MetadataTracking::retrack(X.MD, MD);
91      X.MD = nullptr;
92    }
93  }
94};
95
96/// \brief Typed tracking ref.
97///
98/// Track refererences of a particular type.  It's useful to use this for \a
99/// MDNode and \a ValueAsMetadata.
100template <class T> class TypedTrackingMDRef {
101  TrackingMDRef Ref;
102
103public:
104  TypedTrackingMDRef() {}
105  explicit TypedTrackingMDRef(T *MD) : Ref(static_cast<Metadata *>(MD)) {}
106
107  TypedTrackingMDRef(TypedTrackingMDRef &&X) : Ref(std::move(X.Ref)) {}
108  TypedTrackingMDRef(const TypedTrackingMDRef &X) : Ref(X.Ref) {}
109  TypedTrackingMDRef &operator=(TypedTrackingMDRef &&X) {
110    Ref = std::move(X.Ref);
111    return *this;
112  }
113  TypedTrackingMDRef &operator=(const TypedTrackingMDRef &X) {
114    Ref = X.Ref;
115    return *this;
116  }
117
118  T *get() const { return (T *)Ref.get(); }
119  operator T *() const { return get(); }
120  T *operator->() const { return get(); }
121  T &operator*() const { return *get(); }
122
123  bool operator==(const TypedTrackingMDRef &X) const { return Ref == X.Ref; }
124  bool operator!=(const TypedTrackingMDRef &X) const { return Ref != X.Ref; }
125
126  void reset() { Ref.reset(); }
127  void reset(T *MD) { Ref.reset(static_cast<Metadata *>(MD)); }
128
129  /// \brief Check whether this has a trivial destructor.
130  bool hasTrivialDestructor() const { return Ref.hasTrivialDestructor(); }
131};
132
133typedef TypedTrackingMDRef<MDNode> TrackingMDNodeRef;
134typedef TypedTrackingMDRef<ValueAsMetadata> TrackingValueAsMetadataRef;
135
136// Expose the underlying metadata to casting.
137template <> struct simplify_type<TrackingMDRef> {
138  typedef Metadata *SimpleType;
139  static SimpleType getSimplifiedValue(TrackingMDRef &MD) { return MD.get(); }
140};
141
142template <> struct simplify_type<const TrackingMDRef> {
143  typedef Metadata *SimpleType;
144  static SimpleType getSimplifiedValue(const TrackingMDRef &MD) {
145    return MD.get();
146  }
147};
148
149template <class T> struct simplify_type<TypedTrackingMDRef<T>> {
150  typedef T *SimpleType;
151  static SimpleType getSimplifiedValue(TypedTrackingMDRef<T> &MD) {
152    return MD.get();
153  }
154};
155
156template <class T> struct simplify_type<const TypedTrackingMDRef<T>> {
157  typedef T *SimpleType;
158  static SimpleType getSimplifiedValue(const TypedTrackingMDRef<T> &MD) {
159    return MD.get();
160  }
161};
162
163} // end namespace llvm
164
165#endif
166