Skip to content

[CIR] Refactor IntType constraints #138106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

xlauko
Copy link
Contributor

@xlauko xlauko commented May 1, 2025

  • Adds CIR_ prefixes to integer type constraints types to disambiguate their names from other dialects.
  • Renames PrimitiveInt to CIR_AnyFundamentalIntType to align more with constrian conventions.
  • Adds bunch of helper constraint classes to be able to define base types to reduce clutter of necessary type casts.
  • Reworks constraints to use CIR_ConfinedType to avoid repeating validation checks.
  • Adds IntOfWidths variadic bitwidth constraint to reduce boilerplate code needed to handle multi-bitwidth parameters.
  • Constraints are moved into a separate file, which starts decoupling of constraints and types to remove the cyclic dependency between types and attributes and will eventually help fix several outstanding TODOs.

This mirrors incubator changes from llvm/clangir#1593

- Adds `CIR_` prefixes to integer type constraints types to disambiguate their names from other dialects.
- Renames `PrimitiveInt` to `CIR_AnyFundamentalIntType` to align more with constrian conventions.
- Adds bunch of helper constraint classes to be able to define base types to reduce clutter of necessary type casts.
- Reworks constraints to use `CIR_ConfinedType` to avoid repeating validation checks.
- Adds `IntOfWidths` variadic bitwidth constraint to reduce boilerplate code needed to handle multi-bitwidth parameters.
- Constraints are moved into a separate file, which starts decoupling of constraints and types to remove the cyclic dependency between types and attributes and will eventually help fix several outstanding TODOs.

This mirrors incubator changes from llvm/clangir#1593
@xlauko xlauko marked this pull request as ready for review May 1, 2025 10:33
@xlauko xlauko requested review from lanza and bcardosolopes as code owners May 1, 2025 10:33
@xlauko
Copy link
Contributor Author

xlauko commented May 1, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels May 1, 2025
@xlauko xlauko requested review from erichkeane and andykaylor May 1, 2025 10:33
@llvmbot
Copy link
Member

llvmbot commented May 1, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Henrich Lauko (xlauko)

Changes
  • Adds CIR_ prefixes to integer type constraints types to disambiguate their names from other dialects.
  • Renames PrimitiveInt to CIR_AnyFundamentalIntType to align more with constrian conventions.
  • Adds bunch of helper constraint classes to be able to define base types to reduce clutter of necessary type casts.
  • Reworks constraints to use CIR_ConfinedType to avoid repeating validation checks.
  • Adds IntOfWidths variadic bitwidth constraint to reduce boilerplate code needed to handle multi-bitwidth parameters.
  • Constraints are moved into a separate file, which starts decoupling of constraints and types to remove the cyclic dependency between types and attributes and will eventually help fix several outstanding TODOs.

This mirrors incubator changes from llvm/clangir#1593


Full diff: https://github.com/llvm/llvm-project/pull/138106.diff

7 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+5-1)
  • (added) clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td (+113)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.h (+8)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+11-65)
  • (modified) clang/include/clang/CIR/Dialect/IR/CMakeLists.txt (+6)
  • (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+10)
  • (modified) clang/lib/CIR/Dialect/IR/CMakeLists.txt (+1)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 8319364b9e5e3..4902cc134e50d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -254,7 +254,11 @@ def PtrStrideOp : CIR_Op<"ptr_stride",
     ```
   }];
 
-  let arguments = (ins CIR_PointerType:$base, PrimitiveInt:$stride);
+  let arguments = (ins
+    CIR_PointerType:$base,
+    CIR_AnyFundamentalIntType:$stride
+  );
+
   let results = (outs CIR_PointerType:$result);
 
   let assemblyFormat = [{
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
new file mode 100644
index 0000000000000..3b8cb20da8edb
--- /dev/null
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CIR dialect type constraints.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CIR_DIALECT_IR_CIRTYPECONSTRAINTS_TD
+#define CLANG_CIR_DIALECT_IR_CIRTYPECONSTRAINTS_TD
+
+include "mlir/IR/Constraints.td"
+include "mlir/IR/CommonTypeConstraints.td"
+
+class CIR_IsTypePred<code type> : CPred<"::mlir::isa<" # type # ">($_self)">;
+
+class CIR_TypeBase<code type, string summary = "">
+    : Type<CIR_IsTypePred<type>, summary, type>;
+
+class CIR_CastSelfToType<code type, Pred pred>
+    : SubstLeaves<"$_self", "::mlir::cast<" # type # ">($_self)", pred>;
+
+class CIR_CastedSelfsToType<code type, list<Pred> preds>
+    : And<!foreach(pred, preds, CIR_CastSelfToType<type, pred>)>;
+
+class CIR_ConfinedType<Type type, list<Pred> preds, string summary = "">
+    : Type<And<[type.predicate, CIR_CastedSelfsToType<type.cppType, preds>]>,
+         summary, type.cppType>;
+
+//===----------------------------------------------------------------------===//
+// IntType predicates
+//===----------------------------------------------------------------------===//
+
+def CIR_AnyIntType : CIR_TypeBase<"::cir::IntType", "integer type">;
+
+def CIR_AnyUIntType : CIR_ConfinedType<CIR_AnyIntType, [
+    CPred<"$_self.isUnsigned()">], "unsigned integer type">;
+
+def CIR_AnySIntType : CIR_ConfinedType<CIR_AnyIntType, [
+    CPred<"$_self.isSigned()">], "signed integer type">;
+
+class CIR_HasWidthPred<int width> : CPred<"$_self.getWidth() == " # width>;
+
+def CIR_HasFundamentalIntWidthPred
+    : CPred<"::cir::isValidFundamentalIntWidth($_self.getWidth())">;
+
+class CIR_IntOfWidthsPred<list<int> widths>
+    : Or<!foreach(width, widths, CIR_HasWidthPred<width>)>;
+
+class CIR_IntOfWidths<list<int> widths>
+    : CIR_ConfinedType<CIR_AnyIntType, [CIR_IntOfWidthsPred<widths>],
+        "integer type of widths " # !interleave(widths, "/")>;
+
+class CIR_SIntOfWidths<list<int> widths>
+    : CIR_ConfinedType<CIR_AnySIntType, [CIR_IntOfWidthsPred<widths>],
+        "signed integer type of widths " # !interleave(widths, "/")>;
+
+class CIR_UIntOfWidths<list<int> widths>
+    : CIR_ConfinedType<CIR_AnyUIntType, [CIR_IntOfWidthsPred<widths>],
+        "unsigned integer type of widths " # !interleave(widths, "/")>;
+
+class CIR_UInt<int width>
+    : CIR_ConfinedType<CIR_AnyUIntType, [CIR_HasWidthPred<width>],
+        width # "-bit unsigned integer">,
+      BuildableType<"$_builder.getType<" # cppType # ">(" #
+        width # ", /*isSigned=*/false)">;
+
+def CIR_UInt1 : CIR_UInt<1>;
+def CIR_UInt8 : CIR_UInt<8>;
+def CIR_UInt16 : CIR_UInt<16>;
+def CIR_UInt32 : CIR_UInt<32>;
+def CIR_UInt64 : CIR_UInt<64>;
+def CIR_UInt128 : CIR_UInt<128>;
+
+class CIR_SInt<int width>
+    : CIR_ConfinedType<CIR_AnySIntType, [CIR_HasWidthPred<width>],
+        width # "-bit signed integer">,
+      BuildableType<"$_builder.getType<" # cppType # ">(" #
+        width # ", /*isSigned=*/true)">;
+
+def CIR_SInt1 : CIR_SInt<1>;
+def CIR_SInt8 : CIR_SInt<8>;
+def CIR_SInt16 : CIR_SInt<16>;
+def CIR_SInt32 : CIR_SInt<32>;
+def CIR_SInt64 : CIR_SInt<64>;
+def CIR_SInt128 : CIR_SInt<128>;
+
+// Fundamental integer types represent standard source-level integer types that
+// have a specified set of admissible bitwidths (8, 16, 32, 64).
+
+def CIR_AnyFundamentalIntType
+    : CIR_ConfinedType<CIR_AnyIntType, [CIR_HasFundamentalIntWidthPred],
+        "fundamental integer type"> {
+    let cppFunctionName = "isFundamentalIntType";
+}
+
+def CIR_AnyFundamentalUIntType
+    : CIR_ConfinedType<CIR_AnyUIntType, [CIR_HasFundamentalIntWidthPred],
+        "fundamental unsigned integer type"> {
+    let cppFunctionName = "isFundamentalUIntType";
+}
+
+def CIR_AnyFundamentalSIntType
+    : CIR_ConfinedType<CIR_AnySIntType, [CIR_HasFundamentalIntWidthPred],
+        "fundamental signed integer type"> {
+    let cppFunctionName = "isFundamentalSIntType";
+}
+
+#endif // CLANG_CIR_DIALECT_IR_CIRTYPECONSTRAINTS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
index 074b8d07e0e80..2e32765c1e941 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -24,6 +24,8 @@ namespace detail {
 struct RecordTypeStorage;
 } // namespace detail
 
+bool isValidFundamentalIntWidth(unsigned width);
+
 bool isAnyFloatingPointType(mlir::Type t);
 bool isFPOrFPVectorTy(mlir::Type);
 
@@ -33,6 +35,12 @@ bool isFPOrFPVectorTy(mlir::Type);
 // CIR Dialect Tablegen'd Types
 //===----------------------------------------------------------------------===//
 
+namespace cir {
+
+#include "clang/CIR/Dialect/IR/CIRTypeConstraints.h.inc"
+
+} // namespace cir
+
 #define GET_TYPEDEF_CLASSES
 #include "clang/CIR/Dialect/IR/CIROpsTypes.h.inc"
 
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 6ca6fbeeb6165..d9f05c9aea63d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -14,6 +14,7 @@
 #define MLIR_CIR_DIALECT_CIR_TYPES
 
 include "clang/CIR/Dialect/IR/CIRDialect.td"
+include "clang/CIR/Dialect/IR/CIRTypeConstraints.td"
 include "clang/CIR/Interfaces/CIRFPTypeInterface.td"
 include "mlir/Interfaces/DataLayoutInterfaces.td"
 include "mlir/IR/AttrTypeBase.td"
@@ -41,7 +42,7 @@ def CIR_IntType : CIR_Type<"Int", "int",
     such as `__int128`, and arbitrary width types such as `_BitInt(n)`.
 
     Those integer types that are directly available in C/C++ standard are called
-    primitive integer types. Said types are: `signed char`, `short`, `int`,
+    fundamental integer types. Said types are: `signed char`, `short`, `int`,
     `long`, `long long`, and their unsigned variations.
   }];
   let parameters = (ins "unsigned":$width, "bool":$isSigned);
@@ -55,81 +56,26 @@ def CIR_IntType : CIR_Type<"Int", "int",
     std::string getAlias() const {
       return (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i';
     }
-    /// Return true if this is a primitive integer type (i.e. signed or unsigned
-    /// integer types whose bit width is 8, 16, 32, or 64).
-    bool isPrimitive() const {
-      return isValidPrimitiveIntBitwidth(getWidth());
+    /// Return true if this is a fundamental integer type (i.e. signed or
+    /// unsigned integer types whose bit width is 8, 16, 32, or 64).
+    bool isFundamental() const {
+      return isFundamentalIntType(*this);
     }
-    bool isSignedPrimitive() const {
-      return isPrimitive() && isSigned();
+    bool isSignedFundamental() const {
+      return isFundamentalSIntType(*this);
+    }
+    bool isUnsignedFundamental() const {
+      return isFundamentalUIntType(*this);
     }
 
     /// Returns a minimum bitwidth of cir::IntType
     static unsigned minBitwidth() { return 1; }
     /// Returns a maximum bitwidth of cir::IntType
     static unsigned maxBitwidth() { return 128; }
-
-    /// Returns true if cir::IntType that represents a primitive integer type
-    /// can be constructed from the provided bitwidth.
-    static bool isValidPrimitiveIntBitwidth(unsigned width) {
-      return width == 8 || width == 16 || width == 32 || width == 64;
-    }
   }];
   let genVerifyDecl = 1;
 }
 
-// Constraints
-
-// Unsigned integer type of a specific width.
-class UInt<int width>
-  : Type<And<[
-	CPred<"::mlir::isa<::cir::IntType>($_self)">,
-	CPred<"::mlir::cast<::cir::IntType>($_self).isUnsigned()">,
-	CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
-        ]>, width # "-bit unsigned integer", "::cir::IntType">,
-    BuildableType<
-      "cir::IntType::get($_builder.getContext(), "
-      # width # ", /*isSigned=*/false)"> {
-  int bitwidth = width;
-}
-
-def UInt1  : UInt<1>;
-def UInt8  : UInt<8>;
-def UInt16 : UInt<16>;
-def UInt32 : UInt<32>;
-def UInt64 : UInt<64>;
-
-// Signed integer type of a specific width.
-class SInt<int width>
-  : Type<And<[
-	CPred<"::mlir::isa<::cir::IntType>($_self)">,
-	CPred<"::mlir::cast<::cir::IntType>($_self).isSigned()">,
-	CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
-        ]>, width # "-bit signed integer", "::cir::IntType">,
-    BuildableType<
-      "cir::IntType::get($_builder.getContext(), "
-      # width # ", /*isSigned=*/true)"> {
-  int bitwidth = width;
-}
-
-def SInt1  : SInt<1>;
-def SInt8  : SInt<8>;
-def SInt16 : SInt<16>;
-def SInt32 : SInt<32>;
-def SInt64 : SInt<64>;
-
-def PrimitiveUInt
-    : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64], "primitive unsigned int",
-                "::cir::IntType">;
-
-def PrimitiveSInt
-    : AnyTypeOf<[SInt8, SInt16, SInt32, SInt64], "primitive signed int",
-                "::cir::IntType">;
-
-def PrimitiveInt
-    : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64],
-                "primitive int", "::cir::IntType">;
-
 //===----------------------------------------------------------------------===//
 // FloatType
 //===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
index 39292fb541daa..6e6d59ea5dadb 100644
--- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
@@ -19,3 +19,9 @@ mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
 mlir_tablegen(CIROpsEnums.h.inc -gen-enum-decls)
 mlir_tablegen(CIROpsEnums.cpp.inc -gen-enum-defs)
 add_public_tablegen_target(MLIRCIREnumsGen)
+
+set(LLVM_TARGET_DEFINITIONS CIRTypeConstraints.td)
+mlir_tablegen(CIRTypeConstraints.h.inc -gen-type-constraint-decls)
+mlir_tablegen(CIRTypeConstraints.cpp.inc -gen-type-constraint-defs)
+add_public_tablegen_target(MLIRCIRTypeConstraintsIncGen)
+add_dependencies(mlir-headers MLIRCIRTypeConstraintsIncGen)
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index ce85e48c4555e..7d960c21d7251 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -33,6 +33,12 @@ static void printFuncTypeParams(mlir::AsmPrinter &p,
 // Get autogenerated stuff
 //===----------------------------------------------------------------------===//
 
+namespace cir {
+
+#include "clang/CIR/Dialect/IR/CIRTypeConstraints.cpp.inc"
+
+} // namespace cir
+
 #define GET_TYPEDEF_CLASSES
 #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc"
 
@@ -424,6 +430,10 @@ IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
   return mlir::success();
 }
 
+bool cir::isValidFundamentalIntWidth(unsigned width) {
+  return width == 8 || width == 16 || width == 32 || width == 64;
+}
+
 //===----------------------------------------------------------------------===//
 // Floating-point type definitions
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index 97a530d8c76d6..e5256bf961f46 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -6,6 +6,7 @@ add_clang_library(MLIRCIR
 
   DEPENDS
   MLIRCIROpsIncGen
+  MLIRCIRTypeConstraintsIncGen
   MLIRCIREnumsGen
   MLIRCIROpInterfacesIncGen
   MLIRCIRLoopOpInterfaceIncGen

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

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

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants