Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -542,7 +542,8 @@ ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50, ATTR_KIND_ALLOC_SIZE = 51, - ATTR_KIND_WRITEONLY = 52 + ATTR_KIND_WRITEONLY = 52, + ATTR_KIND_IMAGE = 53 }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -45,6 +45,9 @@ /// Pointer is either null or dereferenceable. def DereferenceableOrNull : EnumAttr<"dereferenceable_or_null">; +/// Argument is an image. +def Image : EnumAttr<"image">; + /// Function may only access memory that is inaccessible from IR. def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly">; Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -620,6 +620,7 @@ KEYWORD(convergent); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); + KEYWORD(image); KEYWORD(inaccessiblememonly); KEYWORD(inaccessiblemem_or_argmemonly); KEYWORD(inlinehint); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1080,6 +1080,7 @@ case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break; case lltok::kw_cold: B.addAttribute(Attribute::Cold); break; case lltok::kw_convergent: B.addAttribute(Attribute::Convergent); break; + case lltok::kw_image: B.addAttribute(Attribute::Image); break; case lltok::kw_inaccessiblememonly: B.addAttribute(Attribute::InaccessibleMemOnly); break; case lltok::kw_inaccessiblemem_or_argmemonly: @@ -1398,6 +1399,7 @@ B.addDereferenceableOrNullAttr(Bytes); continue; } + case lltok::kw_image: B.addAttribute(Attribute::Image); break; case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -170,6 +170,7 @@ kw_convergent, kw_dereferenceable, kw_dereferenceable_or_null, + kw_image, kw_inaccessiblememonly, kw_inaccessiblemem_or_argmemonly, kw_inlinehint, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1066,6 +1066,7 @@ case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; + case Attribute::Image: return 1ULL << 54; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; @@ -1202,6 +1203,8 @@ return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; + case bitc::ATTR_KIND_IMAGE: + return Attribute::Image; case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: return Attribute::InaccessibleMemOnly; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -615,6 +615,8 @@ return bitc::ATTR_KIND_COLD; case Attribute::InaccessibleMemOnly: return bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY; + case Attribute::Image: + return bitc::ATTR_KIND_IMAGE; case Attribute::InaccessibleMemOrArgMemOnly: return bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY; case Attribute::InlineHint: Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -258,6 +258,8 @@ return "swifterror"; if (hasAttribute(Attribute::SwiftSelf)) return "swiftself"; + if (hasAttribute(Attribute::Image)) + return "image"; if (hasAttribute(Attribute::InaccessibleMemOnly)) return "inaccessiblememonly"; if (hasAttribute(Attribute::InaccessibleMemOrArgMemOnly)) @@ -1459,7 +1461,6 @@ .addDereferenceableAttr(1) // the int here is ignored .addDereferenceableOrNullAttr(1) // the int here is ignored .addAttribute(Attribute::ReadNone) - .addAttribute(Attribute::ReadOnly) .addAttribute(Attribute::StructRet) .addAttribute(Attribute::InAlloca); Index: lib/Target/NVPTX/NVPTXUtilities.cpp =================================================================== --- lib/Target/NVPTX/NVPTXUtilities.cpp +++ lib/Target/NVPTX/NVPTXUtilities.cpp @@ -173,43 +173,25 @@ } bool isImageReadOnly(const Value &val) { - if (const Argument *arg = dyn_cast(&val)) { - const Function *func = arg->getParent(); - std::vector annot; - if (findAllNVVMAnnotation(func, "rdoimage", annot)) { - if (is_contained(annot, arg->getArgNo())) - return true; - } - } + if (const Argument *Arg = dyn_cast(&val)) + return isImage(val) && Arg->hasAttribute(Attribute::ReadOnly); return false; } bool isImageWriteOnly(const Value &val) { - if (const Argument *arg = dyn_cast(&val)) { - const Function *func = arg->getParent(); - std::vector annot; - if (findAllNVVMAnnotation(func, "wroimage", annot)) { - if (is_contained(annot, arg->getArgNo())) - return true; - } - } + if (const Argument *Arg = dyn_cast(&val)) + return isImage(val) && Arg->hasAttribute(Attribute::WriteOnly); return false; } bool isImageReadWrite(const Value &val) { - if (const Argument *arg = dyn_cast(&val)) { - const Function *func = arg->getParent(); - std::vector annot; - if (findAllNVVMAnnotation(func, "rdwrimage", annot)) { - if (is_contained(annot, arg->getArgNo())) - return true; - } - } - return false; + return isImage(val) && !isImageReadOnly(val) && !isImageWriteOnly(val); } bool isImage(const Value &val) { - return isImageReadOnly(val) || isImageWriteOnly(val) || isImageReadWrite(val); + if (const Argument *Arg = dyn_cast(&val)) + return Arg->hasAttribute(Attribute::Image); + return false; } bool isManaged(const Value &val) { Index: test/CodeGen/NVPTX/nvcl-param-align.ll =================================================================== --- test/CodeGen/NVPTX/nvcl-param-align.ll +++ test/CodeGen/NVPTX/nvcl-param-align.ll @@ -3,14 +3,13 @@ target triple = "nvptx-unknown-nvcl" ; CHECK-LABEL: .entry foo( -define void @foo(i64 %img, i64 %sampler, <5 x float>* %v) { +define void @foo(i64 readonly image %img, i64 %sampler, <5 x float>* %v) { ; The parameter alignment should be the next power of 2 of 5xsizeof(float), ; which is 32. ; CHECK: .param .u32 .ptr .align 32 foo_param_2 ret void } -!nvvm.annotations = !{!1, !2, !3} +!nvvm.annotations = !{!1, !2} !1 = !{void (i64, i64, <5 x float>*)* @foo, !"kernel", i32 1} -!2 = !{void (i64, i64, <5 x float>*)* @foo, !"rdoimage", i32 0} -!3 = !{void (i64, i64, <5 x float>*)* @foo, !"sampler", i32 1} +!2 = !{void (i64, i64, <5 x float>*)* @foo, !"sampler", i32 1} Index: test/CodeGen/NVPTX/surf-read.ll =================================================================== --- test/CodeGen/NVPTX/surf-read.ll +++ test/CodeGen/NVPTX/surf-read.ll @@ -5,7 +5,7 @@ declare i32 @llvm.nvvm.suld.1d.i32.trap(i64, i32) ; CHECK: .entry foo -define void @foo(i64 %img, float* %red, i32 %idx) { +define void @foo(i64 image %img, float* %red, i32 %idx) { ; CHECK: suld.b.1d.b32.trap {%r[[RED:[0-9]+]]}, [foo_param_0, {%r{{[0-9]+}}}] %val = tail call i32 @llvm.nvvm.suld.1d.i32.trap(i64 %img, i32 %idx) ; CHECK: cvt.rn.f32.s32 %f[[REDF:[0-9]+]], %r[[RED]] @@ -15,6 +15,5 @@ ret void } -!nvvm.annotations = !{!1, !2} +!nvvm.annotations = !{!1} !1 = !{void (i64, float*, i32)* @foo, !"kernel", i32 1} -!2 = !{void (i64, float*, i32)* @foo, !"rdwrimage", i32 0} Index: test/CodeGen/NVPTX/surf-write.ll =================================================================== --- test/CodeGen/NVPTX/surf-write.ll +++ test/CodeGen/NVPTX/surf-write.ll @@ -5,12 +5,11 @@ declare void @llvm.nvvm.sust.b.1d.i32.trap(i64, i32, i32) ; CHECK: .entry foo -define void @foo(i64 %img, i32 %val, i32 %idx) { +define void @foo(i64 writeonly image %img, i32 %val, i32 %idx) { ; CHECK: sust.b.1d.b32.trap [foo_param_0, {%r{{[0-9]+}}}], {%r{{[0-9]+}}} tail call void @llvm.nvvm.sust.b.1d.i32.trap(i64 %img, i32 %idx, i32 %val) ret void } -!nvvm.annotations = !{!1, !2} +!nvvm.annotations = !{!1} !1 = !{void (i64, i32, i32)* @foo, !"kernel", i32 1} -!2 = !{void (i64, i32, i32)* @foo, !"wroimage", i32 0} Index: test/CodeGen/NVPTX/tex-read.ll =================================================================== --- test/CodeGen/NVPTX/tex-read.ll +++ test/CodeGen/NVPTX/tex-read.ll @@ -5,7 +5,7 @@ declare { float, float, float, float } @llvm.nvvm.tex.1d.v4f32.s32(i64, i64, i32) ; CHECK: .entry foo -define void @foo(i64 %img, i64 %sampler, float* %red, i32 %idx) { +define void @foo(i64 readonly image %img, i64 %sampler, float* %red, i32 %idx) { ; CHECK: tex.1d.v4.f32.s32 {%f[[RED:[0-9]+]], %f[[GREEN:[0-9]+]], %f[[BLUE:[0-9]+]], %f[[ALPHA:[0-9]+]]}, [foo_param_0, foo_param_1, {%r{{[0-9]+}}}] %val = tail call { float, float, float, float } @llvm.nvvm.tex.1d.v4f32.s32(i64 %img, i64 %sampler, i32 %idx) %ret = extractvalue { float, float, float, float } %val, 0 @@ -14,7 +14,6 @@ ret void } -!nvvm.annotations = !{!1, !2, !3} +!nvvm.annotations = !{!1, !2} !1 = !{void (i64, i64, float*, i32)* @foo, !"kernel", i32 1} -!2 = !{void (i64, i64, float*, i32)* @foo, !"rdoimage", i32 0} -!3 = !{void (i64, i64, float*, i32)* @foo, !"sampler", i32 1} +!2 = !{void (i64, i64, float*, i32)* @foo, !"sampler", i32 1}