Skip to content

Conversation

@DenisGZM
Copy link
Contributor

@DenisGZM DenisGZM commented Aug 23, 2025

Added extra information in LLT to support ambiguous fp types during GlobalISel. Original idea by @tgymnich

Main differences from #122503 are:

  • Do not deprecate LLT::scalar
  • Allow targets to enable/disable IR translation with extenden LLT via TargetOption::EnableGlobalISelExtendedLLT (disabled by default)
  • IRTranslator use TargetLoweringInfo for appropriate LLT generation.
  • For this reason added flag in GlobalISelMatchTable` to allow switch between legacy and new extended LLT names
  • Revert using stubs like LLT::float32 for float types as they are real now. Added TODO for such cases.

Also MIRParser now may parse new type indentifiers.

@llvmbot
Copy link
Member

llvmbot commented Aug 23, 2025

@llvm/pr-subscribers-llvm-selectiondag
@llvm/pr-subscribers-tablegen

@llvm/pr-subscribers-backend-amdgpu

Author: Denis.G (DenisGZM)

Changes

Added extra information in LLT to support ambiguous fp types during GlobalISel. Original idea by @tgymnich

Main differences from #122503 are:

  • Do not deprecate LLT::scalar
  • Allow targets to enable/disable IR translation with extenden LLT via TargetOption::EnableGlobalISelExtendedLLT (disabled by default)
  • IRTranslator use TargetLoweringInfo for appropriate LLT generation.
  • For this reason added flag in GlobalISelMatchTable` to allow switch between legacy and new extended LLT names
  • Revert using stubs like LLT::float32 for float types as they are real now. Added TODO for such cases.

Also MIRParser now may parse new type indetifiers.


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

50 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/Analysis.h (+2-1)
  • (modified) llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h (+2)
  • (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/LowLevelTypeUtils.h (+3-3)
  • (modified) llvm/include/llvm/CodeGen/TargetLowering.h (+3)
  • (modified) llvm/include/llvm/CodeGenTypes/LowLevelType.h (+275-99)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+1)
  • (modified) llvm/include/llvm/Target/TargetOptions.h (+6-1)
  • (modified) llvm/lib/CodeGen/Analysis.cpp (+5-5)
  • (modified) llvm/lib/CodeGen/GlobalISel/CallLowering.cpp (+7-6)
  • (modified) llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp (+46-41)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizeMutations.cpp (+2-4)
  • (modified) llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp (+2-1)
  • (modified) llvm/lib/CodeGen/LowLevelTypeUtils.cpp (+71-16)
  • (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+78-37)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/TargetLoweringBase.cpp (+8)
  • (modified) llvm/lib/CodeGenTypes/LowLevelType.cpp (+65-14)
  • (modified) llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp (+2-2)
  • (modified) llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp (+3-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp (+5-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp (+9-8)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid0.mir (+2-2)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid1.mir (+2-2)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid2.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid3.mir (+3-3)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err0.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err1.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-err11.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err12.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err13.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err14.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err15.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err2.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err3.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err4.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err5.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err6.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err7.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 (+2-2)
  • (modified) llvm/test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir (+2-2)
  • (modified) llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt (+1)
  • (added) llvm/unittests/CodeGen/GlobalISel/IRTranslatorBF16Test.cpp (+130)
  • (modified) llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp (+8-6)
  • (modified) llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp (+70-9)
diff --git a/llvm/include/llvm/CodeGen/Analysis.h b/llvm/include/llvm/CodeGen/Analysis.h
index 98b52579d03b7..2aadc27930b7a 100644
--- a/llvm/include/llvm/CodeGen/Analysis.h
+++ b/llvm/include/llvm/CodeGen/Analysis.h
@@ -101,7 +101,8 @@ inline void ComputeValueVTs(const TargetLowering &TLI, const DataLayout &DL,
 /// If Offsets is non-null, it points to a vector to be filled in
 /// with the in-memory offsets of each of the individual values.
 ///
-void computeValueLLTs(const DataLayout &DL, Type &Ty,
+void computeValueLLTs(const TargetLowering &TLI,
+                      const DataLayout &DL, Type &Ty,
                       SmallVectorImpl<LLT> &ValueTys,
                       SmallVectorImpl<uint64_t> *Offsets = nullptr,
                       uint64_t StartingOffset = 0);
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index 3d7ccd55ee042..5673fd5168477 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -642,6 +642,8 @@ class IRTranslator : public MachineFunctionPass {
 
   StackProtectorDescriptor SPDescriptor;
 
+  bool mayTranslateUserTypes(const User &U) const;
+
   /// Switch analysis and optimization.
   class GISelSwitchLowering : public SwitchCG::SwitchLowering {
   public:
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index fd72a3898562e..8412042a780e8 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -380,7 +380,7 @@ LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx,
 
 /// Keep the same scalar or element type as \p TypeIdx, but take the number of
 /// elements from \p Ty.
-LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx, LLT Ty);
+LLVM_ABI 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 51a298eb8b247..1c8f34b1a8518 100644
--- a/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
+++ b/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
@@ -27,7 +27,7 @@ class Type;
 struct fltSemantics;
 
 /// Construct a low-level type based on an LLVM type.
-LLVM_ABI LLT getLLTForType(Type &Ty, const DataLayout &DL);
+LLVM_ABI LLT getLLTForType(Type &Ty, const DataLayout &DL, bool AllowExtendedLLT = false);
 
 /// Get a rough equivalent of an MVT for a given LLT. MVT can't distinguish
 /// pointers, so these will convert to a plain integer.
@@ -36,11 +36,11 @@ LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx);
 
 /// Get a rough equivalent of an LLT for a given MVT. LLT does not yet support
 /// scalarable vector types, and will assert if used.
-LLVM_ABI LLT getLLTForMVT(MVT Ty);
+LLVM_ABI LLT getLLTForMVT(MVT Ty, bool AllowExtendedLLT = false);
 
 /// Get the appropriate floating point arithmetic semantic based on the bit size
 /// of the given scalar LLT.
 LLVM_ABI const llvm::fltSemantics &getFltSemanticForLLT(LLT Ty);
-}
+} // namespace llvm
 
 #endif // LLVM_CODEGEN_LOWLEVELTYPEUTILS_H
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 4480ced637456..f4fdd8c69ea9e 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -416,6 +416,9 @@ class LLVM_ABI TargetLoweringBase {
   /// amounts, returns MVT::i32.
   EVT getShiftAmountTy(EVT LHSTy, const DataLayout &DL) const;
 
+  virtual LLT getLLTForType(Type &Ty, const DataLayout &DL) const;
+  virtual LLT getLLTForMVT(MVT Ty) const;
+
   /// Return the preferred type to use for a shift opcode, given the shifted
   /// amount type is \p ShiftValueTy.
   LLVM_READONLY
diff --git a/llvm/include/llvm/CodeGenTypes/LowLevelType.h b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
index d8e0848aff84d..0c217ba1fcf7e 100644
--- a/llvm/include/llvm/CodeGenTypes/LowLevelType.h
+++ b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
@@ -39,68 +39,148 @@ class raw_ostream;
 
 class LLT {
 public:
+  enum class FPVariant {
+    IEEE_FLOAT = 0x0,
+    BRAIN_FLOAT = 0x1,     // BRAIN_FLOAT
+    PPC128_FLOAT = 0x2,    // PPC128_FLOAT
+    EXTENDED_FP80 = 0x3,   // FP80
+    TENSOR_FLOAT32 = 0x4,  // TENSOR_FLOAT32
+    VARIANT_FLOAT_5 = 0x5, // UNASSIGNED
+    VARIANT_FLOAT_6 = 0x6, // UNASSIGNED
+    VARIANT_FLOAT_7 = 0x7, // UNASSIGNED
+  };
+
+  enum class Kind : uint64_t {
+    INVALID = 0b0000,
+    ANY_SCALAR = 0b0001,
+    INTEGER = 0b0010,
+    FLOAT = 0b0011,
+    POINTER = 0b0100,
+    VECTOR_ANY = 0b0101,
+    VECTOR_INTEGER = 0b0110,
+    VECTOR_FLOAT = 0b0111,
+    VECTOR_POINTER = 0b1000,
+  };
+
+  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;
+
+    return Kind::VECTOR_ANY;
+  }
+
+  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;
+
+    return Kind::ANY_SCALAR;
+  }
+
   /// Get a low-level scalar or aggregate "bag of bits".
   static constexpr LLT scalar(unsigned SizeInBits) {
-    return LLT{/*isPointer=*/false, /*isVector=*/false, /*isScalar=*/true,
-               ElementCount::getFixed(0), SizeInBits,
-               /*AddressSpace=*/0};
+    return LLT{Kind::ANY_SCALAR, 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),
+    return LLT{Kind::ANY_SCALAR, ElementCount::getFixed(0),
                /*SizeInBits=*/0,
-               /*AddressSpace=*/0};
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
   }
 
   /// 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.
   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_ANY, 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::EXTENDED_FP80);
+  }
+
+  /// 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::PPC128_FLOAT);
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
   /// width.
-  static constexpr LLT fixed_vector(unsigned NumElements,
-                                    unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getFixed(NumElements), ScalarSizeInBits);
+  static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits) {
+    return vector(ElementCount::getFixed(NumElements),
+                  LLT::scalar(ScalarSizeInBits));
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
@@ -111,9 +191,9 @@ class LLT {
 
   /// Get a low-level scalable vector of some number of elements and element
   /// width.
-  static constexpr LLT scalable_vector(unsigned MinNumElements,
-                                       unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getScalable(MinNumElements), ScalarSizeInBits);
+  static constexpr LLT scalable_vector(unsigned MinNumElements, unsigned ScalarSizeInBits) {
+    return vector(ElementCount::getScalable(MinNumElements),
+                  LLT::scalar(ScalarSizeInBits));
   }
 
   /// Get a low-level scalable vector of some number of elements and element
@@ -132,27 +212,79 @@ class LLT {
     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) {}
 
-  LLVM_ABI explicit LLT(MVT VT);
+  LLVM_ABI explicit LLT(MVT VT, bool AllowExtendedLLT = false);
+  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 Info == Kind::ANY_SCALAR || Info == Kind::INTEGER || Info == Kind::FLOAT; }
+  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::EXTENDED_FP80);
+  }
+  constexpr bool isPPCF128() const {
+    return isVariantFloat(128, FPVariant::PPC128_FLOAT);
+  }
+  constexpr bool isToken() const {
+    return Info == Kind::ANY_SCALAR && RawData == 0;
+  }
+  constexpr bool isAnyScalar() const {
+    return isValid() && Info == Kind::ANY_SCALAR;
+  }
+  constexpr bool isVectorAny() const {
+    return isVector() && Info == Kind::VECTOR_ANY;
+  }
+  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_ANY || Info == Kind::VECTOR_INTEGER||
+            Info == Kind::VECTOR_FLOAT || Info == Kind::VECTOR_POINTER);
+  }
   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
@@ -177,12 +309,18 @@ class LLT {
   /// if the LLT is not a vector type.
   constexpr bool isFixedVector() const { return isVector() && !isScalable(); }
 
+  constexpr bool isFixedVector(unsigned NumElements,
+                               unsigned ScalarSize) const {
+    return isFixedVector() && getNumElements() == NumElements &&
+           getScalarSizeInBits() == ScalarSize;
+  }
+
   /// Returns true if the LLT is a scalable vector. Returns false otherwise,
   /// even if the LLT is not a vector type.
   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());
   }
@@ -207,6 +345,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 {
@@ -217,10 +364,14 @@ 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(), getElementType().isInteger()
+                                                    ? LLT::integer(NewEltSize)
+                                                    : LLT::scalar(NewEltSize))
+           : isInteger() ? LLT::integer(NewEltSize)
+                         : LLT::scalar(NewEltSize);
   }
 
   /// Return a vector or scalar with the same element type and the new element
@@ -229,6 +380,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.
@@ -243,6 +398,9 @@ class LLT {
     }
 
     assert(getScalarSizeInBits() % Factor == 0);
+    if (isInteger())
+      return integer(getScalarSizeInBits() / Factor);
+
     return scalar(getScalarSizeInBits() / Factor);
   }
 
@@ -277,10 +435,26 @@ 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());
+
+    if (isIntegerVector())
+      return integer(getScalarSizeInBits());
+
+    return scalar(getScalarSizeInBits());
+  }
+
+  constexpr LLT changeToInteger() const {
+    if (isPointer() || isPointerVector())
+      return *this;
+
+    if (isVector())
+      return vector(getElementCount(), LLT::integer(getScalarSizeInBits()));
+
+    return integer(getSizeInBits());
   }
 
   LLVM_ABI void print(raw_ostream &OS) const;
@@ -290,8 +464,14 @@ class LLT {
 #endif
 
   constexpr bool operator==(const LLT &RHS) const {
-    return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
-           IsScalar == RHS.IsScalar && RHS.RawData == RawData;
+    if (isAnyScalar() || RHS.isAnyScalar()) {
+      return isScalar() == RHS.isScalar() && RawData == RHS.RawData;
+    }
+    if (isVector() && RHS.isVector()) {
+      return getElementType() == RHS.getElementType() &&
+             getElementCount() == RHS.getElementCount();
+    }
+    return Info == RHS.Info && RawData == RHS.RawData;
   }
 
   constexpr bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
@@ -301,37 +481,33 @@ 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 : 4
+  /// RawData : 60
+  /// 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 ele...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Aug 23, 2025

@llvm/pr-subscribers-llvm-globalisel

Author: Denis.G (DenisGZM)

Changes

Added extra information in LLT to support ambiguous fp types during GlobalISel. Original idea by @tgymnich

Main differences from #122503 are:

  • Do not deprecate LLT::scalar
  • Allow targets to enable/disable IR translation with extenden LLT via TargetOption::EnableGlobalISelExtendedLLT (disabled by default)
  • IRTranslator use TargetLoweringInfo for appropriate LLT generation.
  • For this reason added flag in GlobalISelMatchTable` to allow switch between legacy and new extended LLT names
  • Revert using stubs like LLT::float32 for float types as they are real now. Added TODO for such cases.

Also MIRParser now may parse new type indetifiers.


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

50 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/Analysis.h (+2-1)
  • (modified) llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h (+2)
  • (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/LowLevelTypeUtils.h (+3-3)
  • (modified) llvm/include/llvm/CodeGen/TargetLowering.h (+3)
  • (modified) llvm/include/llvm/CodeGenTypes/LowLevelType.h (+275-99)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+1)
  • (modified) llvm/include/llvm/Target/TargetOptions.h (+6-1)
  • (modified) llvm/lib/CodeGen/Analysis.cpp (+5-5)
  • (modified) llvm/lib/CodeGen/GlobalISel/CallLowering.cpp (+7-6)
  • (modified) llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp (+46-41)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizeMutations.cpp (+2-4)
  • (modified) llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp (+2-1)
  • (modified) llvm/lib/CodeGen/LowLevelTypeUtils.cpp (+71-16)
  • (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+78-37)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/TargetLoweringBase.cpp (+8)
  • (modified) llvm/lib/CodeGenTypes/LowLevelType.cpp (+65-14)
  • (modified) llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp (+2-2)
  • (modified) llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp (+3-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp (+5-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp (+9-8)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid0.mir (+2-2)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid1.mir (+2-2)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid2.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid3.mir (+3-3)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err0.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err1.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-err11.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err12.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err13.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err14.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err15.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err2.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err3.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err4.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err5.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err6.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err7.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 (+2-2)
  • (modified) llvm/test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir (+2-2)
  • (modified) llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt (+1)
  • (added) llvm/unittests/CodeGen/GlobalISel/IRTranslatorBF16Test.cpp (+130)
  • (modified) llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp (+8-6)
  • (modified) llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp (+70-9)
diff --git a/llvm/include/llvm/CodeGen/Analysis.h b/llvm/include/llvm/CodeGen/Analysis.h
index 98b52579d03b7..2aadc27930b7a 100644
--- a/llvm/include/llvm/CodeGen/Analysis.h
+++ b/llvm/include/llvm/CodeGen/Analysis.h
@@ -101,7 +101,8 @@ inline void ComputeValueVTs(const TargetLowering &TLI, const DataLayout &DL,
 /// If Offsets is non-null, it points to a vector to be filled in
 /// with the in-memory offsets of each of the individual values.
 ///
-void computeValueLLTs(const DataLayout &DL, Type &Ty,
+void computeValueLLTs(const TargetLowering &TLI,
+                      const DataLayout &DL, Type &Ty,
                       SmallVectorImpl<LLT> &ValueTys,
                       SmallVectorImpl<uint64_t> *Offsets = nullptr,
                       uint64_t StartingOffset = 0);
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index 3d7ccd55ee042..5673fd5168477 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -642,6 +642,8 @@ class IRTranslator : public MachineFunctionPass {
 
   StackProtectorDescriptor SPDescriptor;
 
+  bool mayTranslateUserTypes(const User &U) const;
+
   /// Switch analysis and optimization.
   class GISelSwitchLowering : public SwitchCG::SwitchLowering {
   public:
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index fd72a3898562e..8412042a780e8 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -380,7 +380,7 @@ LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx,
 
 /// Keep the same scalar or element type as \p TypeIdx, but take the number of
 /// elements from \p Ty.
-LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx, LLT Ty);
+LLVM_ABI 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 51a298eb8b247..1c8f34b1a8518 100644
--- a/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
+++ b/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
@@ -27,7 +27,7 @@ class Type;
 struct fltSemantics;
 
 /// Construct a low-level type based on an LLVM type.
-LLVM_ABI LLT getLLTForType(Type &Ty, const DataLayout &DL);
+LLVM_ABI LLT getLLTForType(Type &Ty, const DataLayout &DL, bool AllowExtendedLLT = false);
 
 /// Get a rough equivalent of an MVT for a given LLT. MVT can't distinguish
 /// pointers, so these will convert to a plain integer.
@@ -36,11 +36,11 @@ LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx);
 
 /// Get a rough equivalent of an LLT for a given MVT. LLT does not yet support
 /// scalarable vector types, and will assert if used.
-LLVM_ABI LLT getLLTForMVT(MVT Ty);
+LLVM_ABI LLT getLLTForMVT(MVT Ty, bool AllowExtendedLLT = false);
 
 /// Get the appropriate floating point arithmetic semantic based on the bit size
 /// of the given scalar LLT.
 LLVM_ABI const llvm::fltSemantics &getFltSemanticForLLT(LLT Ty);
-}
+} // namespace llvm
 
 #endif // LLVM_CODEGEN_LOWLEVELTYPEUTILS_H
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 4480ced637456..f4fdd8c69ea9e 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -416,6 +416,9 @@ class LLVM_ABI TargetLoweringBase {
   /// amounts, returns MVT::i32.
   EVT getShiftAmountTy(EVT LHSTy, const DataLayout &DL) const;
 
+  virtual LLT getLLTForType(Type &Ty, const DataLayout &DL) const;
+  virtual LLT getLLTForMVT(MVT Ty) const;
+
   /// Return the preferred type to use for a shift opcode, given the shifted
   /// amount type is \p ShiftValueTy.
   LLVM_READONLY
diff --git a/llvm/include/llvm/CodeGenTypes/LowLevelType.h b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
index d8e0848aff84d..0c217ba1fcf7e 100644
--- a/llvm/include/llvm/CodeGenTypes/LowLevelType.h
+++ b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
@@ -39,68 +39,148 @@ class raw_ostream;
 
 class LLT {
 public:
+  enum class FPVariant {
+    IEEE_FLOAT = 0x0,
+    BRAIN_FLOAT = 0x1,     // BRAIN_FLOAT
+    PPC128_FLOAT = 0x2,    // PPC128_FLOAT
+    EXTENDED_FP80 = 0x3,   // FP80
+    TENSOR_FLOAT32 = 0x4,  // TENSOR_FLOAT32
+    VARIANT_FLOAT_5 = 0x5, // UNASSIGNED
+    VARIANT_FLOAT_6 = 0x6, // UNASSIGNED
+    VARIANT_FLOAT_7 = 0x7, // UNASSIGNED
+  };
+
+  enum class Kind : uint64_t {
+    INVALID = 0b0000,
+    ANY_SCALAR = 0b0001,
+    INTEGER = 0b0010,
+    FLOAT = 0b0011,
+    POINTER = 0b0100,
+    VECTOR_ANY = 0b0101,
+    VECTOR_INTEGER = 0b0110,
+    VECTOR_FLOAT = 0b0111,
+    VECTOR_POINTER = 0b1000,
+  };
+
+  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;
+
+    return Kind::VECTOR_ANY;
+  }
+
+  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;
+
+    return Kind::ANY_SCALAR;
+  }
+
   /// Get a low-level scalar or aggregate "bag of bits".
   static constexpr LLT scalar(unsigned SizeInBits) {
-    return LLT{/*isPointer=*/false, /*isVector=*/false, /*isScalar=*/true,
-               ElementCount::getFixed(0), SizeInBits,
-               /*AddressSpace=*/0};
+    return LLT{Kind::ANY_SCALAR, 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),
+    return LLT{Kind::ANY_SCALAR, ElementCount::getFixed(0),
                /*SizeInBits=*/0,
-               /*AddressSpace=*/0};
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
   }
 
   /// 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.
   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_ANY, 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::EXTENDED_FP80);
+  }
+
+  /// 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::PPC128_FLOAT);
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
   /// width.
-  static constexpr LLT fixed_vector(unsigned NumElements,
-                                    unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getFixed(NumElements), ScalarSizeInBits);
+  static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits) {
+    return vector(ElementCount::getFixed(NumElements),
+                  LLT::scalar(ScalarSizeInBits));
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
@@ -111,9 +191,9 @@ class LLT {
 
   /// Get a low-level scalable vector of some number of elements and element
   /// width.
-  static constexpr LLT scalable_vector(unsigned MinNumElements,
-                                       unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getScalable(MinNumElements), ScalarSizeInBits);
+  static constexpr LLT scalable_vector(unsigned MinNumElements, unsigned ScalarSizeInBits) {
+    return vector(ElementCount::getScalable(MinNumElements),
+                  LLT::scalar(ScalarSizeInBits));
   }
 
   /// Get a low-level scalable vector of some number of elements and element
@@ -132,27 +212,79 @@ class LLT {
     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) {}
 
-  LLVM_ABI explicit LLT(MVT VT);
+  LLVM_ABI explicit LLT(MVT VT, bool AllowExtendedLLT = false);
+  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 Info == Kind::ANY_SCALAR || Info == Kind::INTEGER || Info == Kind::FLOAT; }
+  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::EXTENDED_FP80);
+  }
+  constexpr bool isPPCF128() const {
+    return isVariantFloat(128, FPVariant::PPC128_FLOAT);
+  }
+  constexpr bool isToken() const {
+    return Info == Kind::ANY_SCALAR && RawData == 0;
+  }
+  constexpr bool isAnyScalar() const {
+    return isValid() && Info == Kind::ANY_SCALAR;
+  }
+  constexpr bool isVectorAny() const {
+    return isVector() && Info == Kind::VECTOR_ANY;
+  }
+  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_ANY || Info == Kind::VECTOR_INTEGER||
+            Info == Kind::VECTOR_FLOAT || Info == Kind::VECTOR_POINTER);
+  }
   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
@@ -177,12 +309,18 @@ class LLT {
   /// if the LLT is not a vector type.
   constexpr bool isFixedVector() const { return isVector() && !isScalable(); }
 
+  constexpr bool isFixedVector(unsigned NumElements,
+                               unsigned ScalarSize) const {
+    return isFixedVector() && getNumElements() == NumElements &&
+           getScalarSizeInBits() == ScalarSize;
+  }
+
   /// Returns true if the LLT is a scalable vector. Returns false otherwise,
   /// even if the LLT is not a vector type.
   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());
   }
@@ -207,6 +345,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 {
@@ -217,10 +364,14 @@ 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(), getElementType().isInteger()
+                                                    ? LLT::integer(NewEltSize)
+                                                    : LLT::scalar(NewEltSize))
+           : isInteger() ? LLT::integer(NewEltSize)
+                         : LLT::scalar(NewEltSize);
   }
 
   /// Return a vector or scalar with the same element type and the new element
@@ -229,6 +380,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.
@@ -243,6 +398,9 @@ class LLT {
     }
 
     assert(getScalarSizeInBits() % Factor == 0);
+    if (isInteger())
+      return integer(getScalarSizeInBits() / Factor);
+
     return scalar(getScalarSizeInBits() / Factor);
   }
 
@@ -277,10 +435,26 @@ 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());
+
+    if (isIntegerVector())
+      return integer(getScalarSizeInBits());
+
+    return scalar(getScalarSizeInBits());
+  }
+
+  constexpr LLT changeToInteger() const {
+    if (isPointer() || isPointerVector())
+      return *this;
+
+    if (isVector())
+      return vector(getElementCount(), LLT::integer(getScalarSizeInBits()));
+
+    return integer(getSizeInBits());
   }
 
   LLVM_ABI void print(raw_ostream &OS) const;
@@ -290,8 +464,14 @@ class LLT {
 #endif
 
   constexpr bool operator==(const LLT &RHS) const {
-    return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
-           IsScalar == RHS.IsScalar && RHS.RawData == RawData;
+    if (isAnyScalar() || RHS.isAnyScalar()) {
+      return isScalar() == RHS.isScalar() && RawData == RHS.RawData;
+    }
+    if (isVector() && RHS.isVector()) {
+      return getElementType() == RHS.getElementType() &&
+             getElementCount() == RHS.getElementCount();
+    }
+    return Info == RHS.Info && RawData == RHS.RawData;
   }
 
   constexpr bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
@@ -301,37 +481,33 @@ 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 : 4
+  /// RawData : 60
+  /// 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 ele...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Aug 23, 2025

@llvm/pr-subscribers-backend-aarch64

Author: Denis.G (DenisGZM)

Changes

Added extra information in LLT to support ambiguous fp types during GlobalISel. Original idea by @tgymnich

Main differences from #122503 are:

  • Do not deprecate LLT::scalar
  • Allow targets to enable/disable IR translation with extenden LLT via TargetOption::EnableGlobalISelExtendedLLT (disabled by default)
  • IRTranslator use TargetLoweringInfo for appropriate LLT generation.
  • For this reason added flag in GlobalISelMatchTable` to allow switch between legacy and new extended LLT names
  • Revert using stubs like LLT::float32 for float types as they are real now. Added TODO for such cases.

Also MIRParser now may parse new type indetifiers.


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

50 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/Analysis.h (+2-1)
  • (modified) llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h (+2)
  • (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h (+1-1)
  • (modified) llvm/include/llvm/CodeGen/LowLevelTypeUtils.h (+3-3)
  • (modified) llvm/include/llvm/CodeGen/TargetLowering.h (+3)
  • (modified) llvm/include/llvm/CodeGenTypes/LowLevelType.h (+275-99)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+1)
  • (modified) llvm/include/llvm/Target/TargetOptions.h (+6-1)
  • (modified) llvm/lib/CodeGen/Analysis.cpp (+5-5)
  • (modified) llvm/lib/CodeGen/GlobalISel/CallLowering.cpp (+7-6)
  • (modified) llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp (+46-41)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizeMutations.cpp (+2-4)
  • (modified) llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp (+1-1)
  • (modified) llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp (+2-1)
  • (modified) llvm/lib/CodeGen/LowLevelTypeUtils.cpp (+71-16)
  • (modified) llvm/lib/CodeGen/MIRParser/MIParser.cpp (+78-37)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/TargetLoweringBase.cpp (+8)
  • (modified) llvm/lib/CodeGenTypes/LowLevelType.cpp (+65-14)
  • (modified) llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp (+2-2)
  • (modified) llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp (+3-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp (+5-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp (+9-8)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid0.mir (+2-2)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid1.mir (+2-2)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid2.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/AArch64/parse-low-level-type-invalid3.mir (+3-3)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err0.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err1.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-err11.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err12.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err13.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err14.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err15.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err2.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err3.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err4.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err5.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err6.mir (+1-1)
  • (modified) llvm/test/CodeGen/MIR/Generic/scalable-vector-type-err7.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 (+2-2)
  • (modified) llvm/test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir (+2-2)
  • (modified) llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt (+1)
  • (added) llvm/unittests/CodeGen/GlobalISel/IRTranslatorBF16Test.cpp (+130)
  • (modified) llvm/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp (+8-6)
  • (modified) llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp (+70-9)
diff --git a/llvm/include/llvm/CodeGen/Analysis.h b/llvm/include/llvm/CodeGen/Analysis.h
index 98b52579d03b7..2aadc27930b7a 100644
--- a/llvm/include/llvm/CodeGen/Analysis.h
+++ b/llvm/include/llvm/CodeGen/Analysis.h
@@ -101,7 +101,8 @@ inline void ComputeValueVTs(const TargetLowering &TLI, const DataLayout &DL,
 /// If Offsets is non-null, it points to a vector to be filled in
 /// with the in-memory offsets of each of the individual values.
 ///
-void computeValueLLTs(const DataLayout &DL, Type &Ty,
+void computeValueLLTs(const TargetLowering &TLI,
+                      const DataLayout &DL, Type &Ty,
                       SmallVectorImpl<LLT> &ValueTys,
                       SmallVectorImpl<uint64_t> *Offsets = nullptr,
                       uint64_t StartingOffset = 0);
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index 3d7ccd55ee042..5673fd5168477 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -642,6 +642,8 @@ class IRTranslator : public MachineFunctionPass {
 
   StackProtectorDescriptor SPDescriptor;
 
+  bool mayTranslateUserTypes(const User &U) const;
+
   /// Switch analysis and optimization.
   class GISelSwitchLowering : public SwitchCG::SwitchLowering {
   public:
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index fd72a3898562e..8412042a780e8 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -380,7 +380,7 @@ LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx,
 
 /// Keep the same scalar or element type as \p TypeIdx, but take the number of
 /// elements from \p Ty.
-LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx, LLT Ty);
+LLVM_ABI 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 51a298eb8b247..1c8f34b1a8518 100644
--- a/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
+++ b/llvm/include/llvm/CodeGen/LowLevelTypeUtils.h
@@ -27,7 +27,7 @@ class Type;
 struct fltSemantics;
 
 /// Construct a low-level type based on an LLVM type.
-LLVM_ABI LLT getLLTForType(Type &Ty, const DataLayout &DL);
+LLVM_ABI LLT getLLTForType(Type &Ty, const DataLayout &DL, bool AllowExtendedLLT = false);
 
 /// Get a rough equivalent of an MVT for a given LLT. MVT can't distinguish
 /// pointers, so these will convert to a plain integer.
@@ -36,11 +36,11 @@ LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx);
 
 /// Get a rough equivalent of an LLT for a given MVT. LLT does not yet support
 /// scalarable vector types, and will assert if used.
-LLVM_ABI LLT getLLTForMVT(MVT Ty);
+LLVM_ABI LLT getLLTForMVT(MVT Ty, bool AllowExtendedLLT = false);
 
 /// Get the appropriate floating point arithmetic semantic based on the bit size
 /// of the given scalar LLT.
 LLVM_ABI const llvm::fltSemantics &getFltSemanticForLLT(LLT Ty);
-}
+} // namespace llvm
 
 #endif // LLVM_CODEGEN_LOWLEVELTYPEUTILS_H
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 4480ced637456..f4fdd8c69ea9e 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -416,6 +416,9 @@ class LLVM_ABI TargetLoweringBase {
   /// amounts, returns MVT::i32.
   EVT getShiftAmountTy(EVT LHSTy, const DataLayout &DL) const;
 
+  virtual LLT getLLTForType(Type &Ty, const DataLayout &DL) const;
+  virtual LLT getLLTForMVT(MVT Ty) const;
+
   /// Return the preferred type to use for a shift opcode, given the shifted
   /// amount type is \p ShiftValueTy.
   LLVM_READONLY
diff --git a/llvm/include/llvm/CodeGenTypes/LowLevelType.h b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
index d8e0848aff84d..0c217ba1fcf7e 100644
--- a/llvm/include/llvm/CodeGenTypes/LowLevelType.h
+++ b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
@@ -39,68 +39,148 @@ class raw_ostream;
 
 class LLT {
 public:
+  enum class FPVariant {
+    IEEE_FLOAT = 0x0,
+    BRAIN_FLOAT = 0x1,     // BRAIN_FLOAT
+    PPC128_FLOAT = 0x2,    // PPC128_FLOAT
+    EXTENDED_FP80 = 0x3,   // FP80
+    TENSOR_FLOAT32 = 0x4,  // TENSOR_FLOAT32
+    VARIANT_FLOAT_5 = 0x5, // UNASSIGNED
+    VARIANT_FLOAT_6 = 0x6, // UNASSIGNED
+    VARIANT_FLOAT_7 = 0x7, // UNASSIGNED
+  };
+
+  enum class Kind : uint64_t {
+    INVALID = 0b0000,
+    ANY_SCALAR = 0b0001,
+    INTEGER = 0b0010,
+    FLOAT = 0b0011,
+    POINTER = 0b0100,
+    VECTOR_ANY = 0b0101,
+    VECTOR_INTEGER = 0b0110,
+    VECTOR_FLOAT = 0b0111,
+    VECTOR_POINTER = 0b1000,
+  };
+
+  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;
+
+    return Kind::VECTOR_ANY;
+  }
+
+  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;
+
+    return Kind::ANY_SCALAR;
+  }
+
   /// Get a low-level scalar or aggregate "bag of bits".
   static constexpr LLT scalar(unsigned SizeInBits) {
-    return LLT{/*isPointer=*/false, /*isVector=*/false, /*isScalar=*/true,
-               ElementCount::getFixed(0), SizeInBits,
-               /*AddressSpace=*/0};
+    return LLT{Kind::ANY_SCALAR, 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),
+    return LLT{Kind::ANY_SCALAR, ElementCount::getFixed(0),
                /*SizeInBits=*/0,
-               /*AddressSpace=*/0};
+               /*AddressSpace=*/0, static_cast<FPVariant>(0)};
   }
 
   /// 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.
   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_ANY, 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::EXTENDED_FP80);
+  }
+
+  /// 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::PPC128_FLOAT);
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
   /// width.
