Skip to content

Conversation

@tgymnich
Copy link
Member

@tgymnich tgymnich commented Mar 10, 2025

  • adds new floating point and integer LLT kinds for both scalars and vectors.

makes progress on #119667

@tgymnich tgymnich requested a review from arsenm March 10, 2025 18:21
@tgymnich tgymnich marked this pull request as ready for review March 11, 2025 11:56
@llvmbot
Copy link
Member

llvmbot commented Mar 11, 2025

@llvm/pr-subscribers-tablegen

Author: Tim Gymnich (tgymnich)

Changes
  • adds new floating point and integer LLT kinds for both scalars and vectors.

Patch is 63.32 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/130651.diff

41 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/LowLevelTypeUtils.h (+1-1)
  • (modified) llvm/include/llvm/CodeGenTypes/LowLevelType.h (+270-94)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizeMutations.cpp (+2-4)
  • (modified) llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp (+2-1)
  • (modified) llvm/lib/CodeGen/LowLevelTypeUtils.cpp (+61-13)
  • (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+71-31)
  • (modified) llvm/lib/CodeGenTypes/LowLevelType.cpp (+47-13)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid0.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid1.mir (+1-1)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid11.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid12.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid13.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid14.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid15.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid16.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid17.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid18.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid19.mir (+10)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid2.mir (+1-1)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid20.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid21.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid22.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid23.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid24.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid25.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid26.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid27.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid28.mir (+10)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid3.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid5.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid6.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid7.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid8.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err10.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err8.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err9.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid0.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir (+2-2)
  • (modified) llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp (+8-6)
  • (modified) llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp (+66-39)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index 9472aa196f9b4..f8819d9efd833 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -374,7 +374,7 @@ LegalizeMutation changeElementCountTo(unsigned TypeIdx, unsigned FromTypeIdx);
 
 /// Keep the same scalar or element type as \p TypeIdx, but take the number of
 /// elements from \p Ty.
-LegalizeMutation changeElementCountTo(unsigned TypeIdx, LLT Ty);
+LegalizeMutation changeElementCountTo(unsigned TypeIdx, ElementCount EC);
 
 /// Change the scalar size or element size to have the same scalar size as type
 /// index \p FromIndex. Unlike changeElementTo, this discards pointer types and
diff --git a/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h b/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
index 142e5cd4e7ad1..e9288ce8fdf51 100644
--- a/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
+++ b/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
@@ -40,6 +40,6 @@ LLT getLLTForMVT(MVT Ty);
 /// Get the appropriate floating point arithmetic semantic based on the bit size
 /// of the given scalar LLT.
 const llvm::fltSemantics &getFltSemanticForLLT(LLT Ty);
-}
+} // namespace llvm
 
 #endif // LLVM_CODEGEN_LOWLEVELTYPEUTILS_H
diff --git a/llvm/include/llvm/CodeGenTypes/LowLevelType.h b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
index 06879e1f8d15b..27692b2c9f1b3 100644
--- a/llvm/include/llvm/CodeGenTypes/LowLevelType.h
+++ b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
@@ -29,6 +29,7 @@
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/CodeGenTypes/MachineValueType.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <cassert>
 
 namespace llvm {
@@ -38,68 +39,159 @@ class raw_ostream;
 
 class LLT {
 public:
+  enum class FPVariant {
+    IEEE_FLOAT = 0x0,
+    BRAIN_FLOAT = 0x1,     // BRAIN_FLOAT
+    VARIANT_FLOAT_2 = 0x2, // PPC_FLOAT
+    VARIANT_FLOAT_3 = 0x3, // FP80
+    VARIANT_FLOAT_4 = 0x4, // TENSOR_FLOAT
+    VARIANT_FLOAT_5 = 0x5, // UNASSIGNED
+    VARIANT_FLOAT_6 = 0x6, // UNASSIGNED
+    VARIANT_FLOAT_7 = 0x7, // UNASSIGNED
+  };
+
+  enum class Kind : uint64_t {
+    SCALAR = 0b000,
+    INTEGER = 0b001,
+    FLOAT = 0b010,
+    POINTER = 0b011,
+    VECTOR_SCALAR = 0b100,
+    VECTOR_INTEGER = 0b101,
+    VECTOR_FLOAT = 0b110,
+    VECTOR_POINTER = 0b111,
+  };
+
+  constexpr static Kind toVector(Kind Ty) {
+    if (Ty == Kind::POINTER)
+      return Kind::VECTOR_POINTER;
+
+    if (Ty == Kind::INTEGER)
+      return Kind::VECTOR_INTEGER;
+
+    if (Ty == Kind::FLOAT)
+      return Kind::VECTOR_FLOAT;
+
+    if (Ty == Kind::SCALAR)
+      return Kind::VECTOR_SCALAR;
+
+    llvm_unreachable("Type is already a vector type");
+  }
+
+  constexpr static Kind toScalar(Kind Ty) {
+    if (Ty == Kind::VECTOR_POINTER)
+      return Kind::POINTER;
+
+    if (Ty == Kind::VECTOR_INTEGER)
+      return Kind::INTEGER;
+
+    if (Ty == Kind::VECTOR_FLOAT)
+      return Kind::FLOAT;
+
+    if (Ty == Kind::VECTOR_SCALAR)
+      return Kind::SCALAR;
+
+    llvm_unreachable("Type is already a scalar type");
+  }
+
   /// Get a low-level scalar or aggregate "bag of bits".
+  // TODO: deperecate this: [[deprecated("Use LLT::integer(unsigned)
+  // instead.")]]
   static constexpr LLT scalar(unsigned SizeInBits) {
-    return LLT{/*isPointer=*/false, /*isVector=*/false, /*isScalar=*/true,
-               ElementCount::getFixed(0), SizeInBits,
-               /*AddressSpace=*/0};
+    return LLT{Kind::INTEGER, ElementCount::getFixed(0), SizeInBits,
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
+  }
+
+  static constexpr LLT integer(unsigned SizeInBits) {
+    return LLT{Kind::INTEGER, ElementCount::getFixed(0), SizeInBits,
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
+  }
+
+  static constexpr LLT floatingPoint(unsigned SizeInBits, FPVariant FP) {
+    return LLT{Kind::FLOAT, ElementCount::getFixed(0), SizeInBits,
+               /*AddressSpace=*/0, FP};
   }
 
   /// Get a low-level token; just a scalar with zero bits (or no size).
   static constexpr LLT token() {
-    return LLT{/*isPointer=*/false, /*isVector=*/false,
-               /*isScalar=*/true,   ElementCount::getFixed(0),
-               /*SizeInBits=*/0,
-               /*AddressSpace=*/0};
+    LLT Token;
+    Token.Info = Kind::INTEGER;
+    return Token;
   }
 
   /// Get a low-level pointer in the given address space.
   static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits) {
     assert(SizeInBits > 0 && "invalid pointer size");
-    return LLT{/*isPointer=*/true, /*isVector=*/false, /*isScalar=*/false,
-               ElementCount::getFixed(0), SizeInBits, AddressSpace};
+    return LLT{Kind::POINTER, ElementCount::getFixed(0), SizeInBits,
+               AddressSpace, static_cast<FPVariant>(0)};
   }
 
   /// Get a low-level vector of some number of elements and element width.
+  // TODO: deprecate this: [[deprecated("Use LLT::vector(EC, LLT) instead.")]]
   static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits) {
     assert(!EC.isScalar() && "invalid number of vector elements");
-    return LLT{/*isPointer=*/false, /*isVector=*/true, /*isScalar=*/false,
-               EC, ScalarSizeInBits, /*AddressSpace=*/0};
+    return LLT{Kind::VECTOR_INTEGER, EC, ScalarSizeInBits,
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
   }
 
   /// Get a low-level vector of some number of elements and element type.
   static constexpr LLT vector(ElementCount EC, LLT ScalarTy) {
     assert(!EC.isScalar() && "invalid number of vector elements");
     assert(!ScalarTy.isVector() && "invalid vector element type");
-    return LLT{ScalarTy.isPointer(),
-               /*isVector=*/true,
-               /*isScalar=*/false,
-               EC,
-               ScalarTy.getSizeInBits().getFixedValue(),
-               ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0};
+
+    Kind Info = toVector(ScalarTy.Info);
+    return LLT{Info, EC, ScalarTy.getSizeInBits().getFixedValue(),
+               ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0,
+               ScalarTy.isFloat() ? ScalarTy.getFPVariant()
+                                  : static_cast<FPVariant>(0)};
+  }
+  // Get a 8-bit brain float value.
+  static constexpr LLT bfloat8() {
+    return floatingPoint(8, FPVariant::BRAIN_FLOAT);
+  }
+
+  // Get a 16-bit brain float value.
+  static constexpr LLT bfloat16() {
+    return floatingPoint(16, FPVariant::BRAIN_FLOAT);
   }
 
   /// Get a 16-bit IEEE half value.
-  /// TODO: Add IEEE semantics to type - This currently returns a simple `scalar(16)`.
   static constexpr LLT float16() {
-    return scalar(16);
+    return floatingPoint(16, FPVariant::IEEE_FLOAT);
   }
 
   /// Get a 32-bit IEEE float value.
   static constexpr LLT float32() {
-    return scalar(32);
+    return floatingPoint(32, FPVariant::IEEE_FLOAT);
   }
 
   /// Get a 64-bit IEEE double value.
   static constexpr LLT float64() {
-    return scalar(64);
+    return floatingPoint(64, FPVariant::IEEE_FLOAT);
+  }
+
+  /// Get a 80-bit X86 floating point value.
+  static constexpr LLT x86fp80() {
+    return floatingPoint(80, FPVariant::VARIANT_FLOAT_3);
+  }
+
+  /// Get a 128-bit IEEE quad value.
+  static constexpr LLT float128() {
+    return floatingPoint(128, FPVariant::IEEE_FLOAT);
+  }
+
+  /// Get a 128-bit PowerPC double double value.
+  static constexpr LLT ppcf128() {
+    return floatingPoint(128, FPVariant::VARIANT_FLOAT_2);
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
   /// width.
+  // TODO: deprecate this: [[deprecated("Use LLT::fixed_vector(unsigned, LLT)
+  // instead.")]]
   static constexpr LLT fixed_vector(unsigned NumElements,
                                     unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getFixed(NumElements), ScalarSizeInBits);
+    return vector(ElementCount::getFixed(NumElements),
+                  LLT::integer(ScalarSizeInBits));
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
@@ -110,9 +202,12 @@ class LLT {
 
   /// Get a low-level scalable vector of some number of elements and element
   /// width.
+  // TODO: deprecate this: [[deprecated("Use LLT::scalable_vector(unsigned, LLT)
+  // instead.")]]
   static constexpr LLT scalable_vector(unsigned MinNumElements,
                                        unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getScalable(MinNumElements), ScalarSizeInBits);
+    return vector(ElementCount::getScalable(MinNumElements),
+                  LLT::integer(ScalarSizeInBits));
   }
 
   /// Get a low-level scalable vector of some number of elements and element
@@ -125,33 +220,84 @@ class LLT {
     return EC.isScalar() ? ScalarTy : LLT::vector(EC, ScalarTy);
   }
 
+  // TODO: deprecate this:  [[deprecated("Use LLT::scalarOrVector(EC, LLT)
+  // instead.")]]
   static constexpr LLT scalarOrVector(ElementCount EC, uint64_t ScalarSize) {
     assert(ScalarSize <= std::numeric_limits<unsigned>::max() &&
            "Not enough bits in LLT to represent size");
     return scalarOrVector(EC, LLT::scalar(static_cast<unsigned>(ScalarSize)));
   }
 
-  explicit constexpr LLT(bool isPointer, bool isVector, bool isScalar,
-                         ElementCount EC, uint64_t SizeInBits,
-                         unsigned AddressSpace)
+  explicit constexpr LLT(Kind Info, ElementCount EC, uint64_t SizeInBits,
+                         unsigned AddressSpace, FPVariant FP)
       : LLT() {
-    init(isPointer, isVector, isScalar, EC, SizeInBits, AddressSpace);
+    init(Info, EC, SizeInBits, AddressSpace, FP);
   }
-  explicit constexpr LLT()
-      : IsScalar(false), IsPointer(false), IsVector(false), RawData(0) {}
 
   explicit LLT(MVT VT);
+  explicit constexpr LLT() : Info(static_cast<Kind>(0)), RawData(0) {}
 
-  constexpr bool isValid() const { return IsScalar || RawData != 0; }
-  constexpr bool isScalar() const { return IsScalar; }
-  constexpr bool isToken() const { return IsScalar && RawData == 0; };
-  constexpr bool isVector() const { return isValid() && IsVector; }
+  constexpr bool isValid() const { return isToken() || RawData != 0; }
+  constexpr bool isScalar() const {
+    return isValid() && (Info == Kind::INTEGER || Info == Kind::FLOAT ||
+                         Info == Kind::SCALAR);
+  }
+  constexpr bool isScalar(unsigned Size) const {
+    return isScalar() && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isFloat() const { return isValid() && Info == Kind::FLOAT; }
+  constexpr bool isFloat(unsigned Size) const {
+    return isFloat() && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isVariantFloat() const {
+    return isFloat() && getFPVariant() != FPVariant::IEEE_FLOAT;
+  }
+  constexpr bool isVariantFloat(FPVariant Variant) const {
+    return isFloat() && getFPVariant() == Variant;
+  }
+  constexpr bool isVariantFloat(unsigned Size, FPVariant Variant) const {
+    return isVariantFloat(Variant) && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isFloatVector() const {
+    return isVector() && Info == Kind::VECTOR_FLOAT;
+  }
+  constexpr bool isIEEEFloat(unsigned Size) const {
+    return isVariantFloat(Size, FPVariant::IEEE_FLOAT);
+  }
+  constexpr bool isBFloat(unsigned Size) const {
+    return isVariantFloat(Size, FPVariant::BRAIN_FLOAT);
+  }
+  constexpr bool isX86FP80() const {
+    return isVariantFloat(80, FPVariant::VARIANT_FLOAT_3);
+  }
+  constexpr bool isPPCF128() const {
+    return isVariantFloat(128, FPVariant::VARIANT_FLOAT_2);
+  }
+  constexpr bool isToken() const {
+    return Info == Kind::INTEGER && RawData == 0;
+  }
+  constexpr bool isInteger() const {
+    return isValid() && Info == Kind::INTEGER;
+  }
+  constexpr bool isInteger(unsigned Size) const {
+    return isInteger() && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isIntegerVector() const {
+    return isVector() && Info == Kind::VECTOR_INTEGER;
+  }
+  constexpr bool isVector() const {
+    return isValid() &&
+           (Info == Kind::VECTOR_INTEGER || Info == Kind::VECTOR_FLOAT ||
+            Info == Kind::VECTOR_POINTER || Info == Kind::VECTOR_SCALAR);
+  }
   constexpr bool isPointer() const {
-    return isValid() && IsPointer && !IsVector;
+    return isValid() && Info == Kind::POINTER;
+  }
+  constexpr bool isPointerVector() const {
+    return isVector() && Info == Kind::VECTOR_POINTER;
   }
-  constexpr bool isPointerVector() const { return IsPointer && isVector(); }
   constexpr bool isPointerOrPointerVector() const {
-    return IsPointer && isValid();
+    return isPointer() || isPointerVector();
   }
 
   /// Returns the number of elements in a vector LLT. Must only be called on
@@ -181,7 +327,7 @@ class LLT {
   constexpr bool isScalableVector() const { return isVector() && isScalable(); }
 
   constexpr ElementCount getElementCount() const {
-    assert(IsVector && "cannot get number of elements on scalar/aggregate");
+    assert(isVector() && "cannot get number of elements on scalar/aggregate");
     return ElementCount::get(getFieldValue(VectorElementsFieldInfo),
                              isScalable());
   }
@@ -206,6 +352,15 @@ class LLT {
     return isVector() ? getElementType() : *this;
   }
 
+  constexpr FPVariant getFPVariant() const {
+    assert((isFloat() || isFloatVector()) &&
+           "cannot get FP info for non float type");
+
+    return FPVariant(getFieldValue(FPFieldInfo));
+  }
+
+  constexpr Kind getKind() const { return Info; }
+
   /// If this type is a vector, return a vector with the same number of elements
   /// but the new element type. Otherwise, return the new element type.
   constexpr LLT changeElementType(LLT NewEltTy) const {
@@ -216,10 +371,10 @@ class LLT {
   /// but the new element size. Otherwise, return the new element type. Invalid
   /// for pointer types. For pointer types, use changeElementType.
   constexpr LLT changeElementSize(unsigned NewEltSize) const {
-    assert(!isPointerOrPointerVector() &&
+    assert(!isPointerOrPointerVector() && !(isFloat() || isFloatVector()) &&
            "invalid to directly change element size for pointers");
-    return isVector() ? LLT::vector(getElementCount(), NewEltSize)
-                      : LLT::scalar(NewEltSize);
+    return isVector() ? LLT::vector(getElementCount(), LLT::integer(NewEltSize))
+                      : LLT::integer(NewEltSize);
   }
 
   /// Return a vector or scalar with the same element type and the new element
@@ -228,6 +383,10 @@ class LLT {
     return LLT::scalarOrVector(EC, getScalarType());
   }
 
+  constexpr LLT changeElementCount(unsigned NumElements) const {
+    return changeElementCount(ElementCount::getFixed(NumElements));
+  }
+
   /// Return a type that is \p Factor times smaller. Reduces the number of
   /// elements if this is a vector, or the bitwidth for scalar/pointers. Does
   /// not attempt to handle cases that aren't evenly divisible.
@@ -242,7 +401,7 @@ class LLT {
     }
 
     assert(getScalarSizeInBits() % Factor == 0);
-    return scalar(getScalarSizeInBits() / Factor);
+    return integer(getScalarSizeInBits() / Factor);
   }
 
   /// Produce a vector type that is \p Factor times bigger, preserving the
@@ -276,10 +435,23 @@ class LLT {
   /// Returns the vector's element type. Only valid for vector types.
   constexpr LLT getElementType() const {
     assert(isVector() && "cannot get element type of scalar/aggregate");
-    if (IsPointer)
+    if (isPointerVector())
       return pointer(getAddressSpace(), getScalarSizeInBits());
-    else
-      return scalar(getScalarSizeInBits());
+
+    if (isFloatVector())
+      return floatingPoint(getScalarSizeInBits(), getFPVariant());
+
+    return integer(getScalarSizeInBits());
+  }
+
+  constexpr LLT changeToInteger() const {
+    if (isPointer() || isPointerVector())
+      return *this;
+
+    if (isVector())
+      return vector(getElementCount(), LLT::integer(getScalarSizeInBits()));
+
+    return integer(getSizeInBits());
   }
 
   void print(raw_ostream &OS) const;
@@ -289,8 +461,7 @@ class LLT {
 #endif
 
   constexpr bool operator==(const LLT &RHS) const {
-    return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
-           IsScalar == RHS.IsScalar && RHS.RawData == RawData;
+    return Info == RHS.Info && RawData == RHS.RawData;
   }
 
   constexpr bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
@@ -300,37 +471,38 @@ class LLT {
 
 private:
   /// LLT is packed into 64 bits as follows:
-  /// isScalar : 1
-  /// isPointer : 1
-  /// isVector  : 1
-  /// with 61 bits remaining for Kind-specific data, packed in bitfields
-  /// as described below. As there isn't a simple portable way to pack bits
-  /// into bitfields, here the different fields in the packed structure is
+  /// Info : 3
+  /// RawData : 61
+  /// with 61 bits of RawData remaining for Kind-specific data, packed in
+  /// bitfields as described below. As there isn't a simple portable way to pack
+  /// bits into bitfields, here the different fields in the packed structure is
   /// described in static const *Field variables. Each of these variables
   /// is a 2-element array, with the first element describing the bitfield size
   /// and the second element describing the bitfield offset.
+  /// There are 3 special LLT instances:
+  /// - invalid: Info == SCALAR, RawData == 0
+  /// - token: Info == INTEGER, RawData == 0
+  /// - empty: Info == FLOAT, RawData == 0
+  /// - tombstone: Info == POINTER, RawData == 0
   ///
-  /// +--------+---------+--------+----------+----------------------+
-  /// |isScalar|isPointer|isVector| RawData  |Notes                 |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    0    |   0    |    0     |Invalid               |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    0    |   1    |    0     |Tombstone Key         |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    1    |   0    |    0     |Empty Key             |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   1    |    0    |   0    |    0     |Token                 |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   1    |    0    |   0    | non-zero |Scalar                |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    1    |   0    | non-zero |Pointer               |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    0    |   1    | non-zero |Vector of non-pointer |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    1    |   1    | non-zero |Vector of pointer     |
-  /// +--------+---------+--------+----------+----------------------+
-  ///
-  /// Everything else is reserved.
+  /*
+                                --- LLT ---
+
+   63       56       47       39       31       23       15       7      0
+   |        |        |        |        |        |        |        |      |
+  |xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|
+   ...................................                                      (1)
+   *****************                                                        (2)
+                     ~~~~~~~~~~~~~~~~~~~~~~~~~~                             (3)
+                                                ^^^^^^^^^^^^^^^^^           (4)
+                                                                      @     (5)
+                                            ###                             (6)
+                                                                       %%%  (7)
+
+  (1) ScalarSize  (2) PointerSize  (3) PointerAddressSpace
+  (4) VectorElements  (5) VectorScalable  (6) FPVariant  (7) Kind
+
+  */
   typedef int BitFieldInfo[2];
   ///
   /// This is how the bitfields are packed per Kind:
@@ -340,6 +512,7 @@ class LLT {
   /// * Non-pointer scalar (isPointer == 0 && isVector == 0):
   ///   SizeInBits: 32;
   static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 29};
+  static const constexpr BitFieldInfo FPFieldInfo{3, 21};
   /// * Pointer (isPoint...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Mar 11, 2025

@llvm/pr-subscribers-llvm-globalisel

Author: Tim Gymnich (tgymnich)

Changes
  • adds new floating point and integer LLT kinds for both scalars and vectors.

makes progress on #119667


Patch is 63.32 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/130651.diff

41 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/LowLevelTypeUtils.h (+1-1)
  • (modified) llvm/include/llvm/CodeGenTypes/LowLevelType.h (+270-94)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizeMutations.cpp (+2-4)
  • (modified) llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp (+2-1)
  • (modified) llvm/lib/CodeGen/LowLevelTypeUtils.cpp (+61-13)
  • (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+71-31)
  • (modified) llvm/lib/CodeGenTypes/LowLevelType.cpp (+47-13)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid0.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid1.mir (+1-1)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid11.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid12.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid13.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid14.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid15.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid16.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid17.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid18.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid19.mir (+10)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid2.mir (+1-1)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid20.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid21.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid22.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid23.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid24.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid25.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid26.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid27.mir (+10)
  • (added) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid28.mir (+10)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid3.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid5.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid6.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid7.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid8.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err10.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err8.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err9.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid0.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir (+2-2)
  • (modified) llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp (+8-6)
  • (modified) llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp (+66-39)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index 9472aa196f9b4..f8819d9efd833 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -374,7 +374,7 @@ LegalizeMutation changeElementCountTo(unsigned TypeIdx, unsigned FromTypeIdx);
 
 /// Keep the same scalar or element type as \p TypeIdx, but take the number of
 /// elements from \p Ty.
-LegalizeMutation changeElementCountTo(unsigned TypeIdx, LLT Ty);
+LegalizeMutation changeElementCountTo(unsigned TypeIdx, ElementCount EC);
 
 /// Change the scalar size or element size to have the same scalar size as type
 /// index \p FromIndex. Unlike changeElementTo, this discards pointer types and
diff --git a/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h b/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
index 142e5cd4e7ad1..e9288ce8fdf51 100644
--- a/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
+++ b/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
@@ -40,6 +40,6 @@ LLT getLLTForMVT(MVT Ty);
 /// Get the appropriate floating point arithmetic semantic based on the bit size
 /// of the given scalar LLT.
 const llvm::fltSemantics &getFltSemanticForLLT(LLT Ty);
-}
+} // namespace llvm
 
 #endif // LLVM_CODEGEN_LOWLEVELTYPEUTILS_H
diff --git a/llvm/include/llvm/CodeGenTypes/LowLevelType.h b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
index 06879e1f8d15b..27692b2c9f1b3 100644
--- a/llvm/include/llvm/CodeGenTypes/LowLevelType.h
+++ b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
@@ -29,6 +29,7 @@
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/CodeGenTypes/MachineValueType.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <cassert>
 
 namespace llvm {
@@ -38,68 +39,159 @@ class raw_ostream;
 
 class LLT {
 public:
+  enum class FPVariant {
+    IEEE_FLOAT = 0x0,
+    BRAIN_FLOAT = 0x1,     // BRAIN_FLOAT
+    VARIANT_FLOAT_2 = 0x2, // PPC_FLOAT
+    VARIANT_FLOAT_3 = 0x3, // FP80
+    VARIANT_FLOAT_4 = 0x4, // TENSOR_FLOAT
+    VARIANT_FLOAT_5 = 0x5, // UNASSIGNED
+    VARIANT_FLOAT_6 = 0x6, // UNASSIGNED
+    VARIANT_FLOAT_7 = 0x7, // UNASSIGNED
+  };
+
+  enum class Kind : uint64_t {
+    SCALAR = 0b000,
+    INTEGER = 0b001,
+    FLOAT = 0b010,
+    POINTER = 0b011,
+    VECTOR_SCALAR = 0b100,
+    VECTOR_INTEGER = 0b101,
+    VECTOR_FLOAT = 0b110,
+    VECTOR_POINTER = 0b111,
+  };
+
+  constexpr static Kind toVector(Kind Ty) {
+    if (Ty == Kind::POINTER)
+      return Kind::VECTOR_POINTER;
+
+    if (Ty == Kind::INTEGER)
+      return Kind::VECTOR_INTEGER;
+
+    if (Ty == Kind::FLOAT)
+      return Kind::VECTOR_FLOAT;
+
+    if (Ty == Kind::SCALAR)
+      return Kind::VECTOR_SCALAR;
+
+    llvm_unreachable("Type is already a vector type");
+  }
+
+  constexpr static Kind toScalar(Kind Ty) {
+    if (Ty == Kind::VECTOR_POINTER)
+      return Kind::POINTER;
+
+    if (Ty == Kind::VECTOR_INTEGER)
+      return Kind::INTEGER;
+
+    if (Ty == Kind::VECTOR_FLOAT)
+      return Kind::FLOAT;
+
+    if (Ty == Kind::VECTOR_SCALAR)
+      return Kind::SCALAR;
+
+    llvm_unreachable("Type is already a scalar type");
+  }
+
   /// Get a low-level scalar or aggregate "bag of bits".
+  // TODO: deperecate this: [[deprecated("Use LLT::integer(unsigned)
+  // instead.")]]
   static constexpr LLT scalar(unsigned SizeInBits) {
-    return LLT{/*isPointer=*/false, /*isVector=*/false, /*isScalar=*/true,
-               ElementCount::getFixed(0), SizeInBits,
-               /*AddressSpace=*/0};
+    return LLT{Kind::INTEGER, ElementCount::getFixed(0), SizeInBits,
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
+  }
+
+  static constexpr LLT integer(unsigned SizeInBits) {
+    return LLT{Kind::INTEGER, ElementCount::getFixed(0), SizeInBits,
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
+  }
+
+  static constexpr LLT floatingPoint(unsigned SizeInBits, FPVariant FP) {
+    return LLT{Kind::FLOAT, ElementCount::getFixed(0), SizeInBits,
+               /*AddressSpace=*/0, FP};
   }
 
   /// Get a low-level token; just a scalar with zero bits (or no size).
   static constexpr LLT token() {
-    return LLT{/*isPointer=*/false, /*isVector=*/false,
-               /*isScalar=*/true,   ElementCount::getFixed(0),
-               /*SizeInBits=*/0,
-               /*AddressSpace=*/0};
+    LLT Token;
+    Token.Info = Kind::INTEGER;
+    return Token;
   }
 
   /// Get a low-level pointer in the given address space.
   static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits) {
     assert(SizeInBits > 0 && "invalid pointer size");
-    return LLT{/*isPointer=*/true, /*isVector=*/false, /*isScalar=*/false,
-               ElementCount::getFixed(0), SizeInBits, AddressSpace};
+    return LLT{Kind::POINTER, ElementCount::getFixed(0), SizeInBits,
+               AddressSpace, static_cast<FPVariant>(0)};
   }
 
   /// Get a low-level vector of some number of elements and element width.
+  // TODO: deprecate this: [[deprecated("Use LLT::vector(EC, LLT) instead.")]]
   static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits) {
     assert(!EC.isScalar() && "invalid number of vector elements");
-    return LLT{/*isPointer=*/false, /*isVector=*/true, /*isScalar=*/false,
-               EC, ScalarSizeInBits, /*AddressSpace=*/0};
+    return LLT{Kind::VECTOR_INTEGER, EC, ScalarSizeInBits,
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
   }
 
   /// Get a low-level vector of some number of elements and element type.
   static constexpr LLT vector(ElementCount EC, LLT ScalarTy) {
     assert(!EC.isScalar() && "invalid number of vector elements");
     assert(!ScalarTy.isVector() && "invalid vector element type");
-    return LLT{ScalarTy.isPointer(),
-               /*isVector=*/true,
-               /*isScalar=*/false,
-               EC,
-               ScalarTy.getSizeInBits().getFixedValue(),
-               ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0};
+
+    Kind Info = toVector(ScalarTy.Info);
+    return LLT{Info, EC, ScalarTy.getSizeInBits().getFixedValue(),
+               ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0,
+               ScalarTy.isFloat() ? ScalarTy.getFPVariant()
+                                  : static_cast<FPVariant>(0)};
+  }
+  // Get a 8-bit brain float value.
+  static constexpr LLT bfloat8() {
+    return floatingPoint(8, FPVariant::BRAIN_FLOAT);
+  }
+
+  // Get a 16-bit brain float value.
+  static constexpr LLT bfloat16() {
+    return floatingPoint(16, FPVariant::BRAIN_FLOAT);
   }
 
   /// Get a 16-bit IEEE half value.
-  /// TODO: Add IEEE semantics to type - This currently returns a simple `scalar(16)`.
   static constexpr LLT float16() {
-    return scalar(16);
+    return floatingPoint(16, FPVariant::IEEE_FLOAT);
   }
 
   /// Get a 32-bit IEEE float value.
   static constexpr LLT float32() {
-    return scalar(32);
+    return floatingPoint(32, FPVariant::IEEE_FLOAT);
   }
 
   /// Get a 64-bit IEEE double value.
   static constexpr LLT float64() {
-    return scalar(64);
+    return floatingPoint(64, FPVariant::IEEE_FLOAT);
+  }
+
+  /// Get a 80-bit X86 floating point value.
+  static constexpr LLT x86fp80() {
+    return floatingPoint(80, FPVariant::VARIANT_FLOAT_3);
+  }
+
+  /// Get a 128-bit IEEE quad value.
+  static constexpr LLT float128() {
+    return floatingPoint(128, FPVariant::IEEE_FLOAT);
+  }
+
+  /// Get a 128-bit PowerPC double double value.
+  static constexpr LLT ppcf128() {
+    return floatingPoint(128, FPVariant::VARIANT_FLOAT_2);
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
   /// width.
+  // TODO: deprecate this: [[deprecated("Use LLT::fixed_vector(unsigned, LLT)
+  // instead.")]]
   static constexpr LLT fixed_vector(unsigned NumElements,
                                     unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getFixed(NumElements), ScalarSizeInBits);
+    return vector(ElementCount::getFixed(NumElements),
+                  LLT::integer(ScalarSizeInBits));
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
@@ -110,9 +202,12 @@ class LLT {
 
   /// Get a low-level scalable vector of some number of elements and element
   /// width.
+  // TODO: deprecate this: [[deprecated("Use LLT::scalable_vector(unsigned, LLT)
+  // instead.")]]
   static constexpr LLT scalable_vector(unsigned MinNumElements,
                                        unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getScalable(MinNumElements), ScalarSizeInBits);
+    return vector(ElementCount::getScalable(MinNumElements),
+                  LLT::integer(ScalarSizeInBits));
   }
 
   /// Get a low-level scalable vector of some number of elements and element
@@ -125,33 +220,84 @@ class LLT {
     return EC.isScalar() ? ScalarTy : LLT::vector(EC, ScalarTy);
   }
 
+  // TODO: deprecate this:  [[deprecated("Use LLT::scalarOrVector(EC, LLT)
+  // instead.")]]
   static constexpr LLT scalarOrVector(ElementCount EC, uint64_t ScalarSize) {
     assert(ScalarSize <= std::numeric_limits<unsigned>::max() &&
            "Not enough bits in LLT to represent size");
     return scalarOrVector(EC, LLT::scalar(static_cast<unsigned>(ScalarSize)));
   }
 
-  explicit constexpr LLT(bool isPointer, bool isVector, bool isScalar,
-                         ElementCount EC, uint64_t SizeInBits,
-                         unsigned AddressSpace)
+  explicit constexpr LLT(Kind Info, ElementCount EC, uint64_t SizeInBits,
+                         unsigned AddressSpace, FPVariant FP)
       : LLT() {
-    init(isPointer, isVector, isScalar, EC, SizeInBits, AddressSpace);
+    init(Info, EC, SizeInBits, AddressSpace, FP);
   }
-  explicit constexpr LLT()
-      : IsScalar(false), IsPointer(false), IsVector(false), RawData(0) {}
 
   explicit LLT(MVT VT);
+  explicit constexpr LLT() : Info(static_cast<Kind>(0)), RawData(0) {}
 
-  constexpr bool isValid() const { return IsScalar || RawData != 0; }
-  constexpr bool isScalar() const { return IsScalar; }
-  constexpr bool isToken() const { return IsScalar && RawData == 0; };
-  constexpr bool isVector() const { return isValid() && IsVector; }
+  constexpr bool isValid() const { return isToken() || RawData != 0; }
+  constexpr bool isScalar() const {
+    return isValid() && (Info == Kind::INTEGER || Info == Kind::FLOAT ||
+                         Info == Kind::SCALAR);
+  }
+  constexpr bool isScalar(unsigned Size) const {
+    return isScalar() && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isFloat() const { return isValid() && Info == Kind::FLOAT; }
+  constexpr bool isFloat(unsigned Size) const {
+    return isFloat() && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isVariantFloat() const {
+    return isFloat() && getFPVariant() != FPVariant::IEEE_FLOAT;
+  }
+  constexpr bool isVariantFloat(FPVariant Variant) const {
+    return isFloat() && getFPVariant() == Variant;
+  }
+  constexpr bool isVariantFloat(unsigned Size, FPVariant Variant) const {
+    return isVariantFloat(Variant) && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isFloatVector() const {
+    return isVector() && Info == Kind::VECTOR_FLOAT;
+  }
+  constexpr bool isIEEEFloat(unsigned Size) const {
+    return isVariantFloat(Size, FPVariant::IEEE_FLOAT);
+  }
+  constexpr bool isBFloat(unsigned Size) const {
+    return isVariantFloat(Size, FPVariant::BRAIN_FLOAT);
+  }
+  constexpr bool isX86FP80() const {
+    return isVariantFloat(80, FPVariant::VARIANT_FLOAT_3);
+  }
+  constexpr bool isPPCF128() const {
+    return isVariantFloat(128, FPVariant::VARIANT_FLOAT_2);
+  }
+  constexpr bool isToken() const {
+    return Info == Kind::INTEGER && RawData == 0;
+  }
+  constexpr bool isInteger() const {
+    return isValid() && Info == Kind::INTEGER;
+  }
+  constexpr bool isInteger(unsigned Size) const {
+    return isInteger() && getScalarSizeInBits() == Size;
+  }
+  constexpr bool isIntegerVector() const {
+    return isVector() && Info == Kind::VECTOR_INTEGER;
+  }
+  constexpr bool isVector() const {
+    return isValid() &&
+           (Info == Kind::VECTOR_INTEGER || Info == Kind::VECTOR_FLOAT ||
+            Info == Kind::VECTOR_POINTER || Info == Kind::VECTOR_SCALAR);
+  }
   constexpr bool isPointer() const {
-    return isValid() && IsPointer && !IsVector;
+    return isValid() && Info == Kind::POINTER;
+  }
+  constexpr bool isPointerVector() const {
+    return isVector() && Info == Kind::VECTOR_POINTER;
   }
-  constexpr bool isPointerVector() const { return IsPointer && isVector(); }
   constexpr bool isPointerOrPointerVector() const {
-    return IsPointer && isValid();
+    return isPointer() || isPointerVector();
   }
 
   /// Returns the number of elements in a vector LLT. Must only be called on
@@ -181,7 +327,7 @@ class LLT {
   constexpr bool isScalableVector() const { return isVector() && isScalable(); }
 
   constexpr ElementCount getElementCount() const {
-    assert(IsVector && "cannot get number of elements on scalar/aggregate");
+    assert(isVector() && "cannot get number of elements on scalar/aggregate");
     return ElementCount::get(getFieldValue(VectorElementsFieldInfo),
                              isScalable());
   }
@@ -206,6 +352,15 @@ class LLT {
     return isVector() ? getElementType() : *this;
   }
 
+  constexpr FPVariant getFPVariant() const {
+    assert((isFloat() || isFloatVector()) &&
+           "cannot get FP info for non float type");
+
+    return FPVariant(getFieldValue(FPFieldInfo));
+  }
+
+  constexpr Kind getKind() const { return Info; }
+
   /// If this type is a vector, return a vector with the same number of elements
   /// but the new element type. Otherwise, return the new element type.
   constexpr LLT changeElementType(LLT NewEltTy) const {
@@ -216,10 +371,10 @@ class LLT {
   /// but the new element size. Otherwise, return the new element type. Invalid
   /// for pointer types. For pointer types, use changeElementType.
   constexpr LLT changeElementSize(unsigned NewEltSize) const {
-    assert(!isPointerOrPointerVector() &&
+    assert(!isPointerOrPointerVector() && !(isFloat() || isFloatVector()) &&
            "invalid to directly change element size for pointers");
-    return isVector() ? LLT::vector(getElementCount(), NewEltSize)
-                      : LLT::scalar(NewEltSize);
+    return isVector() ? LLT::vector(getElementCount(), LLT::integer(NewEltSize))
+                      : LLT::integer(NewEltSize);
   }
 
   /// Return a vector or scalar with the same element type and the new element
@@ -228,6 +383,10 @@ class LLT {
     return LLT::scalarOrVector(EC, getScalarType());
   }
 
+  constexpr LLT changeElementCount(unsigned NumElements) const {
+    return changeElementCount(ElementCount::getFixed(NumElements));
+  }
+
   /// Return a type that is \p Factor times smaller. Reduces the number of
   /// elements if this is a vector, or the bitwidth for scalar/pointers. Does
   /// not attempt to handle cases that aren't evenly divisible.
@@ -242,7 +401,7 @@ class LLT {
     }
 
     assert(getScalarSizeInBits() % Factor == 0);
-    return scalar(getScalarSizeInBits() / Factor);
+    return integer(getScalarSizeInBits() / Factor);
   }
 
   /// Produce a vector type that is \p Factor times bigger, preserving the
@@ -276,10 +435,23 @@ class LLT {
   /// Returns the vector's element type. Only valid for vector types.
   constexpr LLT getElementType() const {
     assert(isVector() && "cannot get element type of scalar/aggregate");
-    if (IsPointer)
+    if (isPointerVector())
       return pointer(getAddressSpace(), getScalarSizeInBits());
-    else
-      return scalar(getScalarSizeInBits());
+
+    if (isFloatVector())
+      return floatingPoint(getScalarSizeInBits(), getFPVariant());
+
+    return integer(getScalarSizeInBits());
+  }
+
+  constexpr LLT changeToInteger() const {
+    if (isPointer() || isPointerVector())
+      return *this;
+
+    if (isVector())
+      return vector(getElementCount(), LLT::integer(getScalarSizeInBits()));
+
+    return integer(getSizeInBits());
   }
 
   void print(raw_ostream &OS) const;
@@ -289,8 +461,7 @@ class LLT {
 #endif
 
   constexpr bool operator==(const LLT &RHS) const {
-    return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
-           IsScalar == RHS.IsScalar && RHS.RawData == RawData;
+    return Info == RHS.Info && RawData == RHS.RawData;
   }
 
   constexpr bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
@@ -300,37 +471,38 @@ class LLT {
 
 private:
   /// LLT is packed into 64 bits as follows:
-  /// isScalar : 1
-  /// isPointer : 1
-  /// isVector  : 1
-  /// with 61 bits remaining for Kind-specific data, packed in bitfields
-  /// as described below. As there isn't a simple portable way to pack bits
-  /// into bitfields, here the different fields in the packed structure is
+  /// Info : 3
+  /// RawData : 61
+  /// with 61 bits of RawData remaining for Kind-specific data, packed in
+  /// bitfields as described below. As there isn't a simple portable way to pack
+  /// bits into bitfields, here the different fields in the packed structure is
   /// described in static const *Field variables. Each of these variables
   /// is a 2-element array, with the first element describing the bitfield size
   /// and the second element describing the bitfield offset.
+  /// There are 3 special LLT instances:
+  /// - invalid: Info == SCALAR, RawData == 0
+  /// - token: Info == INTEGER, RawData == 0
+  /// - empty: Info == FLOAT, RawData == 0
+  /// - tombstone: Info == POINTER, RawData == 0
   ///
-  /// +--------+---------+--------+----------+----------------------+
-  /// |isScalar|isPointer|isVector| RawData  |Notes                 |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    0    |   0    |    0     |Invalid               |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    0    |   1    |    0     |Tombstone Key         |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    1    |   0    |    0     |Empty Key             |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   1    |    0    |   0    |    0     |Token                 |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   1    |    0    |   0    | non-zero |Scalar                |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    1    |   0    | non-zero |Pointer               |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    0    |   1    | non-zero |Vector of non-pointer |
-  /// +--------+---------+--------+----------+----------------------+
-  /// |   0    |    1    |   1    | non-zero |Vector of pointer     |
-  /// +--------+---------+--------+----------+----------------------+
-  ///
-  /// Everything else is reserved.
+  /*
+                                --- LLT ---
+
+   63       56       47       39       31       23       15       7      0
+   |        |        |        |        |        |        |        |      |
+  |xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|
+   ...................................                                      (1)
+   *****************                                                        (2)
+                     ~~~~~~~~~~~~~~~~~~~~~~~~~~                             (3)
+                                                ^^^^^^^^^^^^^^^^^           (4)
+                                                                      @     (5)
+                                            ###                             (6)
+                                                                       %%%  (7)
+
+  (1) ScalarSize  (2) PointerSize  (3) PointerAddressSpace
+  (4) VectorElements  (5) VectorScalable  (6) FPVariant  (7) Kind
+
+  */
   typedef int BitFieldInfo[2];
   ///
   /// This is how the bitfields are packed per Kind:
@@ -340,6 +512,7 @@ class LLT {
   /// * Non-pointer scalar (isPointer == 0 && isVector == 0):
   ///   SizeInBits: 32;
   static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 29};
+  static const constexpr BitFieldInfo FPFieldInfo{3, 21};
   /// * Pointer (isPoint...
[truncated]

@tgymnich tgymnich force-pushed the tim/gisel-fp-1 branch 2 times, most recently from 0a920fd to 3e98c53 Compare March 11, 2025 14:57
@github-actions
Copy link

github-actions bot commented Mar 11, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@tgymnich tgymnich changed the title [GlobalISel][AMDGPU] LLT changes for FPInfo [GlobalISel] LLT changes for FPInfo Mar 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants