diff options
-rw-r--r-- | mlir/g3doc/Dialects/LLVM.md | 7 | ||||
-rw-r--r-- | mlir/include/mlir/LLVMIR/LLVMDialect.h | 1 | ||||
-rw-r--r-- | mlir/lib/LLVMIR/IR/LLVMDialect.cpp | 43 | ||||
-rw-r--r-- | mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 11 | ||||
-rw-r--r-- | mlir/test/LLVMIR/global.mlir | 21 | ||||
-rw-r--r-- | mlir/test/Target/llvmir.mlir | 3 |
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. // |