Skip to content

[MLIR] Add support for int8/uint8 properties #145019

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 2 commits into
base: main
Choose a base branch
from

Conversation

joker-eph
Copy link
Collaborator

This patch is adding the ability to print a uint8_t/int8_t as an int instead of a char and demonstrate support for int8_t/uin8_t properties.

Fix #144993

@llvmbot llvmbot added mlir:core MLIR Core Infrastructure mlir mlir:ods labels Jun 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 20, 2025

@llvm/pr-subscribers-mlir-ods

@llvm/pr-subscribers-mlir-core

Author: Mehdi Amini (joker-eph)

Changes

This patch is adding the ability to print a uint8_t/int8_t as an int instead of a char and demonstrate support for int8_t/uin8_t properties.

Fix #144993


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

6 Files Affected:

  • (modified) mlir/include/mlir/IR/ODSSupport.h (+20)
  • (modified) mlir/include/mlir/IR/OpImplementation.h (+13)
  • (modified) mlir/include/mlir/IR/Properties.td (+1)
  • (modified) mlir/lib/IR/ODSSupport.cpp (+34)
  • (modified) mlir/test/IR/properties.mlir (+8-2)
  • (modified) mlir/test/lib/Dialect/Test/TestOps.td (+4)
diff --git a/mlir/include/mlir/IR/ODSSupport.h b/mlir/include/mlir/IR/ODSSupport.h
index 25d6f3da6a861..b24a2470470ff 100644
--- a/mlir/include/mlir/IR/ODSSupport.h
+++ b/mlir/include/mlir/IR/ODSSupport.h
@@ -43,6 +43,26 @@ convertFromAttribute(int32_t &storage, Attribute attr,
 /// Convert the provided int32_t to an IntegerAttr attribute.
 Attribute convertToAttribute(MLIRContext *ctx, int32_t storage);
 
+/// Convert an IntegerAttr attribute to an int8_t, or return an error if the
+/// attribute isn't an IntegerAttr. If the optional diagnostic is provided an
+/// error message is also emitted.
+LogicalResult
+convertFromAttribute(int8_t &storage, Attribute attr,
+                     function_ref<InFlightDiagnostic()> emitError);
+
+/// Convert the provided int8_t to an IntegerAttr attribute.
+Attribute convertToAttribute(MLIRContext *ctx, int8_t storage);
+
+/// Convert an IntegerAttr attribute to an uint8_t, or return an error if the
+/// attribute isn't an IntegerAttr. If the optional diagnostic is provided an
+/// error message is also emitted.
+LogicalResult
+convertFromAttribute(uint8_t &storage, Attribute attr,
+                     function_ref<InFlightDiagnostic()> emitError);
+
+/// Convert the provided uint8_t to an IntegerAttr attribute.
+Attribute convertToAttribute(MLIRContext *ctx, uint8_t storage);
+
 /// Extract the string from `attr` into `storage`. If `attr` is not a
 /// `StringAttr`, return failure and emit an error into the diagnostic from
 /// `emitError`.
diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index 8b56d81c8eecc..8710b970e8d75 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -135,6 +135,19 @@ class AsmPrinter {
   /// hook on the AsmParser.
   virtual void printFloat(const APFloat &value);
 
+  /// Print the given integer value. This is useful to force a uint8_t/int8_t to
+  /// be printed as an integer instead of a char.
+  template <typename IntT>
+  std::enable_if_t<std::is_integral_v<IntT>, void> printInteger(IntT value) {
+    // Handle int8_t/uint8_t specially to avoid printing as char
+    if constexpr (std::is_same_v<IntT, int8_t> ||
+                  std::is_same_v<IntT, uint8_t>) {
+      getStream() << static_cast<int>(value);
+    } else {
+      getStream() << value;
+    }
+  }
+
   virtual void printType(Type type);
   virtual void printAttribute(Attribute attr);
 
diff --git a/mlir/include/mlir/IR/Properties.td b/mlir/include/mlir/IR/Properties.td
index 25a45489c7b53..1aa19d0ecfa3a 100644
--- a/mlir/include/mlir/IR/Properties.td
+++ b/mlir/include/mlir/IR/Properties.td
@@ -219,6 +219,7 @@ class IntProp<string storageTypeParam, string desc = ""> :
   let optionalParser = [{
     return $_parser.parseOptionalInteger($_storage);
   }];
+  let printer = "$_printer.printInteger($_storage)";
   let writeToMlirBytecode = [{
     $_writer.writeVarInt($_storage);
   }];
diff --git a/mlir/lib/IR/ODSSupport.cpp b/mlir/lib/IR/ODSSupport.cpp
index d56c75ede9849..b8bad1f1b098f 100644
--- a/mlir/lib/IR/ODSSupport.cpp
+++ b/mlir/lib/IR/ODSSupport.cpp
@@ -48,6 +48,40 @@ Attribute mlir::convertToAttribute(MLIRContext *ctx, int32_t storage) {
   return IntegerAttr::get(IntegerType::get(ctx, 32), storage);
 }
 
+LogicalResult
+mlir::convertFromAttribute(int8_t &storage, Attribute attr,
+                           function_ref<InFlightDiagnostic()> emitError) {
+  auto valueAttr = dyn_cast<IntegerAttr>(attr);
+  if (!valueAttr) {
+    emitError() << "expected IntegerAttr for key `value`";
+    return failure();
+  }
+  storage = valueAttr.getValue().getZExtValue();
+  return success();
+}
+
+Attribute mlir::convertToAttribute(MLIRContext *ctx, int8_t storage) {
+  /// Convert the provided int8_t to an IntegerAttr attribute.
+  return IntegerAttr::get(IntegerType::get(ctx, 8), storage);
+}
+
+LogicalResult
+mlir::convertFromAttribute(uint8_t &storage, Attribute attr,
+                           function_ref<InFlightDiagnostic()> emitError) {
+  auto valueAttr = dyn_cast<IntegerAttr>(attr);
+  if (!valueAttr) {
+    emitError() << "expected IntegerAttr for key `value`";
+    return failure();
+  }
+  storage = valueAttr.getValue().getZExtValue();
+  return success();
+}
+
+Attribute mlir::convertToAttribute(MLIRContext *ctx, uint8_t storage) {
+  /// Convert the provided uint8_t to an IntegerAttr attribute.
+  return IntegerAttr::get(IntegerType::get(ctx, 8), storage);
+}
+
 LogicalResult
 mlir::convertFromAttribute(std::string &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
diff --git a/mlir/test/IR/properties.mlir b/mlir/test/IR/properties.mlir
index b339a03812bad..dde9100cde142 100644
--- a/mlir/test/IR/properties.mlir
+++ b/mlir/test/IR/properties.mlir
@@ -59,9 +59,15 @@ test.with_default_valued_properties 1 "foo" 0 unit
 // CHECK:   test.with_optional_properties
 // CHECK-SAME: simple = 0
 // GENERIC: "test.with_optional_properties"()
-// GENERIC-SAME:  <{hasDefault = [], hasUnit = false, longSyntax = [], maybeUnit = [], nested = [], nonTrivialStorage = [], simple = [0]}> : () -> ()
+// GENERIC-SAME:  <{hasDefault = [], hasUnit = false, longSyntax = [], maybeUnit = [], nested = [], nonTrivialStorage = [], simple = [0], simplei8 = [], simpleui8 = []}> : () -> ()
 test.with_optional_properties simple = 0
 
+// CHECK:   test.with_optional_properties
+// CHECK-SAME: simple = 1 simplei8 = -1 simpleui8 = 255
+// GENERIC: "test.with_optional_properties"()
+// GENERIC-SAME:  <{hasDefault = [], hasUnit = false, longSyntax = [], maybeUnit = [], nested = [], nonTrivialStorage = [], simple = [1], simplei8 = [-1 : i8], simpleui8 = [-1 : i8]}> : () -> ()
+test.with_optional_properties simple = 1 simplei8 = -1 simpleui8 = 255
+
 // CHECK:   test.with_optional_properties{{$}}
 // GENERIC: "test.with_optional_properties"()
 // GENERIC-SAME: simple = []
@@ -70,7 +76,7 @@ test.with_optional_properties
 // CHECK:    test.with_optional_properties
 // CHECK-SAME: anAttr = 0 simple = 1 nonTrivialStorage = "foo" hasDefault = some<0> nested = some<1>  longSyntax = some<"bar"> hasUnit maybeUnit = some<unit>
 // GENERIC: "test.with_optional_properties"()
-// GENERIC-SAME: <{anAttr = 0 : i32, hasDefault = [0], hasUnit, longSyntax = ["bar"], maybeUnit = [unit], nested = {{\[}}[1]], nonTrivialStorage = ["foo"], simple = [1]}> : () -> ()
+// GENERIC-SAME: <{anAttr = 0 : i32, hasDefault = [0], hasUnit, longSyntax = ["bar"], maybeUnit = [unit], nested = {{\[}}[1]], nonTrivialStorage = ["foo"], simple = [1], simplei8 = [], simpleui8 = []}> : () -> ()
 test.with_optional_properties
   anAttr = 0
   simple = 1
diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td
index 79bcd9c2e0a9a..d7554f1a83446 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -3387,6 +3387,8 @@ def TestOpWithOptionalProperties : TEST_Op<"with_optional_properties"> {
   let assemblyFormat = [{
     (`anAttr` `=` $anAttr^)?
     (`simple` `=` $simple^)?
+    (`simplei8` `=` $simplei8^)?
+    (`simpleui8` `=` $simpleui8^)?
     (`nonTrivialStorage` `=` $nonTrivialStorage^)?
     (`hasDefault` `=` $hasDefault^)?
     (`nested` `=` $nested^)?
@@ -3398,6 +3400,8 @@ def TestOpWithOptionalProperties : TEST_Op<"with_optional_properties"> {
   let arguments = (ins
     OptionalAttr<I32Attr>:$anAttr,
     OptionalProp<I64Prop>:$simple,
+    OptionalProp<IntProp<"int8_t">>:$simplei8,
+    OptionalProp<IntProp<"uint8_t">>:$simpleui8,
     OptionalProp<StringProp>:$nonTrivialStorage,
     // Confirm that properties with default values now default to nullopt and have
     // the long syntax.

@llvmbot
Copy link
Member

llvmbot commented Jun 20, 2025

@llvm/pr-subscribers-mlir

Author: Mehdi Amini (joker-eph)

Changes

This patch is adding the ability to print a uint8_t/int8_t as an int instead of a char and demonstrate support for int8_t/uin8_t properties.

Fix #144993


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

6 Files Affected:

  • (modified) mlir/include/mlir/IR/ODSSupport.h (+20)
  • (modified) mlir/include/mlir/IR/OpImplementation.h (+13)
  • (modified) mlir/include/mlir/IR/Properties.td (+1)
  • (modified) mlir/lib/IR/ODSSupport.cpp (+34)
  • (modified) mlir/test/IR/properties.mlir (+8-2)
  • (modified) mlir/test/lib/Dialect/Test/TestOps.td (+4)
diff --git a/mlir/include/mlir/IR/ODSSupport.h b/mlir/include/mlir/IR/ODSSupport.h
index 25d6f3da6a861..b24a2470470ff 100644
--- a/mlir/include/mlir/IR/ODSSupport.h
+++ b/mlir/include/mlir/IR/ODSSupport.h
@@ -43,6 +43,26 @@ convertFromAttribute(int32_t &storage, Attribute attr,
 /// Convert the provided int32_t to an IntegerAttr attribute.
 Attribute convertToAttribute(MLIRContext *ctx, int32_t storage);
 
+/// Convert an IntegerAttr attribute to an int8_t, or return an error if the
+/// attribute isn't an IntegerAttr. If the optional diagnostic is provided an
+/// error message is also emitted.
+LogicalResult
+convertFromAttribute(int8_t &storage, Attribute attr,
+                     function_ref<InFlightDiagnostic()> emitError);
+
+/// Convert the provided int8_t to an IntegerAttr attribute.
+Attribute convertToAttribute(MLIRContext *ctx, int8_t storage);
+
+/// Convert an IntegerAttr attribute to an uint8_t, or return an error if the
+/// attribute isn't an IntegerAttr. If the optional diagnostic is provided an
+/// error message is also emitted.
+LogicalResult
+convertFromAttribute(uint8_t &storage, Attribute attr,
+                     function_ref<InFlightDiagnostic()> emitError);
+
+/// Convert the provided uint8_t to an IntegerAttr attribute.
+Attribute convertToAttribute(MLIRContext *ctx, uint8_t storage);
+
 /// Extract the string from `attr` into `storage`. If `attr` is not a
 /// `StringAttr`, return failure and emit an error into the diagnostic from
 /// `emitError`.
diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index 8b56d81c8eecc..8710b970e8d75 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -135,6 +135,19 @@ class AsmPrinter {
   /// hook on the AsmParser.
   virtual void printFloat(const APFloat &value);
 
+  /// Print the given integer value. This is useful to force a uint8_t/int8_t to
+  /// be printed as an integer instead of a char.
+  template <typename IntT>
+  std::enable_if_t<std::is_integral_v<IntT>, void> printInteger(IntT value) {
+    // Handle int8_t/uint8_t specially to avoid printing as char
+    if constexpr (std::is_same_v<IntT, int8_t> ||
+                  std::is_same_v<IntT, uint8_t>) {
+      getStream() << static_cast<int>(value);
+    } else {
+      getStream() << value;
+    }
+  }
+
   virtual void printType(Type type);
   virtual void printAttribute(Attribute attr);
 
diff --git a/mlir/include/mlir/IR/Properties.td b/mlir/include/mlir/IR/Properties.td
index 25a45489c7b53..1aa19d0ecfa3a 100644
--- a/mlir/include/mlir/IR/Properties.td
+++ b/mlir/include/mlir/IR/Properties.td
@@ -219,6 +219,7 @@ class IntProp<string storageTypeParam, string desc = ""> :
   let optionalParser = [{
     return $_parser.parseOptionalInteger($_storage);
   }];
+  let printer = "$_printer.printInteger($_storage)";
   let writeToMlirBytecode = [{
     $_writer.writeVarInt($_storage);
   }];
diff --git a/mlir/lib/IR/ODSSupport.cpp b/mlir/lib/IR/ODSSupport.cpp
index d56c75ede9849..b8bad1f1b098f 100644
--- a/mlir/lib/IR/ODSSupport.cpp
+++ b/mlir/lib/IR/ODSSupport.cpp
@@ -48,6 +48,40 @@ Attribute mlir::convertToAttribute(MLIRContext *ctx, int32_t storage) {
   return IntegerAttr::get(IntegerType::get(ctx, 32), storage);
 }
 
+LogicalResult
+mlir::convertFromAttribute(int8_t &storage, Attribute attr,
+                           function_ref<InFlightDiagnostic()> emitError) {
+  auto valueAttr = dyn_cast<IntegerAttr>(attr);
+  if (!valueAttr) {
+    emitError() << "expected IntegerAttr for key `value`";
+    return failure();
+  }
+  storage = valueAttr.getValue().getZExtValue();
+  return success();
+}
+
+Attribute mlir::convertToAttribute(MLIRContext *ctx, int8_t storage) {
+  /// Convert the provided int8_t to an IntegerAttr attribute.
+  return IntegerAttr::get(IntegerType::get(ctx, 8), storage);
+}
+
+LogicalResult
+mlir::convertFromAttribute(uint8_t &storage, Attribute attr,
+                           function_ref<InFlightDiagnostic()> emitError) {
+  auto valueAttr = dyn_cast<IntegerAttr>(attr);
+  if (!valueAttr) {
+    emitError() << "expected IntegerAttr for key `value`";
+    return failure();
+  }
+  storage = valueAttr.getValue().getZExtValue();
+  return success();
+}
+
+Attribute mlir::convertToAttribute(MLIRContext *ctx, uint8_t storage) {
+  /// Convert the provided uint8_t to an IntegerAttr attribute.
+  return IntegerAttr::get(IntegerType::get(ctx, 8), storage);
+}
+
 LogicalResult
 mlir::convertFromAttribute(std::string &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
diff --git a/mlir/test/IR/properties.mlir b/mlir/test/IR/properties.mlir
index b339a03812bad..dde9100cde142 100644
--- a/mlir/test/IR/properties.mlir
+++ b/mlir/test/IR/properties.mlir
@@ -59,9 +59,15 @@ test.with_default_valued_properties 1 "foo" 0 unit
 // CHECK:   test.with_optional_properties
 // CHECK-SAME: simple = 0
 // GENERIC: "test.with_optional_properties"()
-// GENERIC-SAME:  <{hasDefault = [], hasUnit = false, longSyntax = [], maybeUnit = [], nested = [], nonTrivialStorage = [], simple = [0]}> : () -> ()
+// GENERIC-SAME:  <{hasDefault = [], hasUnit = false, longSyntax = [], maybeUnit = [], nested = [], nonTrivialStorage = [], simple = [0], simplei8 = [], simpleui8 = []}> : () -> ()
 test.with_optional_properties simple = 0
 
+// CHECK:   test.with_optional_properties
+// CHECK-SAME: simple = 1 simplei8 = -1 simpleui8 = 255
+// GENERIC: "test.with_optional_properties"()
+// GENERIC-SAME:  <{hasDefault = [], hasUnit = false, longSyntax = [], maybeUnit = [], nested = [], nonTrivialStorage = [], simple = [1], simplei8 = [-1 : i8], simpleui8 = [-1 : i8]}> : () -> ()
+test.with_optional_properties simple = 1 simplei8 = -1 simpleui8 = 255
+
 // CHECK:   test.with_optional_properties{{$}}
 // GENERIC: "test.with_optional_properties"()
 // GENERIC-SAME: simple = []
@@ -70,7 +76,7 @@ test.with_optional_properties
 // CHECK:    test.with_optional_properties
 // CHECK-SAME: anAttr = 0 simple = 1 nonTrivialStorage = "foo" hasDefault = some<0> nested = some<1>  longSyntax = some<"bar"> hasUnit maybeUnit = some<unit>
 // GENERIC: "test.with_optional_properties"()
-// GENERIC-SAME: <{anAttr = 0 : i32, hasDefault = [0], hasUnit, longSyntax = ["bar"], maybeUnit = [unit], nested = {{\[}}[1]], nonTrivialStorage = ["foo"], simple = [1]}> : () -> ()
+// GENERIC-SAME: <{anAttr = 0 : i32, hasDefault = [0], hasUnit, longSyntax = ["bar"], maybeUnit = [unit], nested = {{\[}}[1]], nonTrivialStorage = ["foo"], simple = [1], simplei8 = [], simpleui8 = []}> : () -> ()
 test.with_optional_properties
   anAttr = 0
   simple = 1
diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td
index 79bcd9c2e0a9a..d7554f1a83446 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -3387,6 +3387,8 @@ def TestOpWithOptionalProperties : TEST_Op<"with_optional_properties"> {
   let assemblyFormat = [{
     (`anAttr` `=` $anAttr^)?
     (`simple` `=` $simple^)?
+    (`simplei8` `=` $simplei8^)?
+    (`simpleui8` `=` $simpleui8^)?
     (`nonTrivialStorage` `=` $nonTrivialStorage^)?
     (`hasDefault` `=` $hasDefault^)?
     (`nested` `=` $nested^)?
@@ -3398,6 +3400,8 @@ def TestOpWithOptionalProperties : TEST_Op<"with_optional_properties"> {
   let arguments = (ins
     OptionalAttr<I32Attr>:$anAttr,
     OptionalProp<I64Prop>:$simple,
+    OptionalProp<IntProp<"int8_t">>:$simplei8,
+    OptionalProp<IntProp<"uint8_t">>:$simpleui8,
     OptionalProp<StringProp>:$nonTrivialStorage,
     // Confirm that properties with default values now default to nullopt and have
     // the long syntax.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This patch extends MLIR to support 8-bit integer properties (int8_t/uint8_t) by adding converters, printers, and tests.

  • Added IntProp<"int8_t"> and IntProp<"uint8_t"> to TestOps and assembly format
  • Implemented convertToAttribute/convertFromAttribute for int8_t/uint8_t in ODSSupport
  • Extended AsmPrinter with printInteger and updated tests in properties.mlir

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
TestOps.td Registered simplei8 and simpleui8 optional properties
properties.mlir Added CHECK lines for printing int8/uint8 properties
mlir/lib/IR/ODSSupport.cpp Added converters for int8_t and uint8_tIntegerAttr
Properties.td Introduced printer hook to call printInteger for IntProp
OpImplementation.h Added printInteger template to handle 8-bit integer printing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:core MLIR Core Infrastructure mlir:ods mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[mlir] OptionalProp<IntProp<uint8_t>> printout empty for 0 and similar values.
2 participants