-  static constexpr LLT fixed_vector(unsigned NumElements,
-                                    unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getFixed(NumElements), ScalarSizeInBits);
+  static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits) {
+    return vector(ElementCount::getFixed(NumElements),
+                  LLT::scalar(ScalarSizeInBits));
   }
 
   /// Get a low-level fixed-width vector of some number of elements and element
@@ -111,9 +191,9 @@ class LLT {
 
   /// Get a low-level scalable vector of some number of elements and element
   /// width.
-  static constexpr LLT scalable_vector(unsigned MinNumElements,
-                                       unsigned ScalarSizeInBits) {
-    return vector(ElementCount::getScalable(MinNumElements), ScalarSizeInBits);
+  static constexpr LLT scalable_vector(unsigned MinNumElements, unsigned ScalarSizeInBits) {
+    return vector(ElementCount::getScalable(MinNumElements),
+                  LLT::scalar(ScalarSizeInBits));
   }
 
   /// Get a low-level scalable vector of some number of elements and element
@@ -132,27 +212,79 @@ class LLT {
     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) {}
 
-  LLVM_ABI explicit LLT(MVT VT);
+  LLVM_ABI explicit LLT(MVT VT, bool AllowExtendedLLT = false);
+  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 Info == Kind::ANY_SCALAR || Info == Kind::INTEGER || Info == Kind::FLOAT; }
+  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::EXTENDED_FP80);
+  }
+  constexpr bool isPPCF128() const {
+    return isVariantFloat(128, FPVariant::PPC128_FLOAT);
+  }
+  constexpr bool isToken() const {
+    return Info == Kind::ANY_SCALAR && RawData == 0;
+  }
+  constexpr bool isAnyScalar() const {
+    return isValid() && Info == Kind::ANY_SCALAR;
+  }
+  constexpr bool isVectorAny() const {
+    return isVector() && Info == Kind::VECTOR_ANY;
+  }
+  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_ANY || Info == Kind::VECTOR_INTEGER||
+            Info == Kind::VECTOR_FLOAT || Info == Kind::VECTOR_POINTER);
+  }
   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
