blob: 7ea651f0f22cf55407ba3348a818c4d2a02f11f7 [file] [log] [blame]
//===- 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;
}
// Returns true if the number of bits is a multiple of an 8-bit byte.
bool isByteSized() const {
return (MinSize & 7) == 0;
}
// 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