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