@@ -177,12 +309,18 @@ class LLT {
   /// if the LLT is not a vector type.
   constexpr bool isFixedVector() const { return isVector() && !isScalable(); }
 
+  constexpr bool isFixedVector(unsigned NumElements,
+                               unsigned ScalarSize) const {
+    return isFixedVector() && getNumElements() == NumElements &&
+           getScalarSizeInBits() == ScalarSize;
+  }
+
   /// Returns true if the LLT is a scalable vector. Returns false otherwise,
   /// even if the LLT is not a vector type.
   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());
   }
@@ -207,6 +345,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 {
@@ -217,10 +364,14 @@ 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(), getElementType().isInteger()
+                                                    ? LLT::integer(NewEltSize)
+                                                    : LLT::scalar(NewEltSize))
+           : isInteger() ? LLT::integer(NewEltSize)
+                         : LLT::scalar(NewEltSize);
   }
 
   /// Return a vector or scalar with the same element type and the new element
@@ -229,6 +380,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.
@@ -243,6 +398,9 @@ class LLT {
     }
 
     assert(getScalarSizeInBits() % Factor == 0);
+    if (isInteger())
+      return integer(getScalarSizeInBits() / Factor);
+
     return scalar(getScalarSizeInBits() / Factor);
   }
 
@@ -277,10 +435,26 @@ 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());
+
+    if (isIntegerVector())
+      return integer(getScalarSizeInBits());
+
+    return scalar(getScalarSizeInBits());
+  }
+
+  constexpr LLT changeToInteger() const {
+    if (isPointer() || isPointerVector())
+      return *this;
+
+    if (isVector())
+      return vector(getElementCount(), LLT::integer(getScalarSizeInBits()));
+
+    return integer(getSizeInBits());
   }
 
   LLVM_ABI void print(raw_ostream &OS) const;
