Add support for Unit Attributes.
authorRiver Riddle <riverriddle@google.com>
Thu, 25 Apr 2019 16:56:09 +0000 (09:56 -0700)
committerMehdi Amini <joker.eph@gmail.com>
Mon, 6 May 2019 15:16:39 +0000 (08:16 -0700)
    A unit attribute is an attribute that represents a value of `unit` type. The
    `unit` type allows only one value forming a singleton set. This attribute value
    is used to represent attributes that only have meaning from their existence.

    One example of such an attribute could be the `swift.self` attribute. This attribute indicates that a function parameter is the self/context
    parameter. It could be represented as a boolean attribute(true or false), but a
    value of false doesn't really bring any value. The parameter either is the
    self/context or it isn't.

    ```mlir {.mlir}
    // A unit attribute defined with the `unit` value specifier.
    func @verbose_form(i1 {unitAttr : unit})

    // A unit attribute can also be defined without the `unit` value specifier.
    func @simple_form(i1 {unitAttr})
    ```

--

PiperOrigin-RevId: 245254045

mlir/g3doc/LangRef.md
mlir/include/mlir/IR/Attributes.h
mlir/include/mlir/IR/Builders.h
mlir/lib/IR/AsmPrinter.cpp
mlir/lib/IR/AttributeDetail.h
mlir/lib/IR/Builders.cpp
mlir/lib/IR/MLIRContext.cpp
mlir/lib/Parser/Parser.cpp
mlir/lib/Parser/TokenKinds.def
mlir/test/IR/invalid.mlir
mlir/test/IR/parser.mlir

index 3249b19..bbd2f48 100644 (file)
@@ -972,6 +972,7 @@ attribute-value ::= affine-map-attribute
                   | function-attribute
                   | string-attribute
                   | type-attribute
+                  | unit-attribute
 ```
 
 #### AffineMap Attribute
@@ -1157,6 +1158,30 @@ type-attribute ::= type
 
 A type attribute is an attribute that represents a [type object](#type-system).
 
+#### Unit Attribute
+
+``` {.ebnf}
+unit-attribute ::= `unit`
+```
+
+A unit attribute is an attribute that represents a value of `unit` type. The
+`unit` type allows only one value forming a singleton set. This attribute value
+is used to represent attributes that only have meaning from their existence.
+
+One example of such an attribute could be the `swift.self` attribute. This
+attribute indicates that a function parameter is the self/context parameter. It
+could be represented as a [boolean attribute](#boolean-attribute)(true or
+false), but a value of false doesn't really bring any value. The parameter
+either is the self/context or it isn't.
+
+```mlir {.mlir}
+// A unit attribute defined with the `unit` value specifier.
+func @verbose_form(i1 {unitAttr : unit})
+
+// A unit attribute can also be defined without the value specifier.
+func @simple_form(i1 {unitAttr})
+```
+
 ## Module
 
 ``` {.ebnf}
