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
//===-- llvm/OperandTraits.h - OperandTraits class definition ---*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the traits classes that are handy for enforcing the correct
// layout of various User subclasses. It also provides the means for accessing
// the operands in the most efficient manner.
//

#ifndef LLVM_IR_OPERANDTRAITS_H
#define LLVM_IR_OPERANDTRAITS_H

#include "llvm/IR/User.h"

namespace llvm {

//===----------------------------------------------------------------------===//
//                          FixedNumOperand Trait Class
//===----------------------------------------------------------------------===//

/// FixedNumOperandTraits - determine the allocation regime of the Use array
/// when it is a prefix to the User object, and the number of Use objects is
/// known at compile time.

template <typename SubClass, unsigned ARITY>
struct FixedNumOperandTraits {
  static Use *op_begin(SubClass* U) {
    static_assert(
        !std::is_polymorphic<SubClass>::value,
        "adding virtual methods to subclasses of User breaks use lists");
    return reinterpret_cast<Use*>(U) - ARITY;
  }
  static Use *op_end(SubClass* U) {
    return reinterpret_cast<Use*>(U);
  }
  static unsigned operands(const User*) {
    return ARITY;
  }
};

//===----------------------------------------------------------------------===//
//                          OptionalOperand Trait Class
//===----------------------------------------------------------------------===//

/// OptionalOperandTraits - when the number of operands may change at runtime.
/// Naturally it may only decrease, because the allocations may not change.

template <typename SubClass, unsigned ARITY = 1>
struct OptionalOperandTraits : public FixedNumOperandTraits<SubClass, ARITY> {
  static unsigned operands(const User *U) {
    return U->getNumOperands();
  }
};

//===----------------------------------------------------------------------===//
//                          VariadicOperand Trait Class
//===----------------------------------------------------------------------===//

/// VariadicOperandTraits - determine the allocation regime of the Use array
/// when it is a prefix to the User object, and the number of Use objects is
/// only known at allocation time.

template <typename SubClass, unsigned MINARITY = 0>
struct VariadicOperandTraits {
  static Use *op_begin(SubClass* U) {
    static_assert(
        !std::is_polymorphic<SubClass>::value,
        "adding virtual methods to subclasses of User breaks use lists");
    return reinterpret_cast<Use*>(U) - static_cast<User*>(U)->getNumOperands();
  }
  static Use *op_end(SubClass* U) {
    return reinterpret_cast<Use*>(U);
  }
  static unsigned operands(const User *U) {
    return U->getNumOperands();
  }
};

//===----------------------------------------------------------------------===//
//                          HungoffOperand Trait Class
//===----------------------------------------------------------------------===//

/// HungoffOperandTraits - determine the allocation regime of the Use array
/// when it is not a prefix to the User object, but allocated at an unrelated
/// heap address.
///
/// This is the traits class that is needed when the Use array must be
/// resizable.

template <unsigned MINARITY = 1>
struct HungoffOperandTraits {
  static Use *op_begin(User* U) {
    return U->getOperandList();
  }
  static Use *op_end(User* U) {
    return U->getOperandList() + U->getNumOperands();
  }
  static unsigned operands(const User *U) {
    return U->getNumOperands();
  }
};

/// Macro for generating in-class operand accessor declarations.
/// It should only be called in the public section of the interface.
///
#define DECLARE_TRANSPARENT_OPERAND_ACCESSORS(VALUECLASS) \
  public: \
  inline VALUECLASS *getOperand(unsigned) const; \
  inline void setOperand(unsigned, VALUECLASS*); \
  inline op_iterator op_begin(); \
  inline const_op_iterator op_begin() const; \
  inline op_iterator op_end(); \
  inline const_op_iterator op_end() const; \
  protected: \
  template <int> inline Use &Op(); \
  template <int> inline const Use &Op() const; \
  public: \
  inline unsigned getNumOperands() const

/// Macro for generating out-of-class operand accessor definitions
#define DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CLASS, VALUECLASS) \
CLASS::op_iterator CLASS::op_begin() { \
  return OperandTraits<CLASS>::op_begin(this); \
} \
CLASS::const_op_iterator CLASS::op_begin() const { \
  return OperandTraits<CLASS>::op_begin(const_cast<CLASS*>(this)); \
} \
CLASS::op_iterator CLASS::op_end() { \
  return OperandTraits<CLASS>::op_end(this); \
} \
CLASS::const_op_iterator CLASS::op_end() const { \
  return OperandTraits<CLASS>::op_end(const_cast<CLASS*>(this)); \
} \
VALUECLASS *CLASS::getOperand(unsigned i_nocapture) const { \
  assert(i_nocapture < OperandTraits<CLASS>::operands(this) \
         && "getOperand() out of range!"); \
  return cast_or_null<VALUECLASS>( \
    OperandTraits<CLASS>::op_begin(const_cast<CLASS*>(this))[i_nocapture].get()); \
} \
void CLASS::setOperand(unsigned i_nocapture, VALUECLASS *Val_nocapture) { \
  assert(i_nocapture < OperandTraits<CLASS>::operands(this) \
         && "setOperand() out of range!"); \
  OperandTraits<CLASS>::op_begin(this)[i_nocapture] = Val_nocapture; \
} \
unsigned CLASS::getNumOperands() const { \
  return OperandTraits<CLASS>::operands(this); \
} \
template <int Idx_nocapture> Use &CLASS::Op() { \
  return this->OpFrom<Idx_nocapture>(this); \
} \
template <int Idx_nocapture> const Use &CLASS::Op() const { \
  return this->OpFrom<Idx_nocapture>(this); \
}


} // End llvm namespace

#endif