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 @@ -48,6 +48,8 @@ static StringRef getByRefAttrName() { return "llvm.byref"; } static StringRef getStructRetAttrName() { return "llvm.sret"; } static StringRef getInAllocaAttrName() { return "llvm.inalloca"; } + static StringRef getNoCaptureAttrName() { return "llvm.nocapture"; } + static StringRef getReadOnlyAttrName() { return "llvm.readonly"; } static StringRef getNoUndefAttrName() { return "llvm.noundef"; } static StringRef getSExtAttrName() { return "llvm.signext"; } static StringRef getZExtAttrName() { return "llvm.zeroext"; } 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 @@ -347,6 +347,16 @@ LLVM::LLVMDialect::getInAllocaAttrName()) { convertedAttrs.push_back(rewriter.getNamedAttr( LLVM::LLVMDialect::getInAllocaAttrName(), convert(attr))); + } else if (attr.getName().getValue() == + LLVM::LLVMDialect::getNoCaptureAttrName()) { + convertedAttrs.push_back( + rewriter.getNamedAttr(LLVM::LLVMDialect::getNoCaptureAttrName(), + rewriter.getUnitAttr())); + } else if (attr.getName().getValue() == + LLVM::LLVMDialect::getReadOnlyAttrName()) { + convertedAttrs.push_back( + rewriter.getNamedAttr(LLVM::LLVMDialect::getReadOnlyAttrName(), + rewriter.getUnitAttr())); } else { convertedAttrs.push_back(attr); } diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -1090,6 +1090,16 @@ builder.getStringAttr(LLVMDialect::getInAllocaAttrName()), TypeAttr::get(mlirType))); } + if (func->getArg(it.index())->hasNoCaptureAttr()) { + argAttrs.push_back(NamedAttribute( + builder.getStringAttr(LLVMDialect::getNoCaptureAttrName()), + UnitAttr::get(context))); + } + if (func->getArg(it.index())->onlyReadsMemory()) { + argAttrs.push_back(NamedAttribute( + builder.getStringAttr(LLVMDialect::getReadOnlyAttrName()), + UnitAttr::get(context))); + } funcOp.setArgAttrs(it.index(), argAttrs); } 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 @@ -969,6 +969,24 @@ .addInAllocaAttr(convertType(attr.getValue()))); } + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getNoCaptureAttrName())) { + auto argTy = mlirArgTy.dyn_cast(); + if (!argTy) + return function.emitError( + "llvm.nocapture attribute attached to LLVM non-pointer argument"); + llvmArg.addAttr(llvm::Attribute::NoCapture); + } + + if (auto attr = function.getArgAttrOfType( + argIdx, LLVMDialect::getReadOnlyAttrName())) { + auto argTy = mlirArgTy.dyn_cast(); + if (!argTy) + return function.emitError( + "llvm.readonly attribute attached to LLVM non-pointer argument"); + llvmArg.addAttr(llvm::Attribute::ReadOnly); + } + if (auto attr = function.getArgAttrOfType(argIdx, "llvm.nest")) { if (!mlirArgTy.isa()) diff --git a/mlir/test/Dialect/LLVMIR/func.mlir b/mlir/test/Dialect/LLVMIR/func.mlir --- a/mlir/test/Dialect/LLVMIR/func.mlir +++ b/mlir/test/Dialect/LLVMIR/func.mlir @@ -120,6 +120,10 @@ llvm.func @llvm_align_decl(!llvm.ptr {llvm.align = 4}) // CHECK: llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32}) llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32}) + // CHECK: llvm.func @nocaptureattr_decl(!llvm.ptr {llvm.nocapture}) + llvm.func @nocaptureattr_decl(!llvm.ptr {llvm.nocapture}) + // CHECK: llvm.func @readonlyattr_decl(!llvm.ptr {llvm.readonly}) + llvm.func @readonlyattr_decl(!llvm.ptr {llvm.readonly}) // CHECK: llvm.func @variadic(...) diff --git a/mlir/test/Target/LLVMIR/Import/func-attrs.ll b/mlir/test/Target/LLVMIR/Import/func-attrs.ll --- a/mlir/test/Target/LLVMIR/Import/func-attrs.ll +++ b/mlir/test/Target/LLVMIR/Import/func-attrs.ll @@ -1,6 +1,6 @@ ; RUN: mlir-translate -import-llvm %s | FileCheck %s -; CHECK: llvm.func @foo(%arg0: !llvm.ptr {llvm.byval = i64}, %arg1: !llvm.ptr {llvm.byref = i64}, %arg2: !llvm.ptr {llvm.sret = i64}, %arg3: !llvm.ptr {llvm.inalloca = i64}) -define void @foo(ptr byval(i64) %arg0, ptr byref(i64) %arg1, ptr sret(i64) %arg2, ptr inalloca(i64) %arg3) { +; CHECK: llvm.func @foo(%arg0: !llvm.ptr {llvm.byval = i64}, %arg1: !llvm.ptr {llvm.byref = i64}, %arg2: !llvm.ptr {llvm.sret = i64}, %arg3: !llvm.ptr {llvm.inalloca = i64}, %arg4: !llvm.ptr {llvm.nocapture}, %arg5: !llvm.ptr {llvm.readonly}) +define void @foo(ptr byval(i64) %arg0, ptr byref(i64) %arg1, ptr sret(i64) %arg2, ptr inalloca(i64) %arg3, ptr nocapture %arg4, ptr readonly %arg5) { ret void } 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 @@ -63,7 +63,7 @@ // ----- // expected-error @below{{llvm.inalloca attribute attached to LLVM non-pointer argument}} -llvm.func @invalid_byval(%arg0 : f32 {llvm.inalloca = f32}) -> f32 { +llvm.func @invalid_inalloca(%arg0 : f32 {llvm.inalloca = f32}) -> f32 { llvm.return %arg0 : f32 } @@ -76,6 +76,20 @@ // ----- +// expected-error @below{{llvm.nocapture attribute attached to LLVM non-pointer argument}} +llvm.func @invalid_nocapture(%arg0 : f32 {llvm.nocapture}) -> f32 { + llvm.return %arg0 : f32 +} + +// ----- + +// expected-error @below{{llvm.readonly attribute attached to LLVM non-pointer argument}} +llvm.func @invalid_readonly(%arg0 : f32 {llvm.readonly}) -> f32 { + llvm.return %arg0 : f32 +} + +// ----- + // expected-error @below{{llvm.align attribute attached to LLVM non-pointer argument}} llvm.func @invalid_align(%arg0 : f32 {llvm.align = 4}) -> f32 { llvm.return %arg0 : f32 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 @@ -1108,6 +1108,22 @@ // CHECK-LABEL: declare void @inallocaattr_decl(ptr inalloca(i32)) llvm.func @inallocaattr_decl(!llvm.ptr {llvm.inalloca = i32}) +// CHECK-LABEL: define void @nocaptureattr(ptr nocapture % +llvm.func @nocaptureattr(%arg0: !llvm.ptr {llvm.nocapture}) { + llvm.return +} + +// CHECK-LABEL: declare void @nocaptureattr_decl(ptr nocapture) +llvm.func @nocaptureattr_decl(%arg0: !llvm.ptr {llvm.nocapture}) + +// CHECK-LABEL: define void @readonlyattr(ptr readonly % +llvm.func @readonlyattr(%arg0: !llvm.ptr {llvm.readonly}) { + llvm.return +} + +// CHECK-LABEL: declare void @readonlyattr_decl(ptr readonly) +llvm.func @readonlyattr_decl(%arg0: !llvm.ptr {llvm.readonly}) + // CHECK-LABEL: define void @signextattr(i1 signext % llvm.func @signextattr(%arg0: i1 {llvm.signext}) { llvm.return