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
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
//===- TypeSize.h - Wrapper around type sizes -------------------*- 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 provides a struct that can be used to query the size of IR types
// which may be scalable vectors. It provides convenience operators so that
// it can be used in much the same way as a single scalar value.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_TYPESIZE_H
#define LLVM_SUPPORT_TYPESIZE_H

#include <cassert>
#include <tuple>

namespace llvm {

class ElementCount {
public:
  unsigned Min;  // Minimum number of vector elements.
  bool Scalable; // If true, NumElements is a multiple of 'Min' determined
                 // at runtime rather than compile time.

  ElementCount(unsigned Min, bool Scalable)
  : Min(Min), Scalable(Scalable) {}

  ElementCount operator*(unsigned RHS) {
    return { Min * RHS, Scalable };
  }
  ElementCount operator/(unsigned RHS) {
    return { Min / RHS, Scalable };
  }

  bool operator==(const ElementCount& RHS) const {
    return Min == RHS.Min && Scalable == RHS.Scalable;
  }
  bool operator!=(const ElementCount& RHS) const {
    return !(*this == RHS);
  }
};

// This class is used to represent the size of types. If the type is of fixed
// size, it will represent the exact size. If the type is a scalable vector,
// it will represent the known minimum size.
class TypeSize {
  uint64_t MinSize;   // The known minimum size.
  bool IsScalable;    // If true, then the runtime size is an integer multiple
                      // of MinSize.

public:
  constexpr TypeSize(uint64_t MinSize, bool Scalable)
    : MinSize(MinSize), IsScalable(Scalable) {}

  static constexpr TypeSize Fixed(uint64_t Size) {
    return TypeSize(Size, /*IsScalable=*/false);
  }

  static constexpr TypeSize Scalable(uint64_t MinSize) {
    return TypeSize(MinSize, /*IsScalable=*/true);
  }

  // Scalable vector types with the same minimum size as a fixed size type are
  // not guaranteed to be the same size at runtime, so they are never
  // considered to be equal.
  friend bool operator==(const TypeSize &LHS, const TypeSize &RHS) {
    return std::tie(LHS.MinSize, LHS.IsScalable) ==
           std::tie(RHS.MinSize, RHS.IsScalable);
  }

  friend bool operator!=(const TypeSize &LHS, const TypeSize &RHS) {
    return !(LHS == RHS);
  }

  // For many cases, size ordering between scalable and fixed size types cannot
  // be determined at compile time, so such comparisons aren't allowed.
  //
  // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime
  // vscale >= 5, equal sized with a vscale of 4, and smaller with
  // a vscale <= 3.
  //
  // If the scalable flags match, just perform the requested comparison
  // between the minimum sizes.
  friend bool operator<(const TypeSize &LHS, const TypeSize &RHS) {
    assert(LHS.IsScalable == RHS.IsScalable &&
           "Ordering comparison of scalable and fixed types");

    return LHS.MinSize < RHS.MinSize;
  }

  friend bool operator>(const TypeSize &LHS, const TypeSize &RHS) {
    return RHS < LHS;
  }

  friend bool operator<=(const TypeSize &LHS, const TypeSize &RHS) {
    return !(RHS < LHS);
  }

  friend bool operator>=(const TypeSize &LHS, const TypeSize& RHS) {
    return !(LHS < RHS);
  }

  // Convenience operators to obtain relative sizes independently of
  // the scalable flag.
  TypeSize operator*(unsigned RHS) const {
    return { MinSize * RHS, IsScalable };
  }

  friend TypeSize operator*(const unsigned LHS, const TypeSize &RHS) {
    return { LHS * RHS.MinSize, RHS.IsScalable };
  }

  TypeSize operator/(unsigned RHS) const {
    return { MinSize / RHS, IsScalable };
  }

  // Return the minimum size with the assumption that the size is exact.
  // Use in places where a scalable size doesn't make sense (e.g. non-vector
  // types, or vectors in backends which don't support scalable vectors).
  uint64_t getFixedSize() const {
    assert(!IsScalable && "Request for a fixed size on a scalable object");
    return MinSize;
  }

  // Return the known minimum size. Use in places where the scalable property
  // doesn't matter (e.g. determining alignment) or in conjunction with the
  // isScalable method below.
  uint64_t getKnownMinSize() const {
    return MinSize;
  }

  // Return whether or not the size is scalable.
  bool isScalable() const {
    return IsScalable;
  }

  // Casts to a uint64_t if this is a fixed-width size.
  //
  // NOTE: This interface is obsolete and will be removed in a future version
  // of LLVM in favour of calling getFixedSize() directly.
  operator uint64_t() const {
    return getFixedSize();
  }

  // Additional convenience operators needed to avoid ambiguous parses.
  // TODO: Make uint64_t the default operator?
  TypeSize operator*(uint64_t RHS) const {
    return { MinSize * RHS, IsScalable };
  }

  TypeSize operator*(int RHS) const {
    return { MinSize * RHS, IsScalable };
  }

  TypeSize operator*(int64_t RHS) const {
    return { MinSize * RHS, IsScalable };
  }

  friend TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) {
    return { LHS * RHS.MinSize, RHS.IsScalable };
  }

  friend TypeSize operator*(const int LHS, const TypeSize &RHS) {
    return { LHS * RHS.MinSize, RHS.IsScalable };
  }

  friend TypeSize operator*(const int64_t LHS, const TypeSize &RHS) {
    return { LHS * RHS.MinSize, RHS.IsScalable };
  }

  TypeSize operator/(uint64_t RHS) const {
    return { MinSize / RHS, IsScalable };
  }

  TypeSize operator/(int RHS) const {
    return { MinSize / RHS, IsScalable };
  }

  TypeSize operator/(int64_t RHS) const {
    return { MinSize / RHS, IsScalable };
  }
};

/// Returns a TypeSize with a known minimum size that is the next integer
/// (mod 2**64) that is greater than or equal to \p Value and is a multiple
/// of \p Align. \p Align must be non-zero.
///
/// Similar to the alignTo functions in MathExtras.h
inline TypeSize alignTo(TypeSize Size, uint64_t Align) {
  assert(Align != 0u && "Align must be non-zero");
  return {(Size.getKnownMinSize() + Align - 1) / Align * Align,
          Size.isScalable()};
}

} // end namespace llvm

#endif // LLVM_SUPPORT_TypeSize_H