Index: mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td =================================================================== --- mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -66,6 +66,12 @@ /// Returns `true` if the given type is compatible with the LLVM dialect. static bool isCompatibleType(Type); + /// Name of the attribute mapped to LLVM's 'readnone' function attribute. + /// It is allowed on any FunctionOpInterface operations. + static StringRef getReadnoneAttrName() { + return "llvm.readnone"; + } + private: /// A cache storing compatible LLVM types that have been verified. This /// can save us lots of verification time if there are many occurrences Index: mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp =================================================================== --- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -2861,6 +2861,17 @@ << "' to be a `loopopts` attribute"; } + if (attr.getName() == LLVMDialect::getReadnoneAttrName()) { + const auto attrName = LLVMDialect::getReadnoneAttrName(); + if (!isa(op)) + return op->emitOpError() + << "'" << attrName + << "' is permitted only on FunctionOpInterface operations"; + if (!attr.getValue().isa()) + return op->emitOpError() + << "expected '" << attrName << "' to be a unit attribute"; + } + if (attr.getName() == LLVMDialect::getStructAttrsAttrName()) { return op->emitOpError() << "'" << LLVM::LLVMDialect::getStructAttrsAttrName() Index: mlir/lib/Target/LLVMIR/ModuleTranslation.cpp =================================================================== --- mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -927,6 +927,10 @@ mapFunction(function.getName(), llvmFunc); addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc); + if (function->getAttrOfType(LLVMDialect::getReadnoneAttrName())) { + llvmFunc->addFnAttr(llvm::Attribute::ReadNone); + } + // Forward the pass-through attributes to LLVM. if (failed(forwardPassthroughAttributes( function.getLoc(), function.getPassthrough(), llvmFunc))) Index: mlir/test/Dialect/LLVMIR/func.mlir =================================================================== --- mlir/test/Dialect/LLVMIR/func.mlir +++ mlir/test/Dialect/LLVMIR/func.mlir @@ -277,3 +277,21 @@ "llvm.func"() ({ }) {sym_name = "generic_unknown_calling_convention", CConv = #llvm.cconv, function_type = !llvm.func} : () -> () } + +// ----- + +module { + // expected-error@+3 {{'llvm.readnone' is permitted only on FunctionOpInterface operations}} + "llvm.func"() ({ + ^bb0: + llvm.return {llvm.readnone} + }) {sym_name = "readnone_return", function_type = !llvm.func} : () -> () +} + +// ----- + +module { + // expected-error@+1 {{op expected 'llvm.readnone' to be a unit attribute}} + "llvm.func"() ({ + }) {sym_name = "readnone_func", llvm.readnone = true, function_type = !llvm.func} : () -> () +} Index: mlir/test/Target/LLVMIR/llvmir.mlir =================================================================== --- mlir/test/Target/LLVMIR/llvmir.mlir +++ mlir/test/Target/LLVMIR/llvmir.mlir @@ -1937,3 +1937,11 @@ // CHECK: ret void llvm.return } + +// ----- + +// Function attributes: readnone + +// CHECK: declare void @readnone_function() #[[ATTR:[0-9]+]] +// CHECK: attributes #[[ATTR]] = { readnone } +llvm.func @readnone_function() attributes {llvm.readnone}