summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mlir/g3doc/Dialects/LLVM.md7
-rw-r--r--mlir/include/mlir/LLVMIR/LLVMDialect.h1
-rw-r--r--mlir/lib/LLVMIR/IR/LLVMDialect.cpp43
-rw-r--r--mlir/lib/Target/LLVMIR/ModuleTranslation.cpp11
-rw-r--r--mlir/test/LLVMIR/global.mlir21
-rw-r--r--mlir/test/Target/llvmir.mlir3
6 files changed, 81 insertions, 5 deletions
diff --git a/mlir/g3doc/Dialects/LLVM.md b/mlir/g3doc/Dialects/LLVM.md
index 566e506828b..20afa32b4ab 100644
--- a/mlir/g3doc/Dialects/LLVM.md
+++ b/mlir/g3doc/Dialects/LLVM.md
@@ -302,6 +302,13 @@ llvm.global constant @cst(42 : i32) : !llvm.i32
// Non-constant values must also be initialized.
llvm.global @variable(32.0 : f32) : !llvm.float
+
+// Strings are expected to be of wrapped LLVM i8 array type and do not
+// automatically include the trailing zero.
+llvm.global @string("abc") : !llvm<"[3 x i8]">
+
+// For strings globals, the trailing type may be omitted.
+llvm.global constant @no_trailing_type("foo bar")
```
#### `llvm.undef`
diff --git a/mlir/include/mlir/LLVMIR/LLVMDialect.h b/mlir/include/mlir/LLVMIR/LLVMDialect.h
index ec7ea8f0382..00f5be4d8d6 100644
--- a/mlir/include/mlir/LLVMIR/LLVMDialect.h
+++ b/mlir/include/mlir/LLVMIR/LLVMDialect.h
@@ -66,6 +66,7 @@ public:
/// Array type utilities.
LLVMType getArrayElementType();
+ unsigned getArrayNumElements();
/// Vector type utilities.
LLVMType getVectorElementType();
diff --git a/mlir/lib/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/LLVMIR/IR/LLVMDialect.cpp
index c50a14ffff9..378907eff0b 100644
--- a/mlir/lib/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/LLVMIR/IR/LLVMDialect.cpp
@@ -840,29 +840,52 @@ static void printGlobalOp(OpAsmPrinter *p, GlobalOp op) {
*p << ')';
p->printOptionalAttrDict(op.getAttrs(), {SymbolTable::getSymbolAttrName(),
"type", "constant", "value"});
+
+ // Print the trailing type unless it's a string global.
+ if (op.value().isa<StringAttr>())
+ return;
*p << " : ";
p->printType(op.type());
}
// <operation> ::= `llvm.global` `constant`? `@` identifier `(` attribute `)`
-// attribute-list? : type
+// attribute-list? (`:` type)?
+//
+// The type can be omitted for string attributes, in which case it will be
+// inferred from the value of the string as [strlen(value) x i8].
static ParseResult parseGlobalOp(OpAsmParser *parser, OperationState *result) {
if (succeeded(parser->parseOptionalKeyword("constant")))
result->addAttribute("constant", parser->getBuilder().getUnitAttr());
Attribute value;
StringAttr name;
- Type type;
+ SmallVector<Type, 1> types;
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))
+ parser->parseOptionalColonTypeList(types))
return failure();
- result->addAttribute("type", parser->getBuilder().getTypeAttr(type));
+ if (types.size() > 1)
+ return parser->emitError(parser->getNameLoc(), "expected zero or one type");
+
+ if (types.empty()) {
+ if (auto strAttr = value.dyn_cast<StringAttr>()) {
+ MLIRContext *context = parser->getBuilder().getContext();
+ auto *dialect = context->getRegisteredDialect<LLVMDialect>();
+ auto arrayType = LLVM::LLVMType::getArrayTy(
+ LLVM::LLVMType::getInt8Ty(dialect), strAttr.getValue().size());
+ types.push_back(arrayType);
+ } else {
+ return parser->emitError(parser->getNameLoc(),
+ "type can only be omitted for string globals");
+ }
+ }
+
+ result->addAttribute("type", parser->getBuilder().getTypeAttr(types[0]));
return success();
}
@@ -872,6 +895,15 @@ static LogicalResult verify(GlobalOp op) {
"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");
+ if (auto strAttr = op.value().dyn_cast<StringAttr>()) {
+ auto type = op.getType();
+ if (!type.getUnderlyingType()->isArrayTy() ||
+ !type.getArrayElementType().getUnderlyingType()->isIntegerTy(8) ||
+ type.getArrayNumElements() != strAttr.getValue().size())
+ return op.emitOpError(
+ "requires an i8 array type of the length equal to that of the string "
+ "attribute");
+ }
return success();
}
@@ -1200,6 +1232,9 @@ llvm::Type *LLVMType::getUnderlyingType() const {
LLVMType LLVMType::getArrayElementType() {
return get(getContext(), getUnderlyingType()->getArrayElementType());
}
+unsigned LLVMType::getArrayNumElements() {
+ return getUnderlyingType()->getArrayNumElements();
+}
/// Vector type utilities.
LLVMType LLVMType::getVectorElementType() {
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index bf43848c9ef..3cbf543bdfc 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -292,6 +292,17 @@ bool ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments) {
// Create named global variables that correspond to llvm.global definitions.
void ModuleTranslation::convertGlobals() {
for (auto op : mlirModule.getOps<LLVM::GlobalOp>()) {
+ // String attributes are treated separately because they cannot appear as
+ // in-function constants and are thus not supported by getLLVMConstant.
+ if (auto strAttr = op.value().dyn_cast<StringAttr>()) {
+ llvm::Constant *cst = llvm::ConstantDataArray::getString(
+ llvmModule->getContext(), strAttr.getValue(), /*AddNull=*/false);
+ new llvm::GlobalVariable(*llvmModule, cst->getType(), op.constant(),
+ llvm::GlobalValue::InternalLinkage, cst,
+ op.sym_name());
+ return;
+ }
+
llvm::Type *type = op.getType().getUnderlyingType();
new llvm::GlobalVariable(
*llvmModule, type, op.constant(), llvm::GlobalValue::InternalLinkage,
diff --git a/mlir/test/LLVMIR/global.mlir b/mlir/test/LLVMIR/global.mlir
index 69e5570b481..ee462270322 100644
--- a/mlir/test/LLVMIR/global.mlir
+++ b/mlir/test/LLVMIR/global.mlir
@@ -6,9 +6,12 @@ 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]">
+// CHECK: llvm.global constant @string("foobar")
llvm.global constant @string("foobar") : !llvm<"[6 x i8]">
+// CHECK: llvm.global @string_notype("1234567")
+llvm.global @string_notype("1234567")
+
// -----
// expected-error @+1 {{op requires attribute 'sym_name'}}
@@ -35,3 +38,19 @@ func @foo() {
// expected-error @+1 {{must appear at the module level}}
llvm.global @bar(42) : !llvm.i32
}
+
+// -----
+
+// expected-error @+1 {{requires an i8 array type of the length equal to that of the string}}
+llvm.global constant @string("foobar") : !llvm<"[42 x i8]">
+
+// -----
+
+// expected-error @+1 {{type can only be omitted for string globals}}
+llvm.global @i64_needs_type(0: i64)
+
+// -----
+
+// expected-error @+1 {{expected zero or one type}}
+llvm.global @more_than_one_type(0) : !llvm.i64, !llvm.i32
+
diff --git a/mlir/test/Target/llvmir.mlir b/mlir/test/Target/llvmir.mlir
index 6f357abc384..6db5cece383 100644
--- a/mlir/test/Target/llvmir.mlir
+++ b/mlir/test/Target/llvmir.mlir
@@ -9,6 +9,9 @@ llvm.global constant @i32_global_const(52: i53) : !llvm.i53
// CHECK: @float_global = internal global float 0.000000e+00
llvm.global @float_global(0.0: f32) : !llvm.float
+// CHECK: @string_const = internal constant [6 x i8] c"foobar"
+llvm.global constant @string_const("foobar") : !llvm<"[6 x i8]">
+
//
// Declarations of the allocation functions to be linked against.
//
OpenPOWER on IntegriCloud