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
| function-attribute
| string-attribute
| type-attribute
+ | unit-attribute
```
#### AffineMap Attribute
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}
namespace detail {
struct AttributeStorage;
+struct UnitAttributeStorage;
struct BoolAttributeStorage;
struct IntegerAttributeStorage;
struct FloatAttributeStorage;
class Attribute {
public:
enum class Kind {
+ Unit,
Bool,
Integer,
Float,
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.
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.
// 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);
}
switch (attr.getKind()) {
+ case Attribute::Kind::Unit:
+ os << "unit";
+ break;
case Attribute::Kind::Bool:
os << (attr.cast<BoolAttr>().getValue() ? "true" : "false");
break;
// 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 << '}';
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)
return NamedAttribute(getIdentifier(name), val);
}
+UnitAttr Builder::getUnitAttr() { return UnitAttr::get(context); }
+
BoolAttr Builder::getBoolAttr(bool value) {
return BoolAttr::get(value, context);
}
llvm::BumpPtrAllocator attributeAllocator;
llvm::sys::SmartRWMutex<true> attributeMutex;
+ UnitAttributeStorage unitAttr;
BoolAttributeStorage *boolAttrs[2] = {nullptr};
DenseSet<IntegerAttributeStorage *, IntegerAttrKeyInfo> integerAttrs;
DenseSet<FloatAttributeStorage *, FloatAttrKeyInfo> floatAttrs;
// Attribute uniquing
//===----------------------------------------------------------------------===//
+UnitAttr UnitAttr::get(MLIRContext *context) {
+ return &context->getImpl().unitAttr;
+}
+
BoolAttr BoolAttr::get(bool value, MLIRContext *context) {
auto &impl = context->getImpl();
/// Attribute parsing.
///
-/// attribute-value ::= bool-literal
+/// attribute-value ::= `unit`
+/// | bool-literal
/// | integer-literal (`:` (index-type | integer-type))?
/// | float-literal (`:` float-type)?
/// | string-literal
///
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);
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)
TOK_KEYWORD(true)
TOK_KEYWORD(tuple)
TOK_KEYWORD(type)
+TOK_KEYWORD(unit)
TOK_KEYWORD(vector)
#undef TOK_MARKER
// -----
-func @illegalattrs() -> () attributes { key } // expected-error {{expected ':' in attribute list}}
-
-// -----
-
func missingsigil() -> (i1, index, f32) // expected-error {{expected a function identifier like}}
// -----
-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}}
}
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: