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 @@ -56,7 +56,7 @@ static StringRef getNoFreeAttrName() { return "llvm.nofree"; } static StringRef getNonNullAttrName() { return "llvm.nonnull"; } static StringRef getPreallocatedAttrName() { return "llvm.preallocated"; } - static StringRef getReadonlyAttrName() { return "llvm.readonly"; } + static StringRef getReadOnlyAttrName() { return "llvm.readonly"; } static StringRef getReturnedAttrName() { return "llvm.returned"; } static StringRef getSExtAttrName() { return "llvm.signext"; } static StringRef getStackAlignmentAttrName() { return "llvm.alignstack"; } @@ -67,7 +67,7 @@ // alternative way of modeling memory effects on FunctionOpInterface. /// Name of the attribute that will cause the creation of a readnone memory /// effect when lowering to the LLVMDialect. - static StringRef getReadnoneAttrName() { return "llvm.readnone"; } + static StringRef getReadNoneAttrName() { return "llvm.readnone"; } /// Verifies if the given string is a well-formed data layout descriptor. /// Uses `reportError` to report errors. diff --git a/mlir/lib/Conversion/FuncToLLVM/AttrMapDetail.h b/mlir/lib/Conversion/FuncToLLVM/AttrMapDetail.h new file mode 100644 --- /dev/null +++ b/mlir/lib/Conversion/FuncToLLVM/AttrMapDetail.h @@ -0,0 +1,38 @@ +//===- AttrMapDetail.h - Attr conversion details ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef ATTRMAPDETAIL_H_ +#define ATTRMAPDETAIL_H_ + +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" + +namespace mlir { +namespace func { +namespace detail { + +/// Returns an optional StringRef of the LLVM attribute name corresponding +/// to the func arg attribute. +static std::optional lookupAttrToLLVMMapping(StringRef name) { + // Mapping from func attribute name to their corresponding LLVM name. + static const llvm::StringMap func2llvmMap = { + {FuncOp::getNoAliasAttrName(), LLVM::LLVMDialect::getNoAliasAttrName()}, + {FuncOp::getReadOnlyAttrName(), LLVM::LLVMDialect::getReadOnlyAttrName()}, + {FuncOp::getWriteOnlyAttrName(), + LLVM::LLVMDialect::getWriteOnlyAttrName()}}; + auto lu = func2llvmMap.find(name); + if (lu != func2llvmMap.end()) + return lu->second; + return std::nullopt; +} + +} // namespace detail +} // namespace func +} // namespace mlir + +#endif // ATTRMAPDETAIL_H_ 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 @@ -13,6 +13,7 @@ #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVMPass.h" +#include "AttrMapDetail.h" #include "mlir/Analysis/DataLayoutAnalysis.h" #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h" @@ -69,7 +70,7 @@ attr.getName() == func.getFunctionTypeAttrName() || attr.getName() == linkageAttrName || attr.getName() == varargsAttrName || - attr.getName() == LLVM::LLVMDialect::getReadnoneAttrName() || + attr.getName() == LLVM::LLVMDialect::getReadNoneAttrName() || (filterArgAndResAttrs && (attr.getName() == func.getArgAttrsAttrName() || attr.getName() == func.getResAttrsAttrName()))) @@ -332,6 +333,12 @@ LLVM::LLVMDialect::getInAllocaAttrName()) { convertedAttrs.push_back(rewriter.getNamedAttr( LLVM::LLVMDialect::getInAllocaAttrName(), convert(attr))); + } else if (auto llvmName = func::detail::lookupAttrToLLVMMapping( + attr.getName().getValue())) { + // unit attrs lookup in dict + assert(attr.getValue().isa()); + convertedAttrs.push_back(rewriter.getNamedAttr( + llvmName.value(), rewriter.getUnitAttr())); } else { convertedAttrs.push_back(attr); } @@ -371,7 +378,7 @@ } // Create a memory effect attribute corresponding to readnone. - StringRef readnoneAttrName = LLVM::LLVMDialect::getReadnoneAttrName(); + StringRef readnoneAttrName = LLVM::LLVMDialect::getReadNoneAttrName(); LLVM::MemoryEffectsAttr memoryAttr = {}; if (funcOp->hasAttr(readnoneAttrName)) { auto attr = funcOp->getAttrOfType(readnoneAttrName); diff --git a/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp b/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp --- a/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp +++ b/mlir/lib/Conversion/MathToLibm/MathToLibm.cpp @@ -148,7 +148,7 @@ // optimization opportunities (e.g. LICM) for backends targeting LLVM IR. // This will have to be changed, when strict FP behavior is supported // by Math dialect. - opFunc->setAttr(LLVM::LLVMDialect::getReadnoneAttrName(), + opFunc->setAttr(LLVM::LLVMDialect::getReadNoneAttrName(), UnitAttr::get(rewriter.getContext())); } assert(isa(SymbolTable::lookupSymbolIn(module, name))); 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 @@ -3061,8 +3061,8 @@ // Check a unit attribute that is attached to a pointer value. if (name == LLVMDialect::getNoAliasAttrName() || - name == LLVMDialect::getReadonlyAttrName() || - name == LLVMDialect::getReadnoneAttrName() || + name == LLVMDialect::getReadOnlyAttrName() || + name == LLVMDialect::getReadNoneAttrName() || name == LLVMDialect::getWriteOnlyAttrName() || name == LLVMDialect::getNestAttrName() || name == LLVMDialect::getNoCaptureAttrName() || @@ -3159,8 +3159,8 @@ name == LLVMDialect::getNoCaptureAttrName() || name == LLVMDialect::getNoFreeAttrName() || name == LLVMDialect::getPreallocatedAttrName() || - name == LLVMDialect::getReadnoneAttrName() || - name == LLVMDialect::getReadonlyAttrName() || + name == LLVMDialect::getReadNoneAttrName() || + name == LLVMDialect::getReadOnlyAttrName() || name == LLVMDialect::getReturnedAttrName() || name == LLVMDialect::getStackAlignmentAttrName() || name == LLVMDialect::getStructRetAttrName() || diff --git a/mlir/lib/Target/LLVMIR/AttrKindDetail.h b/mlir/lib/Target/LLVMIR/AttrKindDetail.h --- a/mlir/lib/Target/LLVMIR/AttrKindDetail.h +++ b/mlir/lib/Target/LLVMIR/AttrKindDetail.h @@ -45,8 +45,8 @@ {llvm::Attribute::AttrKind::NonNull, LLVMDialect::getNonNullAttrName()}, {llvm::Attribute::AttrKind::Preallocated, LLVMDialect::getPreallocatedAttrName()}, - {llvm::Attribute::AttrKind::ReadOnly, LLVMDialect::getReadonlyAttrName()}, - {llvm::Attribute::AttrKind::ReadNone, LLVMDialect::getReadnoneAttrName()}, + {llvm::Attribute::AttrKind::ReadOnly, LLVMDialect::getReadOnlyAttrName()}, + {llvm::Attribute::AttrKind::ReadNone, LLVMDialect::getReadNoneAttrName()}, {llvm::Attribute::AttrKind::Returned, LLVMDialect::getReturnedAttrName()}, {llvm::Attribute::AttrKind::SExt, LLVMDialect::getSExtAttrName()}, {llvm::Attribute::AttrKind::StackAlignment, 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 @@ -7,6 +7,13 @@ return } +// ----- +// READONLY-LABEL: func @check_readonly_writeonly +// READONLY-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 +} + // ----- // CHECK-LABEL: func @check_strided_memref_arguments( 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 @@ -2164,3 +2164,8 @@ memory = #llvm.memory_effects} // CHECK: attributes #[[ATTR]] = { memory(readwrite) } + +// ----- + +// 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})