diff --git a/mlir/include/mlir/Dialect/Func/IR/FuncOps.td b/mlir/include/mlir/Dialect/Func/IR/FuncOps.td --- a/mlir/include/mlir/Dialect/Func/IR/FuncOps.td +++ b/mlir/include/mlir/Dialect/Func/IR/FuncOps.td @@ -321,6 +321,15 @@ //===------------------------------------------------------------------===// bool isDeclaration() { return isExternal(); } + + //===------------------------------------------------------------------===// + // FuncOp Methods + //===------------------------------------------------------------------===// + + /// Arg attributes for access modes + static StringRef getReadOnlyAttrName() { return "func.readonly"; } + static StringRef getWriteOnlyAttrName() { return "func.writeonly"; } + static StringRef getNoAliasAttrName() { return "func.noalias"; } }]; let hasCustomAssemblyFormat = 1; } 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 @@ -38,6 +38,7 @@ static StringRef getAlignAttrName() { return "llvm.align"; } static StringRef getNoAliasAttrName() { return "llvm.noalias"; } static StringRef getReadonlyAttrName() { return "llvm.readonly"; } + static StringRef getWriteonlyAttrName() { return "llvm.writeonly"; } static StringRef getNoAliasScopesAttrName() { return "noalias_scopes"; } static StringRef getAliasScopesAttrName() { return "alias_scopes"; } static StringRef getLoopAttrName() { return "llvm.loop"; } diff --git a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp --- a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp +++ b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp @@ -343,6 +343,21 @@ LLVM::LLVMDialect::getInAllocaAttrName()) { convertedAttrs.push_back(rewriter.getNamedAttr( LLVM::LLVMDialect::getInAllocaAttrName(), convert(attr))); + } else if (attr.getName().getValue() == + func::FuncOp::getReadOnlyAttrName()) { + assert(attr.getValue().isa()); + convertedAttrs.push_back(rewriter.getNamedAttr( + LLVM::LLVMDialect::getReadonlyAttrName(), rewriter.getUnitAttr())); + } else if (attr.getName().getValue() == + func::FuncOp::getWriteOnlyAttrName()) { + assert(attr.getValue().isa()); + convertedAttrs.push_back(rewriter.getNamedAttr( + LLVM::LLVMDialect::getWriteonlyAttrName(), rewriter.getUnitAttr())); + } else if (attr.getName().getValue() == + func::FuncOp::getNoAliasAttrName()) { + assert(attr.getValue().isa()); + convertedAttrs.push_back(rewriter.getNamedAttr( + LLVM::LLVMDialect::getNoAliasAttrName(), rewriter.getUnitAttr())); } else { convertedAttrs.push_back(attr); } 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 @@ -931,6 +931,14 @@ "llvm.readonly attribute attached to LLVM non-pointer argument"); llvmArg.addAttr(llvm::Attribute::AttrKind::ReadOnly); } + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getWriteonlyAttrName())) { + if (!mlirArgTy.isa()) + return function.emitError( + "llvm.readonly attribute attached to LLVM non-pointer argument"); + llvmArg.addAttr(llvm::Attribute::AttrKind::WriteOnly); + } + if (auto attr = function.getArgAttrOfType( argIdx, LLVMDialect::getAlignAttrName())) { diff --git a/mlir/test/Conversion/FuncToLLVM/func-memref.mlir b/mlir/test/Conversion/FuncToLLVM/func-memref.mlir --- a/mlir/test/Conversion/FuncToLLVM/func-memref.mlir +++ b/mlir/test/Conversion/FuncToLLVM/func-memref.mlir @@ -3,7 +3,14 @@ // BAREPTR-LABEL: func @check_noalias // BAREPTR-SAME: %{{.*}}: !llvm.ptr {llvm.noalias}, %{{.*}}: !llvm.ptr {llvm.noalias} -func.func @check_noalias(%static : memref<2xf32> {llvm.noalias}, %other : memref<2xf32> {llvm.noalias}) { +func.func @check_noalias(%static : memref<2xf32> {func.noalias}, %other : memref<2xf32> {llvm.noalias}) { + return +} + +// ----- +// BAREPTR-LABEL: func @check_readonly_writeonly +// BAREPTR-SAME: %{{.*}}: !llvm.ptr {llvm.readonly}, %{{.*}}: !llvm.ptr {llvm.writeonly} +func.func @check_readonly_writeonly(%static : memref<2xf32> {func.readonly}, %other : memref<2xf32> {func.writeonly}) { 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 @@ -2034,5 +2034,5 @@ llvm.func @readnone_function() attributes {llvm.readnone} // ----- -// CHECK: declare void @readonly_function([[PTR:.+]] readonly) -llvm.func @readonly_function(%arg0: !llvm.ptr {llvm.readonly}) +// CHECK: declare void @readonly_writeonly_function([[PTR:.+]] readonly, [[PTR2:.+]] writeonly) +llvm.func @readonly_writeonly_function(%arg0: !llvm.ptr {llvm.readonly}, %arg1: !llvm.ptr {llvm.writeonly})