1//===- TypeSize.h - Wrapper around type sizes -------------------*- 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// This file provides a struct that can be used to query the size of IR types 10// which may be scalable vectors. It provides convenience operators so that 11// it can be used in much the same way as a single scalar value. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_SUPPORT_TYPESIZE_H 16#define LLVM_SUPPORT_TYPESIZE_H 17 18#include <cassert> 19#include <tuple> 20 21namespace llvm { 22 23class ElementCount { 24public: 25 unsigned Min; // Minimum number of vector elements. 26 bool Scalable; // If true, NumElements is a multiple of 'Min' determined 27 // at runtime rather than compile time. 28 29 ElementCount(unsigned Min, bool Scalable) 30 : Min(Min), Scalable(Scalable) {} 31 32 ElementCount operator*(unsigned RHS) { 33 return { Min * RHS, Scalable }; 34 } 35 ElementCount operator/(unsigned RHS) { 36 return { Min / RHS, Scalable }; 37 } 38 39 bool operator==(const ElementCount& RHS) const { 40 return Min == RHS.Min && Scalable == RHS.Scalable; 41 } 42 bool operator!=(const ElementCount& RHS) const { 43 return !(*this == RHS); 44 } 45}; 46 47// This class is used to represent the size of types. If the type is of fixed 48// size, it will represent the exact size. If the type is a scalable vector, 49// it will represent the known minimum size. 50class TypeSize { 51 uint64_t MinSize; // The known minimum size. 52 bool IsScalable; // If true, then the runtime size is an integer multiple 53 // of MinSize. 54 55public: 56 constexpr TypeSize(uint64_t MinSize, bool Scalable) 57 : MinSize(MinSize), IsScalable(Scalable) {} 58 59 static constexpr TypeSize Fixed(uint64_t Size) { 60 return TypeSize(Size, /*IsScalable=*/false); 61 } 62 63 static constexpr TypeSize Scalable(uint64_t MinSize) { 64 return TypeSize(MinSize, /*IsScalable=*/true); 65 } 66 67 // Scalable vector types with the same minimum size as a fixed size type are 68 // not guaranteed to be the same size at runtime, so they are never 69 // considered to be equal. 70 friend bool operator==(const TypeSize &LHS, const TypeSize &RHS) { 71 return std::tie(LHS.MinSize, LHS.IsScalable) == 72 std::tie(RHS.MinSize, RHS.IsScalable); 73 } 74 75 friend bool operator!=(const TypeSize &LHS, const TypeSize &RHS) { 76 return !(LHS == RHS); 77 } 78 79 // For many cases, size ordering between scalable and fixed size types cannot 80 // be determined at compile time, so such comparisons aren't allowed. 81 // 82 // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime 83 // vscale >= 5, equal sized with a vscale of 4, and smaller with 84 // a vscale <= 3. 85 // 86 // If the scalable flags match, just perform the requested comparison 87 // between the minimum sizes. 88 friend bool operator<(const TypeSize &LHS, const TypeSize &RHS) { 89 assert(LHS.IsScalable == RHS.IsScalable && 90 "Ordering comparison of scalable and fixed types"); 91 92 return LHS.MinSize < RHS.MinSize; 93 } 94 95 friend bool operator>(const TypeSize &LHS, const TypeSize &RHS) { 96 return RHS < LHS; 97 } 98 99 friend bool operator<=(const TypeSize &LHS, const TypeSize &RHS) { 100 return !(RHS < LHS); 101 } 102 103 friend bool operator>=(const TypeSize &LHS, const TypeSize& RHS) { 104 return !(LHS < RHS); 105 } 106 107 // Convenience operators to obtain relative sizes independently of 108 // the scalable flag. 109 TypeSize operator*(unsigned RHS) const { 110 return { MinSize * RHS, IsScalable }; 111 } 112 113 friend TypeSize operator*(const unsigned LHS, const TypeSize &RHS) { 114 return { LHS * RHS.MinSize, RHS.IsScalable }; 115 } 116 117 TypeSize operator/(unsigned RHS) const { 118 return { MinSize / RHS, IsScalable }; 119 } 120 121 // Return the minimum size with the assumption that the size is exact. 122 // Use in places where a scalable size doesn't make sense (e.g. non-vector 123 // types, or vectors in backends which don't support scalable vectors). 124 uint64_t getFixedSize() const { 125 assert(!IsScalable && "Request for a fixed size on a scalable object"); 126 return MinSize; 127 } 128 129 // Return the known minimum size. Use in places where the scalable property 130 // doesn't matter (e.g. determining alignment) or in conjunction with the 131 // isScalable method below. 132 uint64_t getKnownMinSize() const { 133 return MinSize; 134 } 135 136 // Return whether or not the size is scalable. 137 bool isScalable() const { 138 return IsScalable; 139 } 140 141 // Returns true if the number of bits is a multiple of an 8-bit byte. 142 bool isByteSized() const { 143 return (MinSize & 7) == 0; 144 } 145 146 // Casts to a uint64_t if this is a fixed-width size. 147 // 148 // NOTE: This interface is obsolete and will be removed in a future version 149 // of LLVM in favour of calling getFixedSize() directly. 150 operator uint64_t() const { 151 return getFixedSize(); 152 } 153 154 // Additional convenience operators needed to avoid ambiguous parses. 155 // TODO: Make uint64_t the default operator? 156 TypeSize operator*(uint64_t RHS) const { 157 return { MinSize * RHS, IsScalable }; 158 } 159 160 TypeSize operator*(int RHS) const { 161 return { MinSize * RHS, IsScalable }; 162 } 163 164 TypeSize operator*(int64_t RHS) const { 165 return { MinSize * RHS, IsScalable }; 166 } 167 168 friend TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) { 169 return { LHS * RHS.MinSize, RHS.IsScalable }; 170 } 171 172 friend TypeSize operator*(const int LHS, const TypeSize &RHS) { 173 return { LHS * RHS.MinSize, RHS.IsScalable }; 174 } 175 176 friend TypeSize operator*(const int64_t LHS, const TypeSize &RHS) { 177 return { LHS * RHS.MinSize, RHS.IsScalable }; 178 } 179 180 TypeSize operator/(uint64_t RHS) const { 181 return { MinSize / RHS, IsScalable }; 182 } 183 184 TypeSize operator/(int RHS) const { 185 return { MinSize / RHS, IsScalable }; 186 } 187 188 TypeSize operator/(int64_t RHS) const { 189 return { MinSize / RHS, IsScalable }; 190 } 191}; 192 193/// Returns a TypeSize with a known minimum size that is the next integer 194/// (mod 2**64) that is greater than or equal to \p Value and is a multiple 195/// of \p Align. \p Align must be non-zero. 196/// 197/// Similar to the alignTo functions in MathExtras.h 198inline TypeSize alignTo(TypeSize Size, uint64_t Align) { 199 assert(Align != 0u && "Align must be non-zero"); 200 return {(Size.getKnownMinSize() + Align - 1) / Align * Align, 201 Size.isScalable()}; 202} 203 204} // end namespace llvm 205 206#endif // LLVM_SUPPORT_TypeSize_H 207