index b2136f1..25b7399 100644 (file)
@@ -38,6 +38,7 @@ class VectorOrTensorType;
 namespace detail {
 
 struct AttributeStorage;
+struct UnitAttributeStorage;
 struct BoolAttributeStorage;
 struct IntegerAttributeStorage;
 struct FloatAttributeStorage;
@@ -68,6 +69,7 @@ class AttributeListStorage;
 class Attribute {
 public:
   enum class Kind {
+    Unit,
     Bool,
     Integer,
     Float,
@@ -158,6 +160,18 @@ inline raw_ostream &operator<<(raw_ostream &os, Attribute attr) {
   return os;
 }
 
+/// Unit attributes are attributes that hold no specific value and are given
+/// meaning by their existence.
+class UnitAttr : public Attribute {
+public:
+  using Attribute::Attribute;
+  using ImplType = detail::UnitAttributeStorage;
+
+  static UnitAttr get(MLIRContext *context);
+
+  static bool kindof(Kind kind) { return kind == Attribute::Kind::Unit; }
+};
+
 /// Numeric attributes are (vector/tensor of) bool, integer, or floating-point
 /// constants. For all the attributes, we can only build constant op out of
 /// numeric attributes.
index a3f8ad5..a2bfcf2 100644 (file)
@@ -50,6 +50,7 @@ class DenseElementsAttr;
 class DenseIntElementsAttr;
 class AffineMapAttr;
 class AffineMap;
+class UnitAttr;
 
 /// This class is a general helper class for creating context-global objects
 /// like types, attributes, and affine expressions.
@@ -98,6 +99,7 @@ public:
   // Attributes.
   NamedAttribute getNamedAttr(StringRef name, Attribute val);
 
+  UnitAttr getUnitAttr();
   BoolAttr getBoolAttr(bool value);
   IntegerAttr getIntegerAttr(Type type, int64_t value);
   IntegerAttr getIntegerAttr(Type type, const APInt &value);
index ce4311d..8b1410e 100644 (file)
@@ -546,6 +546,9 @@ void ModulePrinter::printAttributeOptionalType(Attribute attr,
   }
 
   switch (attr.getKind()) {
+  case Attribute::Kind::Unit:
+    os << "unit";
+    break;
   case Attribute::Kind::Bool:
     os << (attr.cast<BoolAttr>().getValue() ? "true" : "false");
     break;
@@ -1133,7 +1136,13 @@ void ModulePrinter::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
   // Otherwise, print them all out in braces.
   os << " {";
   interleaveComma(filteredAttrs, [&](NamedAttribute attr) {
-    os << attr.first << ": ";
+    os << attr.first;
+
+    // Pretty printing elides the attribute value for unit attributes.
+    if (attr.second.isa<UnitAttr>())
+      return;
+
+    os << ": ";
     printAttributeAndType(attr.second);
   });
   os << '}';
index 813d3a4..e1da603 100644 (file)
@@ -45,6 +45,11 @@ struct AttributeStorage {
   bool isOrContainsFunctionCache : 1;
 };
 
+/// An attribute representing a unit value.
+struct UnitAttributeStorage : public AttributeStorage {
+  UnitAttributeStorage() : AttributeStorage(Attribute::Kind::Unit) {}
+};
+
 /// An attribute representing a boolean value.
 struct BoolAttributeStorage : public AttributeStorage {
   BoolAttributeStorage(Type type, bool value)
index 962fa34..d999b14 100644 (file)
@@ -109,6 +109,8 @@ NamedAttribute Builder::getNamedAttr(StringRef name, Attribute val) {
   return NamedAttribute(getIdentifier(name), val);
 }
 
+UnitAttr Builder::getUnitAttr() { return UnitAttr::get(context); }
+
 BoolAttr Builder::getBoolAttr(bool value) {
   return BoolAttr::get(value, context);
 }
index e1ee993..c0df0e0 100644 (file)
@@ -580,6 +580,7 @@ public:
   llvm::BumpPtrAllocator attributeAllocator;
   llvm::sys::SmartRWMutex<true> attributeMutex;
 
+  UnitAttributeStorage unitAttr;
   BoolAttributeStorage *boolAttrs[2] = {nullptr};
   DenseSet<IntegerAttributeStorage *, IntegerAttrKeyInfo> integerAttrs;
   DenseSet<FloatAttributeStorage *, FloatAttrKeyInfo> floatAttrs;
@@ -983,6 +984,10 @@ const Dialect &TypeUniquer::lookupDialectForType(MLIRContext *ctx,
 // Attribute uniquing
 //===----------------------------------------------------------------------===//
 
+UnitAttr UnitAttr::get(MLIRContext *context) {
+  return &context->getImpl().unitAttr;
+}
+
 BoolAttr BoolAttr::get(bool value, MLIRContext *context) {
   auto &impl = context->getImpl();
 
index 1156fc6..d7b7c9f 100644 (file)
@@ -1010,7 +1010,8 @@ Function *Parser::resolveFunctionReference(StringRef nameStr, SMLoc nameLoc,
 
 /// Attribute parsing.
 ///
-///  attribute-value ::= bool-literal
+///  attribute-value ::= `unit`
+///                    | bool-literal
 ///                    | integer-literal (`:` (index-type | integer-type))?
 ///                    | float-literal (`:` float-type)?
 ///                    | string-literal
@@ -1026,6 +1027,10 @@ Function *Parser::resolveFunctionReference(StringRef nameStr, SMLoc nameLoc,
 ///
 Attribute Parser::parseAttribute(Type type) {
   switch (getToken().getKind()) {
+  case Token::kw_unit:
+    consumeToken(Token::kw_unit);
+    return builder.getUnitAttr();
+
   case Token::kw_true:
     consumeToken(Token::kw_true);
     return builder.getBoolAttr(true);
@@ -1595,8 +1600,12 @@ Parser::parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes) {
     Identifier nameId = builder.getIdentifier(getTokenSpelling());
     consumeToken();
 
-    if (parseToken(Token::colon, "expected ':' in attribute list"))
-      return ParseFailure;
+    // Try to parse the ':' for the attribute value.
+    if (!consumeIf(Token::colon)) {
+      // If there is no ':', we treat this as a unit attribute.
+      attributes.push_back({nameId, builder.getUnitAttr()});
+      return ParseSuccess;
+    }
 
     auto attr = parseAttribute();
     if (!attr)
index 0b2c2ef..52a7fdc 100644 (file)
@@ -118,6 +118,7 @@ TOK_KEYWORD(to)
 TOK_KEYWORD(true)
 TOK_KEYWORD(tuple)
 TOK_KEYWORD(type)
+TOK_KEYWORD(unit)
 TOK_KEYWORD(vector)
 
 #undef TOK_MARKER
index a2d6353..fe4f7d5 100644 (file)
@@ -73,10 +73,6 @@ func @memrefs(memref<42x42xi8, #map0, #map1>) // expected-error {{memref affine
 
 // -----
 
-func @illegalattrs() -> () attributes { key } // expected-error {{expected ':' in attribute list}}
-
-// -----
-
 func missingsigil() -> (i1, index, f32) // expected-error {{expected a function identifier like}}
 
 
@@ -147,27 +143,11 @@ func @block_first_has_predecessor() {
 
 // -----
 
-func @illegalattrs() -> ()
-  attributes { key } { // expected-error {{expected ':' in attribute list}}
-^bb42:
-  return
-}
-
-// -----
-
 func @empty() {
 } // expected-error {{function must have a body}}
 
 // -----
 
-func @illegalattrs() -> ()
-  attributes { key } { // expected-error {{expected ':' in attribute list}}
-^bb42:
-  return
-}
-
-// -----
-
 func @no_return() {
   %x = constant 0 : i32  // expected-error {{block with no terminator}}
 }
index d9368ba..77a4889 100644 (file)
@@ -511,6 +511,16 @@ func @stringquote() -> () {
   return
 }
 
+// CHECK-LABEL: func @unitAttrs
+func @unitAttrs() -> () {
+  // CHECK-NEXT: "foo"() {unitAttr} : () -> ()
+  "foo"() {unitAttr : unit} : () -> ()
+
+  // CHECK-NEXT: "foo"() {unitAttr} : () -> ()
+  "foo"() {unitAttr} : () -> ()
+  return
+}
+
 // CHECK-LABEL: func @floatAttrs
 func @floatAttrs() -> () {
 ^bb0: