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