reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
//===- llvm/IR/TrackingMDRef.h - Tracking Metadata references ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// References to metadata that track RAUW.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_IR_TRACKINGMDREF_H
#define LLVM_IR_TRACKINGMDREF_H

#include "llvm/IR/Metadata.h"
#include <algorithm>
#include <cassert>

namespace llvm {

/// Tracking metadata reference.
///
/// This class behaves like \a TrackingVH, but for metadata.
class TrackingMDRef {
  Metadata *MD = nullptr;

public:
  TrackingMDRef() = default;
  explicit TrackingMDRef(Metadata *MD) : MD(MD) { track(); }

  TrackingMDRef(TrackingMDRef &&X) : MD(X.MD) { retrack(X); }
  TrackingMDRef(const TrackingMDRef &X) : MD(X.MD) { track(); }

  TrackingMDRef &operator=(TrackingMDRef &&X) {
    if (&X == this)
      return *this;

    untrack();
    MD = X.MD;
    retrack(X);
    return *this;
  }

  TrackingMDRef &operator=(const TrackingMDRef &X) {
    if (&X == this)
      return *this;

    untrack();
    MD = X.MD;
    track();
    return *this;
  }

  ~TrackingMDRef() { untrack(); }

  Metadata *get() const { return MD; }
  operator Metadata *() const { return get(); }
  Metadata *operator->() const { return get(); }
  Metadata &operator*() const { return *get(); }

  void reset() {
    untrack();
    MD = nullptr;
  }
  void reset(Metadata *MD) {
    untrack();
    this->MD = MD;
    track();
  }

  /// Check whether this has a trivial destructor.
  ///
  /// If \c MD isn't replaceable, the destructor will be a no-op.
  bool hasTrivialDestructor() const {
    return !MD || !MetadataTracking::isReplaceable(*MD);
  }

  bool operator==(const TrackingMDRef &X) const { return MD == X.MD; }
  bool operator!=(const TrackingMDRef &X) const { return MD != X.MD; }

private:
  void track() {
    if (MD)
      MetadataTracking::track(MD);
  }

  void untrack() {
    if (MD)
      MetadataTracking::untrack(MD);
  }

  void retrack(TrackingMDRef &X) {
    assert(MD == X.MD && "Expected values to match");
    if (X.MD) {
      MetadataTracking::retrack(X.MD, MD);
      X.MD = nullptr;
    }
  }
};

/// Typed tracking ref.
///
/// Track refererences of a particular type.  It's useful to use this for \a
/// MDNode and \a ValueAsMetadata.
template <class T> class TypedTrackingMDRef {
  TrackingMDRef Ref;

public:
  TypedTrackingMDRef() = default;
  explicit TypedTrackingMDRef(T *MD) : Ref(static_cast<Metadata *>(MD)) {}

  TypedTrackingMDRef(TypedTrackingMDRef &&X) : Ref(std::move(X.Ref)) {}
  TypedTrackingMDRef(const TypedTrackingMDRef &X) : Ref(X.Ref) {}

  TypedTrackingMDRef &operator=(TypedTrackingMDRef &&X) {
    Ref = std::move(X.Ref);
    return *this;
  }

  TypedTrackingMDRef &operator=(const TypedTrackingMDRef &X) {
    Ref = X.Ref;
    return *this;
  }

  T *get() const { return (T *)Ref.get(); }
  operator T *() const { return get(); }
  T *operator->() const { return get(); }
  T &operator*() const { return *get(); }

  bool operator==(const TypedTrackingMDRef &X) const { return Ref == X.Ref; }
  bool operator!=(const TypedTrackingMDRef &X) const { return Ref != X.Ref; }

  void reset() { Ref.reset(); }
  void reset(T *MD) { Ref.reset(static_cast<Metadata *>(MD)); }

  /// Check whether this has a trivial destructor.
  bool hasTrivialDestructor() const { return Ref.hasTrivialDestructor(); }
};

using TrackingMDNodeRef = TypedTrackingMDRef<MDNode>;
using TrackingValueAsMetadataRef = TypedTrackingMDRef<ValueAsMetadata>;

// Expose the underlying metadata to casting.
template <> struct simplify_type<TrackingMDRef> {
  using SimpleType = Metadata *;

  static SimpleType getSimplifiedValue(TrackingMDRef &MD) { return MD.get(); }
};

template <> struct simplify_type<const TrackingMDRef> {
  using SimpleType = Metadata *;

  static SimpleType getSimplifiedValue(const TrackingMDRef &MD) {
    return MD.get();
  }
};

template <class T> struct simplify_type<TypedTrackingMDRef<T>> {
  using SimpleType = T *;

  static SimpleType getSimplifiedValue(TypedTrackingMDRef<T> &MD) {
    return MD.get();
  }
};

template <class T> struct simplify_type<const TypedTrackingMDRef<T>> {
  using SimpleType = T *;

  static SimpleType getSimplifiedValue(const TypedTrackingMDRef<T> &MD) {
    return MD.get();
  }
};

} // end namespace llvm

#endif // LLVM_IR_TRACKINGMDREF_H