diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -37,6 +37,7 @@ static StringRef getDataLayoutAttrName() { return "llvm.data_layout"; } static StringRef getAlignAttrName() { return "llvm.align"; } static StringRef getNoAliasAttrName() { return "llvm.noalias"; } + static StringRef getReadonlyAttrName() { return "llvm.readonly"; } static StringRef getNoAliasScopesAttrName() { return "noalias_scopes"; } static StringRef getAliasScopesAttrName() { return "alias_scopes"; } static StringRef getLoopAttrName() { return "llvm.loop"; } diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -2821,6 +2821,15 @@ << "llvm.noalias attribute attached to non-pointer result"; return success(); } + if (name == LLVMDialect::getReadonlyAttrName()) { + if (!attrValue.isa()) + return op->emitError() << "expected llvm.readonly result attribute to " + "be a unit attribute"; + if (verifyValueType && !resTy.isa()) + return op->emitError() + << "llvm.readonly attribute attached to non-pointer result"; + return success(); + } if (name == LLVMDialect::getNoUndefAttrName()) { if (!attrValue.isa()) return op->emitError() << "expected llvm.noundef result attribute to " diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -924,6 +924,13 @@ "llvm.noalias attribute attached to LLVM non-pointer argument"); llvmArg.addAttr(llvm::Attribute::AttrKind::NoAlias); } + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getReadonlyAttrName())) { + if (!mlirArgTy.isa()) + return function.emitError( + "llvm.readonly attribute attached to LLVM non-pointer argument"); + llvmArg.addAttr(llvm::Attribute::AttrKind::ReadOnly); + } if (auto attr = function.getArgAttrOfType( argIdx, LLVMDialect::getAlignAttrName())) { diff --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir --- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir @@ -348,3 +348,10 @@ %0 = llvm.intr.experimental.stepvector : vector<7xf32> llvm.return %0 : vector<7xf32> } + +// ----- + +// expected-error @below{{llvm.readonly attribute attached to LLVM non-pointer argument}} +llvm.func @wrong_readonly_attribute(%vec : f32 {llvm.readonly}) { + llvm.return +} diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2022,3 +2022,7 @@ // CHECK: declare void @readnone_function() #[[ATTR:[0-9]+]] // CHECK: attributes #[[ATTR]] = { memory(none) } llvm.func @readnone_function() attributes {llvm.readnone} + +// ----- +// CHECK: declare void @readonly_function([[PTR:.+]] readonly) +llvm.func @readonly_function(%arg0: !llvm.ptr {llvm.readonly})