@@ -290,8 +464,14 @@ class LLT {
 #endif
 
   constexpr bool operator==(const LLT &RHS) const {
-    return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
-           IsScalar == RHS.IsScalar && RHS.RawData == RawData;
+    if (isAnyScalar() || RHS.isAnyScalar()) {
+      return isScalar() == RHS.isScalar() && RawData == RHS.RawData;
+    }
+    if (isVector() && RHS.isVector()) {
+      return getElementType() == RHS.getElementType() &&
+             getElementCount() == RHS.getElementCount();
+    }
+    return Info == RHS.Info && RawData == RHS.RawData;
   }
 
   constexpr bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
@@ -301,37 +481,33 @@ 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 : 4
+  /// RawData : 60
+  /// 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 ele...
[truncated]

@github-actions
Copy link

github-actions bot commented Aug 23, 2025

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

@DenisGZM
Copy link
Contributor Author

@aemerson @arsenm could you please take a look at this patch. Saw you discussed on llvm discourse about changes in LLT, so would be nice to hear your thoughts on this

@DenisGZM DenisGZM changed the title [GlobalISel][LLT] Introduce FPInfo for LLT [GlobalISel][LLT] Introduce FPInfo for LLT (Enable bfloat, ppc128float and others in GlobalISel) Sep 1, 2025
@K-Wu
Copy link
Member

K-Wu commented Oct 20, 2025

I once contributed to LLVM for a few months, and I recall the check-in process is like when you get enough number of approvals, it is good to be checked in. Given that this is an important feature that will unblock many downstream backends, can it be checked in now?

If you still believe @arsenm review is necessary, I will write an email to them.

@DenisGZM
Copy link
Contributor Author

If you still believe @arsenm review is necessary, I will write an email to them.

Yes, please. I think any fresh look would be helpful. I don't mind landing this, but the final decision is up to maintainers

@K-Wu
Copy link
Member

K-Wu commented Oct 23, 2025

Hi @aemerson , @tgymnich , @Pierre-vh , @DenisGZM ,

I sent an email to @arsenm two days ago but didn't get reply yet. Is there an alternate reviewer who can do the final approval?

@HolyMolyCowMan
Copy link
Contributor

I have started attempting to use these changes and I think there is an issue preventing this from compiling.

When I try to compile I get the following:

ld.lld: error: undefined symbol: llvm::LLT::LLT(llvm::MVT, bool)
>>> referenced by GlobalISelMatchTable.cpp
>>>               utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/GlobalISel/GlobalISelMatchTable.cpp.o:(llvm::gi::MVTToLLT(llvm::MVT::SimpleValueType) (.localalias))

I believe this is because the CMAKE in llvm/utils/TableGen/Common/CMakeLists.txt doesn't include CodeGenTypes as a dependency.

@DenisGZM
Copy link
Contributor Author

I have started attempting to use these changes and I think there is an issue preventing this from compiling.

When I try to compile I get the following:

ld.lld: error: undefined symbol: llvm::LLT::LLT(llvm::MVT, bool)
>>> referenced by GlobalISelMatchTable.cpp
>>>               utils/TableGen/Common/CMakeFiles/obj.LLVMTableGenCommon.dir/GlobalISel/GlobalISelMatchTable.cpp.o:(llvm::gi::MVTToLLT(llvm::MVT::SimpleValueType) (.localalias))

I believe this is because the CMAKE in llvm/utils/TableGen/Common/CMakeLists.txt doesn't include CodeGenTypes as a dependency.

Added linking

@DenisGZM DenisGZM closed this Oct 30, 2025
@DenisGZM DenisGZM reopened this Oct 30, 2025
@Endilll Endilll removed their request for review October 30, 2025 13:36
@HolyMolyCowMan
Copy link
Contributor

Hi,

I was wondering if you had any thoughts on an issue I'm encountering downstream of this patch. A lot of tablegen patterns that used to just rely on size, now care about type as well.

This is causing a lot of tests to fail in the AArch64 backend as these patterns are no longer matching and thus aren't selected. Whilst I could attempt to duplicate these patterns it would be nice if we could continue to use shared patterns & patterns from SDAG.

I'm wondering if we need some kind of machinery to compare only by size when comparing a generic scalar type in the match table? Maybe this should be the case more generally too (for example when comparing an s32 with an fp32)?

@DenisGZM
Copy link
Contributor Author

DenisGZM commented Nov 11, 2025

I was wondering if you had any thoughts on an issue I'm encountering downstream of this patch. A lot of tablegen patterns that used to just rely on size, now care about type as well.

This is causing a lot of tests to fail in the AArch64 backend as these patterns are no longer matching and thus aren't selected. Whilst I could attempt to duplicate these patterns it would be nice if we could continue to use shared patterns & patterns from SDAG.

I haven't tried to support this so far. I'll try to explore this issue asap. I think we definitely shouldn't duplicate patterns, but we may have to ensure we legalized new LLT types before selection.

I'm wondering if we need some kind of machinery to compare only by size when comparing a generic scalar type in the match table? Maybe this should be the case more generally too (for example when comparing an s32 with an fp32)?

Right now, compares (==) with scalar (new kind ANY_SCALAR) are processed only by size. I will check if tables could properly use it

@HolyMolyCowMan
Copy link
Contributor

Thank you for your thoughts and help.

I think we definitely shouldn't duplicate patterns, but we may have to ensure we legalized new LLT types before selection.

All types should be legal before selection right? So I imagine you can operate on the assumption that any backend wanting to enable this will have gone through the efforts to legalize these types.

Right now, compares (==) with scalar (new kind ANY_SCALAR) are processed only by size.

If I understand correctly, the == operator for LLTs compares the raw data which I believe also compares type? The LLT == is used by the match table so this should help.

@DenisGZM
Copy link
Contributor Author

All types should be legal before selection right? So I imagine you can operate on the assumption that any backend wanting to enable this will have gone through the efforts to legalize these types.

I think not only types that comes from IRTranslator must be legal, but all other types are used during selection must also transform to more specific variants (integers, floating points). But I understand that it would be great if targets could continue use any_scalars.

If I understand correctly, the == operator for LLTs compares the raw data which I believe also compares type? The LLT == is used by the match table so this should help.

You're right, we would compare rawdata. RawData is separate from type, but for floating points it also contained FPVariant which would break comparison. In current patch I fixed this logic.

I checked GlobalISelMatcher after compare fix. I guess I found the main problem with it.

Let say:

  • We generated match tables with extended types
  • Instruction to match have anyscalar type operand "s32"

I this case we would like to apply any rule in either i32 or f32 groups. But as soon as we match the root type with any of them, we will abort the matching if the selection cannot be applied in the corresponding group.

As I see, if only use extended types with match tables generated for extended llt, this problem may be avoided. Or we need to update logic in MatchTableEmitter to allow continue matching.

@DenisGZM
Copy link
Contributor Author

I reworked FPVariants. Right now we rely on APFloat::Semantics to choose between different floating point variants.

  1. Size of fp LLT now derives from appropriate fp semantics
  2. We get rid of unreal types
  3. More clean and scalable solution for other custom fp types

Please, have a look once more
@HolyMolyCowMan @aemerson @tgymnich @Pierre-vh @arsenm @spavloff

Copy link
Member

@tgymnich tgymnich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few minor concerns with using APFloat::Semantics:
Using APFloat::Semantics couples LLT to APFloat::Semantics with a small chance that APFloat::Semantics might outgrow the 7-bits in LLT one day.
Additionally APFloat::Semantics does not currently represent all possible hardware floating point types (e.g. nvfp4).

I also have some reservations about having ANY_SCALAR and ANY_VECTOR kinds.
I assume it's ok to have them if we only use them in rules and forbid them as register types.

Overall this looks good to me and I want to see how this plays out once merged.

using namespace gi;

static cl::opt<bool>
AllowExtendedLLT("gisel-extended-llt",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this option is used only in one test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right. This is because the patch didn't mean to enable extended llt in all available targets. Target maintainers can decide if they want to support such changes and if they are ready for it.

Or the question is, why are there so few tests?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't unerstand how the target differentiation (supports extended LLT - does not support) works. If I want to enable ExtLLT in some target, what should do with TableGen?

Maybe it worth providing support in some target (SPIRV?) to demonstrate how this should work?

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.

10 participants