Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -1243,6 +1243,14 @@ thread execution pattern under certain parallel execution models. Transformations that are execution model agnostic may not make the execution of a convergent operation control dependent on any additional values. +``inaccessiblememonly`` + This attribute indicates that the function may only access memory that + is not accessible by the module being compiled. This is a weaker form + of ``readnone``. +``inaccessiblemem_or_argmemonly`` + This attribute indicates that the function may only access memory that is + either not accessible by the module being compiled, or is pointed to + by its pointer arguments. This is a weaker form of ``argmemonly`` ``inlinehint`` This attribute indicates that the source code contained a hint that inlining this function is desirable (such as the "inline" keyword in Index: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h @@ -483,7 +483,9 @@ ATTR_KIND_ARGMEMONLY = 45, ATTR_KIND_SWIFT_SELF = 46, ATTR_KIND_SWIFT_ERROR = 47, - ATTR_KIND_NO_RECURSE = 48 + ATTR_KIND_NO_RECURSE = 48, + ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, + ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50 }; enum ComdatSelectionKindCodes { Index: llvm/trunk/include/llvm/IR/Attributes.td =================================================================== --- llvm/trunk/include/llvm/IR/Attributes.td +++ llvm/trunk/include/llvm/IR/Attributes.td @@ -41,6 +41,13 @@ /// Pointer is either null or dereferenceable. def DereferenceableOrNull : EnumAttr<"dereferenceable_or_null">; +/// Function may only access memory that is inaccessible from IR. +def InaccessibleMemOnly : EnumAttr<"inaccessiblememonly">; + +/// Function may only access memory that is either inaccessible from the IR, +/// or pointed to by its pointer arguments. +def InaccessibleMemOrArgMemOnly : EnumAttr<"inaccessiblemem_or_argmemonly">; + /// Pass structure in an alloca. def InAlloca : EnumAttr<"inalloca">; Index: llvm/trunk/include/llvm/IR/Function.h =================================================================== --- llvm/trunk/include/llvm/IR/Function.h +++ llvm/trunk/include/llvm/IR/Function.h @@ -293,6 +293,26 @@ } void setOnlyAccessesArgMemory() { addFnAttr(Attribute::ArgMemOnly); } + /// @brief Determine if the function may only access memory that is + /// inaccessible from the IR. + bool onlyAccessesInaccessibleMemory() const { + return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, + Attribute::InaccessibleMemOnly); + } + void setOnlyAccessesInaccessibleMemory() { + addFnAttr(Attribute::InaccessibleMemOnly); + } + + /// @brief Determine if the function may only access memory that is + // either inaccessible from the IR or pointed to by its arguments. + bool onlyAccessesInaccessibleMemOrArgMem() const { + return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, + Attribute::InaccessibleMemOrArgMemOnly); + } + void setOnlyAccessesInaccessibleMemOrArgMem() { + addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); + } + /// @brief Determine if the function cannot return. bool doesNotReturn() const { return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, Index: llvm/trunk/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLLexer.cpp +++ llvm/trunk/lib/AsmParser/LLLexer.cpp @@ -609,6 +609,8 @@ KEYWORD(convergent); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); + KEYWORD(inaccessiblememonly); + KEYWORD(inaccessiblemem_or_argmemonly); KEYWORD(inlinehint); KEYWORD(inreg); KEYWORD(jumptable); Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -995,6 +995,10 @@ 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_inaccessiblememonly: + B.addAttribute(Attribute::InaccessibleMemOnly); break; + case lltok::kw_inaccessiblemem_or_argmemonly: + B.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); break; case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break; case lltok::kw_jumptable: B.addAttribute(Attribute::JumpTable); break; case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break; Index: llvm/trunk/lib/AsmParser/LLToken.h =================================================================== --- llvm/trunk/lib/AsmParser/LLToken.h +++ llvm/trunk/lib/AsmParser/LLToken.h @@ -115,6 +115,8 @@ kw_convergent, kw_dereferenceable, kw_dereferenceable_or_null, + kw_inaccessiblememonly, + kw_inaccessiblemem_or_argmemonly, kw_inlinehint, kw_inreg, kw_jumptable, Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1230,6 +1230,10 @@ return Attribute::Cold; case bitc::ATTR_KIND_CONVERGENT: return Attribute::Convergent; + case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: + return Attribute::InaccessibleMemOnly; + case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: + return Attribute::InaccessibleMemOrArgMemOnly; case bitc::ATTR_KIND_INLINE_HINT: return Attribute::InlineHint; case bitc::ATTR_KIND_IN_REG: Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -178,6 +178,10 @@ return bitc::ATTR_KIND_IN_ALLOCA; case Attribute::Cold: return bitc::ATTR_KIND_COLD; + case Attribute::InaccessibleMemOnly: + return bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY; + case Attribute::InaccessibleMemOrArgMemOnly: + return bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY; case Attribute::InlineHint: return bitc::ATTR_KIND_INLINE_HINT; case Attribute::InReg: Index: llvm/trunk/lib/IR/Attributes.cpp =================================================================== --- llvm/trunk/lib/IR/Attributes.cpp +++ llvm/trunk/lib/IR/Attributes.cpp @@ -198,6 +198,10 @@ return "byval"; if (hasAttribute(Attribute::Convergent)) return "convergent"; + if (hasAttribute(Attribute::InaccessibleMemOnly)) + return "inaccessiblememonly"; + if (hasAttribute(Attribute::InaccessibleMemOrArgMemOnly)) + return "inaccessiblemem_or_argmemonly"; if (hasAttribute(Attribute::InAlloca)) return "inalloca"; if (hasAttribute(Attribute::InlineHint)) @@ -445,6 +449,8 @@ case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; case Attribute::NoRecurse: return 1ULL << 48; + case Attribute::InaccessibleMemOnly: return 1ULL << 49; + case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -1251,7 +1251,9 @@ I->getKindAsEnum() == Attribute::JumpTable || I->getKindAsEnum() == Attribute::Convergent || I->getKindAsEnum() == Attribute::ArgMemOnly || - I->getKindAsEnum() == Attribute::NoRecurse) { + I->getKindAsEnum() == Attribute::NoRecurse || + I->getKindAsEnum() == Attribute::InaccessibleMemOnly || + I->getKindAsEnum() == Attribute::InaccessibleMemOrArgMemOnly) { if (!isFunction) { CheckFailed("Attribute '" + I->getAsString() + "' only applies to functions!", V); @@ -1422,6 +1424,18 @@ "Attributes 'readnone and readonly' are incompatible!", V); Assert( + !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) && + Attrs.hasAttribute(AttributeSet::FunctionIndex, + Attribute::InaccessibleMemOrArgMemOnly)), + "Attributes 'readnone and inaccessiblemem_or_argmemonly' are incompatible!", V); + + Assert( + !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) && + Attrs.hasAttribute(AttributeSet::FunctionIndex, + Attribute::InaccessibleMemOnly)), + "Attributes 'readnone and inaccessiblememonly' are incompatible!", V); + + Assert( !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::NoInline) && Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline)), Index: llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test =================================================================== --- llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test +++ llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test @@ -1,3 +1,3 @@ ; RUN: not llvm-c-test --module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s -CHECK: Error parsing bitcode: Unknown attribute kind (50) +CHECK: Error parsing bitcode: Unknown attribute kind (52) Index: llvm/trunk/test/Bitcode/attributes.ll =================================================================== --- llvm/trunk/test/Bitcode/attributes.ll +++ llvm/trunk/test/Bitcode/attributes.ll @@ -204,7 +204,7 @@ ; CHECK: define void @f34() { call void @nobuiltin() nobuiltin -; CHECK: call void @nobuiltin() #28 +; CHECK: call void @nobuiltin() #30 ret void; } @@ -277,6 +277,16 @@ ret void } +; CHECK: define void @f48() #28 +define void @f48() inaccessiblememonly { + ret void +} + +; CHECK: define void @f49() #29 +define void @f49() inaccessiblemem_or_argmemonly { + ret void +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -305,4 +315,6 @@ ; CHECK: attributes #25 = { convergent } ; CHECK: attributes #26 = { argmemonly } ; CHECK: attributes #27 = { norecurse } -; CHECK: attributes #28 = { nobuiltin } +; CHECK: attributes #28 = { inaccessiblememonly } +; CHECK: attributes #29 = { inaccessiblemem_or_argmemonly } +; CHECK: attributes #30 = { nobuiltin } Index: llvm/trunk/test/Bitcode/compatibility.ll =================================================================== --- llvm/trunk/test/Bitcode/compatibility.ll +++ llvm/trunk/test/Bitcode/compatibility.ll @@ -503,6 +503,10 @@ ; CHECK:declare void @f.kvpair() #31 declare void @f.norecurse() norecurse ; CHECK: declare void @f.norecurse() #32 +declare void @f.inaccessiblememonly() inaccessiblememonly +; CHECK: declare void @f.inaccessiblememonly() #33 +declare void @f.inaccessiblemem_or_argmemonly() inaccessiblemem_or_argmemonly +; CHECK: declare void @f.inaccessiblemem_or_argmemonly() #34 ; Functions -- section declare void @f.section() section "80" @@ -561,7 +565,7 @@ ; Functions -- Personality constant declare void @llvm.donothing() nounwind readnone -; CHECK: declare void @llvm.donothing() #33 +; CHECK: declare void @llvm.donothing() #35 define void @f.no_personality() personality i8 3 { ; CHECK: define void @f.no_personality() personality i8 3 invoke void @llvm.donothing() to label %normal unwind label %exception @@ -1136,7 +1140,7 @@ ; CHECK: select <2 x i1> , <2 x i8> , <2 x i8> call void @f.nobuiltin() builtin - ; CHECK: call void @f.nobuiltin() #37 + ; CHECK: call void @f.nobuiltin() #39 call fastcc noalias i32* @f.noalias() noinline ; CHECK: call fastcc noalias i32* @f.noalias() #12 @@ -1516,11 +1520,13 @@ ; CHECK: attributes #30 = { uwtable } ; CHECK: attributes #31 = { "cpu"="cortex-a8" } ; CHECK: attributes #32 = { norecurse } -; CHECK: attributes #33 = { nounwind readnone } -; CHECK: attributes #34 = { argmemonly nounwind readonly } -; CHECK: attributes #35 = { argmemonly nounwind } -; CHECK: attributes #36 = { nounwind readonly } -; CHECK: attributes #37 = { builtin } +; CHECK: attributes #33 = { inaccessiblememonly } +; CHECK: attributes #34 = { inaccessiblemem_or_argmemonly } +; CHECK: attributes #35 = { nounwind readnone } +; CHECK: attributes #36 = { argmemonly nounwind readonly } +; CHECK: attributes #37 = { argmemonly nounwind } +; CHECK: attributes #38 = { nounwind readonly } +; CHECK: attributes #39 = { builtin } ;; Metadata Index: llvm/trunk/test/Bitcode/invalid.ll =================================================================== --- llvm/trunk/test/Bitcode/invalid.ll +++ llvm/trunk/test/Bitcode/invalid.ll @@ -1,6 +1,6 @@ ; RUN: not llvm-dis < %s.bc 2>&1 | FileCheck %s -; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (50) +; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (52) ; invalid.ll.bc has an invalid attribute number. ; The test checks that LLVM reports the error and doesn't access freed memory Index: llvm/trunk/test/LTO/X86/invalid.ll =================================================================== --- llvm/trunk/test/LTO/X86/invalid.ll +++ llvm/trunk/test/LTO/X86/invalid.ll @@ -1,4 +1,4 @@ ; RUN: not llvm-lto %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s -; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (50) +; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (52)