%3 = llvm.constant(splat<vector<4xf32>, 1.0>) : !llvm<"<4 x float>">
```
+#### `llvm.global`
+
+Since MLIR allows for arbitrary operations to be present at the top level,
+global variables are defined using the `llvm.global` operation. Both global
+constants and variables can be defined, and the value must be initialized in
+both cases. The initialization and type syntax is similar to `llvm.constant` and
+may use two types: one for MLIR attribute and another for the LLVM value. These
+types must be compatible. `llvm.global` must appear at top-level of the
+enclosing module. It uses an @-identifier for its value, which will be uniqued
+by the module with respect to other @-identifiers in it.
+
+Examples:
+
+```mlir {.mlir}
+// Global values use @-identifiers.
+llvm.global constant @cst(42 : i32) : !llvm.i32
+
+// Non-constant values must also be initialized.
+llvm.global @variable(32.0 : f32) : !llvm.float
+```
+
#### `llvm.undef`
Unlike LLVM IR, MLIR does not have first-class undefined values. Such values
parseOptionalAttributeDict(SmallVectorImpl<NamedAttribute> &result) = 0;
//===--------------------------------------------------------------------===//
+ // Identifier Parsing
+ //===--------------------------------------------------------------------===//
+
+ virtual ParseResult
+ parseSymbolName(StringAttr &result, StringRef attrName,
+ SmallVectorImpl<NamedAttribute> &attrs) = 0;
+
+ //===--------------------------------------------------------------------===//
// Operand Parsing
//===--------------------------------------------------------------------===//
// Pseudo-operations (do not appear in LLVM IR but necessary for the dialect to
// work correctly).
+def LLVM_GlobalOp
+ : LLVM_ZeroResultOp<"global">,
+ Arguments<(ins TypeAttr:$type, UnitAttr:$constant, StrAttr:$sym_name,
+ AnyAttr:$value)> {
+
+ let builders = [
+ OpBuilder<"Builder *builder, OperationState *result, LLVMType type, "
+ "bool isConstant, StringRef name, Attribute value, "
+ "ArrayRef<NamedAttribute> attrs = {}">
+ ];
+
+ let extraClassDeclaration = [{
+ /// Return the LLVM type of the global.
+ LLVMType getType() {
+ return type().cast<LLVMType>();
+ }
+ }];
+
+ let printer = "printGlobalOp(p, *this);";
+ let parser = "return parseGlobalOp(parser, result);";
+ let verifier = "return ::verify(*this);";
+}
+
def LLVM_LLVMFuncOp : LLVM_ZeroResultOp<"func",
[NativeOpTrait<"IsIsolatedFromAbove">, NativeOpTrait<"FunctionLike">]> {
let summary = "LLVM dialect function, has wrapped LLVM IR function type";
}
//===----------------------------------------------------------------------===//
+// Builder, printer and verifier for LLVM::GlobalOp.
+//===----------------------------------------------------------------------===//
+
+void GlobalOp::build(Builder *builder, OperationState *result, LLVMType type,
+ bool isConstant, StringRef name, Attribute value,
+ ArrayRef<NamedAttribute> attrs) {
+ result->addAttribute(SymbolTable::getSymbolAttrName(),
+ builder->getStringAttr(name));
+ result->addAttribute("type", builder->getTypeAttr(type));
+ if (isConstant)
+ result->addAttribute("constant", builder->getUnitAttr());
+ result->addAttribute("value", value);
+ result->attributes.append(attrs.begin(), attrs.end());
+}
+
+static void printGlobalOp(OpAsmPrinter *p, GlobalOp op) {
+ *p << op.getOperationName() << ' ';
+ if (op.constant())
+ *p << "constant ";
+ *p << '@' << op.sym_name() << '(';
+ p->printAttribute(op.value());
+ *p << ')';
+ p->printOptionalAttrDict(op.getAttrs(), {SymbolTable::getSymbolAttrName(),
+ "type", "constant", "value"});
+ *p << " : ";
+ p->printType(op.type());
+}
+
+// <operation> ::= `llvm.global` `constant`? `@` identifier `(` attribute `)`
+// attribute-list? : type
+static ParseResult parseGlobalOp(OpAsmParser *parser, OperationState *result) {
+ if (succeeded(parser->parseOptionalKeyword("constant")))
+ result->addAttribute("constant", parser->getBuilder().getUnitAttr());
+
+ Attribute value;
+ StringAttr name;
+ Type type;
+ if (parser->parseSymbolName(name, SymbolTable::getSymbolAttrName(),
+ result->attributes) ||
+ parser->parseLParen() ||
+ parser->parseAttribute(value, "value", result->attributes) ||
+ parser->parseRParen() ||
+ parser->parseOptionalAttributeDict(result->attributes) ||
+ parser->parseColonType(type))
+ return failure();
+
+ result->addAttribute("type", parser->getBuilder().getTypeAttr(type));
+ return success();
+}
+
+static LogicalResult verify(GlobalOp op) {
+ if (!llvm::PointerType::isValidElementType(op.getType().getUnderlyingType()))
+ return op.emitOpError(
+ "expects type to be a valid element type for an LLVM pointer");
+ if (op.getParentOp() && !isa<ModuleOp>(op.getParentOp()))
+ return op.emitOpError("must appear at the module level");
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
// Builder, printer and verifier for LLVM::LLVMFuncOp.
//===----------------------------------------------------------------------===//
}
//===--------------------------------------------------------------------===//
+ // Identifier Parsing
+ //===--------------------------------------------------------------------===//
+
+ /// Parse an @-identifier and store it (without the '@' symbol) in a string
+ /// attribute named 'attrName'.
+ ParseResult parseSymbolName(StringAttr &result, StringRef attrName,
+ SmallVectorImpl<NamedAttribute> &attrs) override {
+ if (parser.getToken().isNot(Token::at_identifier))
+ return failure();
+ result = getBuilder().getStringAttr(parser.getTokenSpelling().drop_front());
+ attrs.push_back(getBuilder().getNamedAttr(attrName, result));
+ parser.consumeToken();
+ return success();
+ }
+
+ //===--------------------------------------------------------------------===//
// Operand Parsing
//===--------------------------------------------------------------------===//
--- /dev/null
+// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
+
+// CHECK: llvm.global @global(42 : i64) : !llvm.i64
+llvm.global @global(42 : i64) : !llvm.i64
+
+// CHECK: llvm.global constant @constant(3.700000e+01 : f64) : !llvm.float
+llvm.global constant @constant(37.0) : !llvm.float
+
+// CHECK: llvm.global constant @string("foobar") : !llvm<"[6 x i8]">
+llvm.global constant @string("foobar") : !llvm<"[6 x i8]">
+
+// -----
+
+// expected-error @+1 {{op requires attribute 'sym_name'}}
+"llvm.global"() {type = !llvm.i64, constant, value = 42 : i64} : () -> ()
+
+// -----
+
+// expected-error @+1 {{op requires attribute 'type'}}
+"llvm.global"() {sym_name = "foo", constant, value = 42 : i64} : () -> ()
+
+// -----
+
+// expected-error @+1 {{op requires attribute 'value'}}
+"llvm.global"() {sym_name = "foo", type = !llvm.i64, constant} : () -> ()
+
+// -----
+
+// expected-error @+1 {{expects type to be a valid element type for an LLVM pointer}}
+llvm.global constant @constant(37.0) : !llvm<"label">
+
+// -----
+
+func @foo() {
+ // expected-error @+1 {{must appear at the module level}}
+ llvm.global @bar(42) : !llvm.i32
+}