[IntegerAttr] Add helpers for working with LLVM's APSInt type.
authorChris Lattner <clattner@nondot.org>
Tue, 18 May 2021 17:23:01 +0000 (10:23 -0700)
committerChris Lattner <clattner@nondot.org>
Tue, 18 May 2021 17:51:52 +0000 (10:51 -0700)
The FIRRTL dialect in CIRCT uses inherently signful types, and APSInt
is the best way to model that.  Add a couple of helpers that make it
easier to work with an IntegerAttr that carries a sign.

This follows the example of getZExt() and getSExt() which assert when
the underlying type of the attribute is unexpected.  In this case
we assert fail when the underlying type of the attribute is signless.

This is strictly additive, so it is NFC.  It is tested in the CIRCT
repo.

Differential Revision: https://reviews.llvm.org/D102701

mlir/include/mlir/IR/BuiltinAttributes.td
mlir/include/mlir/Support/LLVM.h
mlir/lib/IR/BuiltinAttributes.cpp

index 05dbc6b..1a5c60a 100644 (file)
@@ -466,6 +466,12 @@ def Builtin_IntegerAttr : Builtin_Attr<"Integer"> {
         return BoolAttr::get(type.getContext(), value.getBoolValue());
       return $_get(type.getContext(), type, value);
     }]>,
+    AttrBuilder<(ins "const APSInt &":$value), [{
+      auto signedness = value.isSigned() ?
+        IntegerType::Signed : IntegerType::Unsigned;
+      auto type = IntegerType::get($_ctxt, value.getBitWidth(), signedness);
+      return $_get(type.getContext(), type, value);
+    }]>,
     AttrBuilderWithInferredContext<(ins "Type":$type, "int64_t":$value), [{
       // `index` has a defined internal storage width.
       if (type.isIndex()) {
@@ -492,6 +498,10 @@ def Builtin_IntegerAttr : Builtin_Attr<"Integer"> {
     /// an unsigned integer.
     uint64_t getUInt() const;
 
+    /// Return the value as an APSInt which carries the signed from the type of
+    /// the attribute.  This traps on signless integers types!
+    APSInt getAPSInt() const;
+
   private:
     /// Return a boolean attribute. This is a special variant of the `get`
     /// method that is used by the MLIRContext to cache the boolean IntegerAttr
index 0683e4d..096cd9d 100644 (file)
@@ -64,6 +64,7 @@ template <typename T, typename ResultT> class TypeSwitch;
 
 // Other common classes.
 class APInt;
+class APSInt;
 class APFloat;
 template <typename Fn> class function_ref;
 template <typename IteratorT> class iterator_range;
@@ -118,6 +119,7 @@ using TypeSwitch = llvm::TypeSwitch<T, ResultT>;
 // Other common classes.
 using llvm::APFloat;
 using llvm::APInt;
+using llvm::APSInt;
 template <typename Fn> using function_ref = llvm::function_ref<Fn>;
 using llvm::iterator_range;
 using llvm::raw_ostream;
index 76ce6ca..b36a244 100644 (file)
@@ -259,6 +259,14 @@ uint64_t IntegerAttr::getUInt() const {
   return getValue().getZExtValue();
 }
 
+/// Return the value as an APSInt which carries the signed from the type of
+/// the attribute.  This traps on signless integers types!
+APSInt IntegerAttr::getAPSInt() const {
+  assert(!getType().isSignlessInteger() &&
+         "Signless integers don't carry a sign for APSInt");
+  return APSInt(getValue(), getType().isUnsignedInteger());
+}
+
 LogicalResult IntegerAttr::verify(function_ref<InFlightDiagnostic()> emitError,
                                   Type type, APInt value) {
   if (IntegerType integerType = type.dyn_cast<IntegerType>()) {