https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/120783
>From 54d3ac991abaa341dd4798bbf6aeb3ede4441d64 Mon Sep 17 00:00:00 2001 From: Antonio Frighetto <m...@antoniofrighetto.com> Date: Fri, 20 Dec 2024 19:30:59 +0100 Subject: [PATCH] [IR][ModRef] Introduce `errno` memory location Model C/C++ `errno` macro by adding a corresponding `errno` memory location kind to the IR. Preliminary work to separate `errno` writes from other memory accesses, to the benefit of alias analyses and optimization correctness. Previous discussion: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972. --- .../CodeGen/sanitize-metadata-nosanitize.c | 18 +++--- clang/test/CodeGenOpenCL/convergent.cl | 2 +- llvm/include/llvm/AsmParser/LLToken.h | 4 ++ llvm/include/llvm/Bitcode/LLVMBitCodes.h | 3 + llvm/include/llvm/IR/Function.h | 15 +++++ llvm/include/llvm/IR/InstrTypes.h | 15 +++++ llvm/include/llvm/Support/ModRef.h | 57 ++++++++++++++++++- llvm/lib/AsmParser/LLLexer.cpp | 4 ++ llvm/lib/AsmParser/LLParser.cpp | 13 ++++- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 28 +++++++++ llvm/lib/IR/Attributes.cpp | 3 + llvm/lib/IR/Function.cpp | 29 ++++++++++ llvm/lib/IR/Instructions.cpp | 29 ++++++++++ llvm/lib/Support/ModRef.cpp | 3 + .../test/Assembler/memory-attribute-errors.ll | 6 +- llvm/test/Assembler/memory-attribute.ll | 12 ++++ .../Transforms/FunctionAttrs/argmemonly.ll | 22 +++---- .../Transforms/FunctionAttrs/nocapture.ll | 30 +++++----- .../FunctionAttrs/read-write-scc.ll | 4 +- .../Transforms/FunctionAttrs/readattrs.ll | 2 +- .../Transforms/FunctionAttrs/writeonly.ll | 4 +- .../InferFunctionAttrs/norecurse_debug.ll | 2 +- .../cfi-nounwind-direct-call.ll | 2 +- .../Transforms/SCCP/ipscp-drop-argmemonly.ll | 12 ++-- llvm/unittests/Support/ModRefTest.cpp | 4 +- mlir/test/Target/LLVMIR/llvmir.mlir | 10 ++-- 26 files changed, 272 insertions(+), 61 deletions(-) diff --git a/clang/test/CodeGen/sanitize-metadata-nosanitize.c b/clang/test/CodeGen/sanitize-metadata-nosanitize.c index fd2fdce31b52fb..77dc7d9d492ecc 100644 --- a/clang/test/CodeGen/sanitize-metadata-nosanitize.c +++ b/clang/test/CodeGen/sanitize-metadata-nosanitize.c @@ -10,7 +10,7 @@ // CHECK: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 2, ptr @__sanitizer_metadata_covered2.module_ctor, ptr @__sanitizer_metadata_covered2.module_ctor }, { i32, ptr, ptr } { i32 2, ptr @__sanitizer_metadata_atomics2.module_ctor, ptr @__sanitizer_metadata_atomics2.module_ctor }] // CHECK: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 2, ptr @__sanitizer_metadata_covered2.module_dtor, ptr @__sanitizer_metadata_covered2.module_dtor }, { i32, ptr, ptr } { i32 2, ptr @__sanitizer_metadata_atomics2.module_dtor, ptr @__sanitizer_metadata_atomics2.module_dtor }] //. -// CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) +// CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) // CHECK-LABEL: define dso_local void @escape // CHECK-SAME: (ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !pcsections [[META2:![0-9]+]] { // CHECK-NEXT: entry: @@ -21,7 +21,7 @@ __attribute__((noinline, not_tail_called)) void escape(const volatile void *p) { sink = p; } -// CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) +// CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none, errnomem: none) // CHECK-LABEL: define dso_local i32 @normal_function // CHECK-SAME: (ptr noundef [[X:%.*]], ptr nocapture noundef readonly [[Y:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !pcsections [[META4:![0-9]+]] { // CHECK-NEXT: entry: @@ -38,7 +38,7 @@ int normal_function(int *x, int *y) { return *y; } -// CHECK: Function Attrs: disable_sanitizer_instrumentation mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) +// CHECK: Function Attrs: disable_sanitizer_instrumentation mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none, errnomem: none) // CHECK-LABEL: define dso_local i32 @test_disable_sanitize_instrumentation // CHECK-SAME: (ptr noundef [[X:%.*]], ptr nocapture noundef readonly [[Y:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] { // CHECK-NEXT: entry: @@ -55,7 +55,7 @@ __attribute__((disable_sanitizer_instrumentation)) int test_disable_sanitize_ins return *y; } -// CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) +// CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none, errnomem: none) // CHECK-LABEL: define dso_local i32 @test_no_sanitize_thread // CHECK-SAME: (ptr noundef [[X:%.*]], ptr nocapture noundef readonly [[Y:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] !pcsections [[META14:![0-9]+]] { // CHECK-NEXT: entry: @@ -72,7 +72,7 @@ __attribute__((no_sanitize("thread"))) int test_no_sanitize_thread(int *x, int * return *y; } -// CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) +// CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none, errnomem: none) // CHECK-LABEL: define dso_local i32 @test_no_sanitize_all // CHECK-SAME: (ptr noundef [[X:%.*]], ptr nocapture noundef readonly [[Y:%.*]]) local_unnamed_addr #[[ATTR3]] !pcsections [[META14]] { // CHECK-NEXT: entry: @@ -89,10 +89,10 @@ __attribute__((no_sanitize("all"))) int test_no_sanitize_all(int *x, int *y) { return *y; } //. -// CHECK: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } -// CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } -// CHECK: attributes #[[ATTR2]] = { disable_sanitizer_instrumentation mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } -// CHECK: attributes #[[ATTR3]] = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "no_sanitize_thread" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none, errnomem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK: attributes #[[ATTR2]] = { disable_sanitizer_instrumentation mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none, errnomem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK: attributes #[[ATTR3]] = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none, errnomem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "no_sanitize_thread" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } // CHECK: attributes #[[ATTR4:[0-9]+]] = { nounwind "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } //. // CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} diff --git a/clang/test/CodeGenOpenCL/convergent.cl b/clang/test/CodeGenOpenCL/convergent.cl index 123adba7b40d2c..d64915205aabf6 100644 --- a/clang/test/CodeGenOpenCL/convergent.cl +++ b/clang/test/CodeGenOpenCL/convergent.cl @@ -133,7 +133,7 @@ kernel void assume_convergent_asm() __asm__ volatile("s_barrier"); } -// CHECK: attributes #0 = { nofree noinline norecurse nounwind " +// CHECK: attributes #0 = { nofree noinline norecurse nounwind memory(readwrite, errnomem: none) " // CHECK: attributes #1 = { {{[^}]*}}convergent{{[^}]*}} } // CHECK: attributes #2 = { {{[^}]*}}convergent{{[^}]*}} } // CHECK: attributes #3 = { {{[^}]*}}convergent noduplicate{{[^}]*}} } diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index 7b47bc88ddb25f..e36ebcb0f13b08 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -201,11 +201,15 @@ enum Kind { kw_readwrite, kw_argmem, kw_inaccessiblemem, + kw_errnomem, // Legacy memory attributes: kw_argmemonly, kw_inaccessiblememonly, kw_inaccessiblemem_or_argmemonly, + kw_inaccessiblemem_or_errnomemonly, + kw_inaccessiblemem_or_argmem_or_errnomemonly, + kw_errnomemonly, // Captures attribute: kw_address, diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 9eb38c3e448291..4d4911932fb181 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -789,6 +789,9 @@ enum AttributeKindCodes { ATTR_KIND_NO_DIVERGENCE_SOURCE = 100, ATTR_KIND_SANITIZE_TYPE = 101, ATTR_KIND_CAPTURES = 102, + ATTR_KIND_ERRNOMEMONLY = 103, + ATTR_KIND_INACCESSIBLEMEM_OR_ERRNOMEMONLY = 104, + ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEM_OR_ERRNOMEMONLY = 105, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h index e7afcbd31420c1..847b8367743234 100644 --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -575,11 +575,26 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> { bool onlyAccessesInaccessibleMemory() const; void setOnlyAccessesInaccessibleMemory(); + /// Determine if the function may only access errno memory. + bool onlyAccessesErrnoMemory() const; + void setOnlyAccessesErrnoMemory(); + /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. bool onlyAccessesInaccessibleMemOrArgMem() const; void setOnlyAccessesInaccessibleMemOrArgMem(); + /// Determine if the function may only access memory that is + /// either inaccessible from the IR or errno memory. + bool onlyAccessesInaccessibleMemOrErrnoMem() const; + void setOnlyAccessesInaccessibleMemOrErrnoMem(); + + /// Determine if the function may only access memory that is + /// either inaccessible from the IR, pointed to by its arguments, or errno + /// memory. + bool onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const; + void setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem(); + /// Determine if the function cannot return. bool doesNotReturn() const { return hasFnAttribute(Attribute::NoReturn); diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h index 47ddc7555594c5..5ef72e09292f3a 100644 --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -1909,11 +1909,26 @@ class CallBase : public Instruction { bool onlyAccessesInaccessibleMemory() const; void setOnlyAccessesInaccessibleMemory(); + /// Determine if the function may only access errno memory. + bool onlyAccessesErrnoMemory() const; + void setOnlyAccessesErrnoMemory(); + /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. bool onlyAccessesInaccessibleMemOrArgMem() const; void setOnlyAccessesInaccessibleMemOrArgMem(); + /// Determine if the function may only access memory that is + /// either inaccessible from the IR or errno memory. + bool onlyAccessesInaccessibleMemOrErrnoMem() const; + void setOnlyAccessesInaccessibleMemOrErrnoMem(); + + /// Determine if the function may only access memory that is + /// either inaccessible from the IR, pointed to by its arguments, or errno + /// memory. + bool onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const; + void setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem(); + /// Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { addFnAttr(Attribute::NoReturn); } diff --git a/llvm/include/llvm/Support/ModRef.h b/llvm/include/llvm/Support/ModRef.h index 9ecdab71ec8ca6..aa4ce8295c77a7 100644 --- a/llvm/include/llvm/Support/ModRef.h +++ b/llvm/include/llvm/Support/ModRef.h @@ -61,8 +61,10 @@ enum class IRMemLocation { ArgMem = 0, /// Memory that is inaccessible via LLVM IR. InaccessibleMem = 1, + /// Errno memory. + ErrnoMem = 2, /// Any other memory. - Other = 2, + Other = 3, /// Helpers to iterate all locations in the MemoryEffectsBase class. First = ArgMem, @@ -139,6 +141,11 @@ template <typename LocationEnum> class MemoryEffectsBase { return MemoryEffectsBase(Location::InaccessibleMem, MR); } + /// Create MemoryEffectsBase that can only access errno memory. + static MemoryEffectsBase errnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { + return MemoryEffectsBase(Location::ErrnoMem, MR); + } + /// Create MemoryEffectsBase that can only access inaccessible or argument /// memory. static MemoryEffectsBase @@ -149,6 +156,27 @@ template <typename LocationEnum> class MemoryEffectsBase { return FRMB; } + /// Create MemoryEffectsBase that can only access inaccessible or errno + /// memory. + static MemoryEffectsBase + inaccessibleOrErrnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { + MemoryEffectsBase FRMB = none(); + FRMB.setModRef(Location::ErrnoMem, MR); + FRMB.setModRef(Location::InaccessibleMem, MR); + return FRMB; + } + + /// Create MemoryEffectsBase that can only access inaccessible, argument or + /// errno memory. + static MemoryEffectsBase + inaccessibleOrArgOrErrnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { + MemoryEffectsBase FRMB = none(); + FRMB.setModRef(Location::ArgMem, MR); + FRMB.setModRef(Location::ErrnoMem, MR); + FRMB.setModRef(Location::InaccessibleMem, MR); + return FRMB; + } + /// Create MemoryEffectsBase from an encoded integer value (used by memory /// attribute). static MemoryEffectsBase createFromIntValue(uint32_t Data) { @@ -207,11 +235,21 @@ template <typename LocationEnum> class MemoryEffectsBase { return isModOrRefSet(getModRef(Location::ArgMem)); } + /// Whether this function may access errno memory. + bool doesAccessErrnoMem() const { + return isModOrRefSet(getModRef(Location::ErrnoMem)); + } + /// Whether this function only (at most) accesses inaccessible memory. bool onlyAccessesInaccessibleMem() const { return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory(); } + /// Whether this function only (at most) accesses errno memory. + bool onlyAccessesErrnoMem() const { + return getWithoutLoc(Location::ErrnoMem).doesNotAccessMemory(); + } + /// Whether this function only (at most) accesses argument and inaccessible /// memory. bool onlyAccessesInaccessibleOrArgMem() const { @@ -220,6 +258,23 @@ template <typename LocationEnum> class MemoryEffectsBase { .doesNotAccessMemory(); } + /// Whether this function only (at most) accesses inaccessible and errno + /// memory. + bool onlyAccessesInaccessibleOrErrnoMem() const { + return getWithoutLoc(Location::InaccessibleMem) + .getWithoutLoc(Location::ErrnoMem) + .doesNotAccessMemory(); + } + + /// Whether this function only (at most) accesses inaccessible, argument and + /// errno memory. + bool onlyAccessesInaccessibleOrArgOrErrnoMem() const { + return getWithoutLoc(Location::InaccessibleMem) + .getWithoutLoc(Location::ArgMem) + .getWithoutLoc(Location::ErrnoMem) + .doesNotAccessMemory(); + } + /// Intersect with other MemoryEffectsBase. MemoryEffectsBase operator&(MemoryEffectsBase Other) const { return MemoryEffectsBase(Data & Other.Data); diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 5ea507c009bdc6..7fcdd5d6f0df9c 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -701,9 +701,13 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(readwrite); KEYWORD(argmem); KEYWORD(inaccessiblemem); + KEYWORD(errnomem); KEYWORD(argmemonly); KEYWORD(inaccessiblememonly); + KEYWORD(errnomemonly); KEYWORD(inaccessiblemem_or_argmemonly); + KEYWORD(inaccessiblemem_or_errnomemonly); + KEYWORD(inaccessiblemem_or_argmem_or_errnomemonly); KEYWORD(address_is_null); KEYWORD(address); KEYWORD(provenance); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index fa0079bac435c1..55b352a44d8838 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1670,9 +1670,18 @@ static bool upgradeMemoryAttr(MemoryEffects &ME, lltok::Kind Kind) { case lltok::kw_inaccessiblememonly: ME &= MemoryEffects::inaccessibleMemOnly(); return true; + case lltok::kw_errnomemonly: + ME &= MemoryEffects::errnoMemOnly(); + return true; case lltok::kw_inaccessiblemem_or_argmemonly: ME &= MemoryEffects::inaccessibleOrArgMemOnly(); return true; + case lltok::kw_inaccessiblemem_or_errnomemonly: + ME &= MemoryEffects::inaccessibleOrErrnoMemOnly(); + return true; + case lltok::kw_inaccessiblemem_or_argmem_or_errnomemonly: + ME &= MemoryEffects::inaccessibleOrArgOrErrnoMemOnly(); + return true; default: return false; } @@ -2490,6 +2499,8 @@ static std::optional<MemoryEffects::Location> keywordToLoc(lltok::Kind Tok) { return IRMemLocation::ArgMem; case lltok::kw_inaccessiblemem: return IRMemLocation::InaccessibleMem; + case lltok::kw_errnomem: + return IRMemLocation::ErrnoMem; default: return std::nullopt; } @@ -2538,7 +2549,7 @@ std::optional<MemoryEffects> LLParser::parseMemoryAttr() { std::optional<ModRefInfo> MR = keywordToModRef(Lex.getKind()); if (!MR) { if (!Loc) - tokError("expected memory location (argmem, inaccessiblemem) " + tokError("expected memory location (argmem, inaccessiblemem, errnomem) " "or access kind (none, read, write, readwrite)"); else tokError("expected access kind (none, read, write, readwrite)"); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 551dfd4af88bb2..8165002e9d7204 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1910,6 +1910,10 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { return 1ULL << 62; case Attribute::NoFree: return 1ULL << 63; + // 7ULL << 36 is ErrnoMemOnly, which is upgraded separately. + // 7ULL << 37 is InaccessibleMemOrErrnoMemOnly, which is upgraded separately. + // 7ULL << 38 is InaccessibleMemOrArgOrErrnoMemOnly, which is upgraded + // separately. default: // Other attributes are not supported in the raw format, // as we ran out of space. @@ -1982,6 +1986,21 @@ static void decodeLLVMAttributesForBitcode(AttrBuilder &B, Attrs &= ~(1ULL << 53); ME &= MemoryEffects::writeOnly(); } + if (Attrs & (7ULL << 36)) { + // ErrnoMemOnly + Attrs &= ~(7ULL << 36); + ME &= MemoryEffects::errnoMemOnly(); + } + if (Attrs & (7ULL << 37)) { + // InaccessibleMemOrErrnoMemOnly + Attrs &= ~(7ULL << 37); + ME &= MemoryEffects::inaccessibleOrErrnoMemOnly(); + } + if (Attrs & (7ULL << 38)) { + // InaccessibleMemOrArgOrErrnoMemOnly + Attrs &= ~(7ULL << 38); + ME &= MemoryEffects::inaccessibleOrArgOrErrnoMemOnly(); + } if (ME != MemoryEffects::unknown()) B.addMemoryAttr(ME); } @@ -2289,9 +2308,18 @@ static bool upgradeOldMemoryAttribute(MemoryEffects &ME, uint64_t EncodedKind) { case bitc::ATTR_KIND_INACCESSIBLEMEM_ONLY: ME &= MemoryEffects::inaccessibleMemOnly(); return true; + case bitc::ATTR_KIND_ERRNOMEMONLY: + ME &= MemoryEffects::errnoMemOnly(); + return true; case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY: ME &= MemoryEffects::inaccessibleOrArgMemOnly(); return true; + case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ERRNOMEMONLY: + ME &= MemoryEffects::inaccessibleOrErrnoMemOnly(); + return true; + case bitc::ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEM_OR_ERRNOMEMONLY: + ME &= MemoryEffects::inaccessibleOrArgOrErrnoMemOnly(); + return true; default: return false; } diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index ceb31856283c9a..0ead5a26ce5bd3 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -643,6 +643,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const { case IRMemLocation::InaccessibleMem: OS << "inaccessiblemem: "; break; + case IRMemLocation::ErrnoMem: + OS << "errnomem: "; + break; case IRMemLocation::Other: llvm_unreachable("This is represented as the default access kind"); } diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index 9c5dd5aeb92e97..e4c64bcf9bc5d0 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -922,6 +922,14 @@ void Function::setOnlyAccessesInaccessibleMemory() { setMemoryEffects(getMemoryEffects() & MemoryEffects::inaccessibleMemOnly()); } +/// Determine if the function may only access errno memory. +bool Function::onlyAccessesErrnoMemory() const { + return getMemoryEffects().onlyAccessesErrnoMem(); +} +void Function::setOnlyAccessesErrnoMemory() { + setMemoryEffects(getMemoryEffects() & MemoryEffects::errnoMemOnly()); +} + /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. bool Function::onlyAccessesInaccessibleMemOrArgMem() const { @@ -932,6 +940,27 @@ void Function::setOnlyAccessesInaccessibleMemOrArgMem() { MemoryEffects::inaccessibleOrArgMemOnly()); } +/// Determine if the function may only access memory that is +/// either inaccessible from the IR or errno memory. +bool Function::onlyAccessesInaccessibleMemOrErrnoMem() const { + return getMemoryEffects().onlyAccessesInaccessibleOrErrnoMem(); +} +void Function::setOnlyAccessesInaccessibleMemOrErrnoMem() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::inaccessibleOrErrnoMemOnly()); +} + +/// Determine if the function may only access memory that is +/// either inaccessible from the IR, pointed to by its arguments or errno +/// memory. +bool Function::onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const { + return getMemoryEffects().onlyAccessesInaccessibleOrArgOrErrnoMem(); +} +void Function::setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::inaccessibleOrArgOrErrnoMemOnly()); +} + bool Function::isTargetIntrinsic() const { return Intrinsic::isTargetIntrinsic(IntID); } diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index b585d8cfbf2e2b..e3e17507e9acfb 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -665,6 +665,14 @@ void CallBase::setOnlyAccessesInaccessibleMemory() { setMemoryEffects(getMemoryEffects() & MemoryEffects::inaccessibleMemOnly()); } +/// Determine if the function may only access errno memory. +bool CallBase::onlyAccessesErrnoMemory() const { + return getMemoryEffects().onlyAccessesErrnoMem(); +} +void CallBase::setOnlyAccessesErrnoMemory() { + setMemoryEffects(getMemoryEffects() & MemoryEffects::errnoMemOnly()); +} + /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. bool CallBase::onlyAccessesInaccessibleMemOrArgMem() const { @@ -675,6 +683,27 @@ void CallBase::setOnlyAccessesInaccessibleMemOrArgMem() { MemoryEffects::inaccessibleOrArgMemOnly()); } +/// Determine if the function may only access memory that is +/// either inaccessible from the IR or errno memory. +bool CallBase::onlyAccessesInaccessibleMemOrErrnoMem() const { + return getMemoryEffects().onlyAccessesInaccessibleOrErrnoMem(); +} +void CallBase::setOnlyAccessesInaccessibleMemOrErrnoMem() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::inaccessibleOrErrnoMemOnly()); +} + +/// Determine if the function may only access memory that is +/// either inaccessible from the IR, pointed to by its arguments or errno +/// memory. +bool CallBase::onlyAccessesInaccessibleMemOrArgMemOrErrnoMem() const { + return getMemoryEffects().onlyAccessesInaccessibleOrArgOrErrnoMem(); +} +void CallBase::setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::inaccessibleOrArgOrErrnoMemOnly()); +} + //===----------------------------------------------------------------------===// // CallInst Implementation //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Support/ModRef.cpp b/llvm/lib/Support/ModRef.cpp index d3b3dd11171f16..2bb9bc945bd2e2 100644 --- a/llvm/lib/Support/ModRef.cpp +++ b/llvm/lib/Support/ModRef.cpp @@ -43,6 +43,9 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, MemoryEffects ME) { case IRMemLocation::InaccessibleMem: OS << "InaccessibleMem: "; break; + case IRMemLocation::ErrnoMem: + OS << "ErrnoMem: "; + break; case IRMemLocation::Other: OS << "Other: "; break; diff --git a/llvm/test/Assembler/memory-attribute-errors.ll b/llvm/test/Assembler/memory-attribute-errors.ll index 1fba90362e79b9..2eed11d9465d58 100644 --- a/llvm/test/Assembler/memory-attribute-errors.ll +++ b/llvm/test/Assembler/memory-attribute-errors.ll @@ -12,16 +12,16 @@ ; MISSING-ARGS: error: expected '(' declare void @fn() memory ;--- empty.ll -; EMPTY: error: expected memory location (argmem, inaccessiblemem) or access kind (none, read, write, readwrite) +; EMPTY: error: expected memory location (argmem, inaccessiblemem, errnomem) or access kind (none, read, write, readwrite) declare void @fn() memory() ;--- unterminated.ll ; UNTERMINATED: error: unterminated memory attribute declare void @fn() memory(read ;--- invalid-kind.ll -; INVALID-KIND: error: expected memory location (argmem, inaccessiblemem) or access kind (none, read, write, readwrite) +; INVALID-KIND: error: expected memory location (argmem, inaccessiblemem, errnomem) or access kind (none, read, write, readwrite) declare void @fn() memory(foo) ;--- other.ll -; OTHER: error: expected memory location (argmem, inaccessiblemem) or access kind (none, read, write, readwrite) +; OTHER: error: expected memory location (argmem, inaccessiblemem, errnomem) or access kind (none, read, write, readwrite) declare void @fn() memory(other: read) ;--- missing-colon.ll ; MISSING-COLON: error: expected ':' after location diff --git a/llvm/test/Assembler/memory-attribute.ll b/llvm/test/Assembler/memory-attribute.ll index 2f7d3980eb378b..effd4ce7c45483 100644 --- a/llvm/test/Assembler/memory-attribute.ll +++ b/llvm/test/Assembler/memory-attribute.ll @@ -40,6 +40,18 @@ declare void @fn_inaccessiblemem_write() memory(inaccessiblemem: write) ; CHECK: @fn_inaccessiblemem_readwrite() declare void @fn_inaccessiblemem_readwrite() memory(inaccessiblemem: readwrite) +; CHECK: Function Attrs: memory(errnomem: read) +; CHECK: @fn_errnomem_read() +declare void @fn_errnomem_read() memory(errnomem: read) + +; CHECK: Function Attrs: memory(errnomem: write) +; CHECK: @fn_errnomem_write() +declare void @fn_errnomem_write() memory(errnomem: write) + +; CHECK: Function Attrs: memory(errnomem: readwrite) +; CHECK: @fn_errnomem_readwrite() +declare void @fn_errnomem_readwrite() memory(errnomem: readwrite) + ; CHECK: Function Attrs: memory(read, argmem: readwrite) ; CHECK: @fn_read_argmem_readwrite() declare void @fn_read_argmem_readwrite() memory(read, argmem: readwrite) diff --git a/llvm/test/Transforms/FunctionAttrs/argmemonly.ll b/llvm/test/Transforms/FunctionAttrs/argmemonly.ll index 5bbe6fa7c27c2e..6f3bd8c5ae0de6 100644 --- a/llvm/test/Transforms/FunctionAttrs/argmemonly.ll +++ b/llvm/test/Transforms/FunctionAttrs/argmemonly.ll @@ -56,7 +56,7 @@ entry: } define i32 @test_read_global() { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i32 @test_read_global ; FNATTRS-SAME: () #[[ATTR2:[0-9]+]] { ; FNATTRS-NEXT: entry: @@ -76,7 +76,7 @@ entry: } define i32 @test_read_loaded_ptr(ptr %ptr) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i32 @test_read_loaded_ptr ; FNATTRS-SAME: (ptr nocapture readonly [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { ; FNATTRS-NEXT: entry: @@ -119,7 +119,7 @@ entry: } define void @test_write_global() { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test_write_global ; FNATTRS-SAME: () #[[ATTR5:[0-9]+]] { ; FNATTRS-NEXT: entry: @@ -243,7 +243,7 @@ declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1) @arr = global [32 x i8] zeroinitializer define void @test_memcpy_src_global(ptr %dst) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test_memcpy_src_global ; FNATTRS-SAME: (ptr nocapture writeonly initializes((0, 32)) [[DST:%.*]]) #[[ATTR11:[0-9]+]] { ; FNATTRS-NEXT: entry: @@ -263,7 +263,7 @@ entry: } define void @test_memcpy_dst_global(ptr %src) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test_memcpy_dst_global ; FNATTRS-SAME: (ptr nocapture readonly [[SRC:%.*]]) #[[ATTR11]] { ; FNATTRS-NEXT: entry: @@ -388,7 +388,7 @@ define void @test_inaccessibleorargmemonly_readwrite(ptr %arg) { } define void @test_recursive_argmem_read(ptr %p) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test_recursive_argmem_read ; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR16:[0-9]+]] { ; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 @@ -408,7 +408,7 @@ define void @test_recursive_argmem_read(ptr %p) { } define void @test_recursive_argmem_readwrite(ptr %p) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(readwrite, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(readwrite, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test_recursive_argmem_readwrite ; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR17:[0-9]+]] { ; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 @@ -454,7 +454,7 @@ define void @test_recursive_argmem_read_alloca(ptr %p) { } define void @test_scc_argmem_read_1(ptr %p) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test_scc_argmem_read_1 ; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR16]] { ; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 @@ -474,7 +474,7 @@ define void @test_scc_argmem_read_1(ptr %p) { } define void @test_scc_argmem_read_2(ptr %p) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test_scc_argmem_read_2 ; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) #[[ATTR16]] { ; FNATTRS-NEXT: call void @test_scc_argmem_read_1(ptr [[P]]) @@ -518,7 +518,7 @@ entry: ; FIXME: This could be `memory(argmem: read)`. define i64 @select_different_obj(i1 %c, ptr %p, ptr %p2) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i64 @select_different_obj ; FNATTRS-SAME: (i1 [[C:%.*]], ptr nocapture readonly [[P:%.*]], ptr nocapture readonly [[P2:%.*]]) #[[ATTR3]] { ; FNATTRS-NEXT: entry: @@ -580,7 +580,7 @@ join: ; FIXME: This could be `memory(argmem: read)`. define i64 @phi_different_obj(i1 %c, ptr %p, ptr %p2) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i64 @phi_different_obj ; FNATTRS-SAME: (i1 [[C:%.*]], ptr nocapture readonly [[P:%.*]], ptr nocapture readonly [[P2:%.*]]) #[[ATTR3]] { ; FNATTRS-NEXT: entry: diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll index 7df6132ac6a315..ce2373ce574676 100644 --- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll +++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll @@ -20,7 +20,7 @@ define ptr @c1(ptr %q) { ; It would also be acceptable to mark %q as readnone. Update @c3 too. define void @c2(ptr %q) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @c2 ; FNATTRS-SAME: (ptr [[Q:%.*]]) #[[ATTR1:[0-9]+]] { ; FNATTRS-NEXT: store ptr [[Q]], ptr @g, align 8 @@ -37,7 +37,7 @@ define void @c2(ptr %q) { } define void @c3(ptr %q) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @c3 ; FNATTRS-SAME: (ptr [[Q:%.*]]) #[[ATTR2:[0-9]+]] { ; FNATTRS-NEXT: call void @c2(ptr [[Q]]) @@ -127,7 +127,7 @@ l1: @lookup_table = global [2 x i1] [ i1 0, i1 1 ] define i1 @c5(ptr %q, i32 %bitno) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i1 @c5 ; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR3:[0-9]+]] { ; FNATTRS-NEXT: [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32 @@ -222,7 +222,7 @@ define ptr @lookup_bit(ptr %q, i32 %bitno) readnone nounwind { } define i1 @c7(ptr %q, i32 %bitno) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i1 @c7 ; FNATTRS-SAME: (ptr readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR6:[0-9]+]] { ; FNATTRS-NEXT: [[PTR:%.*]] = call ptr @lookup_bit(ptr [[Q]], i32 [[BITNO]]) @@ -243,7 +243,7 @@ define i1 @c7(ptr %q, i32 %bitno) { define i32 @nc1(ptr %q, ptr %p, i1 %b) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i32 @nc1 ; FNATTRS-SAME: (ptr [[Q:%.*]], ptr nocapture [[P:%.*]], i1 [[B:%.*]]) #[[ATTR7:[0-9]+]] { ; FNATTRS-NEXT: e: @@ -284,7 +284,7 @@ l: } define i32 @nc1_addrspace(ptr %q, ptr addrspace(1) %p, i1 %b) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define i32 @nc1_addrspace ; FNATTRS-SAME: (ptr [[Q:%.*]], ptr addrspace(1) nocapture [[P:%.*]], i1 [[B:%.*]]) #[[ATTR7]] { ; FNATTRS-NEXT: e: @@ -328,7 +328,7 @@ l: } define void @nc2(ptr %p, ptr %q) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @nc2 ; FNATTRS-SAME: (ptr nocapture [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR7]] { ; FNATTRS-NEXT: [[TMP1:%.*]] = call i32 @nc1(ptr [[Q]], ptr [[P]], i1 false) @@ -398,7 +398,7 @@ define void @nc5(ptr %f, ptr %p) { ; It would be acceptable to add readnone to %y1_1 and %y1_2. define void @test1_1(ptr %x1_1, ptr %y1_1, i1 %c) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test1_1 ; FNATTRS-SAME: (ptr nocapture readnone [[X1_1:%.*]], ptr [[Y1_1:%.*]], i1 [[C:%.*]]) #[[ATTR10:[0-9]+]] { ; FNATTRS-NEXT: [[TMP1:%.*]] = call ptr @test1_2(ptr [[X1_1]], ptr [[Y1_1]], i1 [[C]]) @@ -418,7 +418,7 @@ define void @test1_1(ptr %x1_1, ptr %y1_1, i1 %c) { } define ptr @test1_2(ptr %x1_2, ptr %y1_2, i1 %c) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define ptr @test1_2 ; FNATTRS-SAME: (ptr nocapture readnone [[X1_2:%.*]], ptr returned [[Y1_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] { ; FNATTRS-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] @@ -450,7 +450,7 @@ f: } define void @test2(ptr %x2) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test2 ; FNATTRS-SAME: (ptr nocapture readnone [[X2:%.*]]) #[[ATTR10]] { ; FNATTRS-NEXT: call void @test2(ptr [[X2]]) @@ -470,7 +470,7 @@ define void @test2(ptr %x2) { } define void @test3(ptr %x3, ptr %y3, ptr %z3) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test3 ; FNATTRS-SAME: (ptr nocapture readnone [[X3:%.*]], ptr nocapture readnone [[Y3:%.*]], ptr nocapture readnone [[Z3:%.*]]) #[[ATTR10]] { ; FNATTRS-NEXT: call void @test3(ptr [[Z3]], ptr [[Y3]], ptr [[X3]]) @@ -490,7 +490,7 @@ define void @test3(ptr %x3, ptr %y3, ptr %z3) { } define void @test4_1(ptr %x4_1, i1 %c) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @test4_1 ; FNATTRS-SAME: (ptr [[X4_1:%.*]], i1 [[C:%.*]]) #[[ATTR10]] { ; FNATTRS-NEXT: [[TMP1:%.*]] = call ptr @test4_2(ptr [[X4_1]], ptr [[X4_1]], ptr [[X4_1]], i1 [[C]]) @@ -510,7 +510,7 @@ define void @test4_1(ptr %x4_1, i1 %c) { } define ptr @test4_2(ptr %x4_2, ptr %y4_2, ptr %z4_2, i1 %c) { -; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define ptr @test4_2 ; FNATTRS-SAME: (ptr nocapture readnone [[X4_2:%.*]], ptr readnone returned [[Y4_2:%.*]], ptr nocapture readnone [[Z4_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] { ; FNATTRS-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] @@ -674,7 +674,7 @@ entry: @g2 = global ptr null define void @captureLaunder(ptr %p) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: readwrite) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: readwrite, errnomem: none) ; FNATTRS-LABEL: define void @captureLaunder ; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR14:[0-9]+]] { ; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]]) @@ -718,7 +718,7 @@ entry: @g3 = global ptr null define void @captureStrip(ptr %p) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define void @captureStrip ; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR1]] { ; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]]) diff --git a/llvm/test/Transforms/FunctionAttrs/read-write-scc.ll b/llvm/test/Transforms/FunctionAttrs/read-write-scc.ll index be61990fd6278b..6dd48a04f3145f 100644 --- a/llvm/test/Transforms/FunctionAttrs/read-write-scc.ll +++ b/llvm/test/Transforms/FunctionAttrs/read-write-scc.ll @@ -4,7 +4,7 @@ @i = global i32 0 define void @foo() { -; CHECK: Function Attrs: nofree nosync nounwind memory(readwrite, argmem: none, inaccessiblemem: none) +; CHECK: Function Attrs: nofree nosync nounwind memory(readwrite, argmem: none, inaccessiblemem: none, errnomem: none) ; CHECK-LABEL: define {{[^@]+}}@foo ; CHECK-SAME: () #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: store i32 1, ptr @i, align 4 @@ -17,7 +17,7 @@ define void @foo() { } define void @bar() { -; CHECK: Function Attrs: nofree nosync nounwind memory(readwrite, argmem: none, inaccessiblemem: none) +; CHECK: Function Attrs: nofree nosync nounwind memory(readwrite, argmem: none, inaccessiblemem: none, errnomem: none) ; CHECK-LABEL: define {{[^@]+}}@bar ; CHECK-SAME: () #[[ATTR0]] { ; CHECK-NEXT: [[I:%.*]] = load i32, ptr @i, align 4 diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll index e60954c9cd29a3..6e597c5dd5ab36 100644 --- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll +++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll @@ -33,7 +33,7 @@ define void @test1_2(ptr %x1_2, ptr %y1_2, ptr %z1_2) { ; TODO: Missing with attributor-light: argmem: none, inaccessiblemem: none define ptr @test2(ptr %p) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define {{[^@]+}}@test2 ; FNATTRS-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] { ; FNATTRS-NEXT: store i32 0, ptr @x, align 4 diff --git a/llvm/test/Transforms/FunctionAttrs/writeonly.ll b/llvm/test/Transforms/FunctionAttrs/writeonly.ll index ba546aff6e6211..1d05711541d46d 100644 --- a/llvm/test/Transforms/FunctionAttrs/writeonly.ll +++ b/llvm/test/Transforms/FunctionAttrs/writeonly.ll @@ -44,7 +44,7 @@ nouses-argworn-funro_entry: @d-ccc = internal global %_type_of_d-ccc <{ ptr null, i8 1, i8 13, i8 0, i8 -127 }>, align 8 define void @nouses-argworn-funwo(ptr writeonly %.aaa) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funwo ; FNATTRS-SAME: (ptr nocapture readnone [[DOTAAA:%.*]]) #[[ATTR2:[0-9]+]] { ; FNATTRS-NEXT: nouses-argworn-funwo_entry: @@ -82,7 +82,7 @@ define void @test_store(ptr %p) { @G = external global ptr define i8 @test_store_capture(ptr %p) { -; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: read, inaccessiblemem: none) +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: read, inaccessiblemem: none, errnomem: none) ; FNATTRS-LABEL: define {{[^@]+}}@test_store_capture ; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] { ; FNATTRS-NEXT: store ptr [[P]], ptr @G, align 8 diff --git a/llvm/test/Transforms/InferFunctionAttrs/norecurse_debug.ll b/llvm/test/Transforms/InferFunctionAttrs/norecurse_debug.ll index c8568272d320fb..36791ae60fed60 100644 --- a/llvm/test/Transforms/InferFunctionAttrs/norecurse_debug.ll +++ b/llvm/test/Transforms/InferFunctionAttrs/norecurse_debug.ll @@ -52,5 +52,5 @@ attributes #1 = { nounwind readnone speculatable } !28 = !DILocation(line: 9, column: 18, scope: !2) !29 = !DILocation(line: 10, column: 1, scope: !2) -; CHECK: attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: write, inaccessiblemem: none) } +; CHECK: attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, argmem: write, inaccessiblemem: none, errnomem: none) } ; CHECK-NOT: foo.coefficient1 diff --git a/llvm/test/Transforms/LowerTypeTests/cfi-nounwind-direct-call.ll b/llvm/test/Transforms/LowerTypeTests/cfi-nounwind-direct-call.ll index 2795333effd76b..8e212040d66515 100644 --- a/llvm/test/Transforms/LowerTypeTests/cfi-nounwind-direct-call.ll +++ b/llvm/test/Transforms/LowerTypeTests/cfi-nounwind-direct-call.ll @@ -117,7 +117,7 @@ attributes #6 = { noreturn nounwind } ; CHECK-NEXT: ret i32 [[DOT]] ; ; -; CHECK: Function Attrs: minsize mustprogress nofree norecurse nosync nounwind optsize willreturn memory(write, argmem: none, inaccessiblemem: none) +; CHECK: Function Attrs: minsize mustprogress nofree norecurse nosync nounwind optsize willreturn memory(write, argmem: none, inaccessiblemem: none, errnomem: none) ; CHECK-LABEL: define dso_local noundef range(i32 0, 2) i32 @_Z10call_catchi ; CHECK-SAME: (i32 noundef [[NUM:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !type [[META4]] !type [[META5]] !type [[META6]] { ; CHECK-NEXT: entry: diff --git a/llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll b/llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll index 22726e0cac1f12..5e8c7cd21324d8 100644 --- a/llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll +++ b/llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll @@ -11,10 +11,10 @@ ; Here the pointer argument %arg will be replaced by a constant. We need to ; drop argmemonly. ;. -; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = internal global i32 0 +; CHECK: @g = internal global i32 0 ;. define internal void @ptrarg.1(ptr %arg, i32 %val) argmemonly nounwind { -; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none) +; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none, errnomem: none) ; CHECK-LABEL: @ptrarg.1( ; CHECK-NEXT: store i32 10, ptr @g, align 4 ; CHECK-NEXT: ret void @@ -62,7 +62,7 @@ define void @caller.2(ptr %ptr) { ; Here the pointer argument %arg will be replaced by a constant. We need to ; drop inaccessiblemem_or_argmemonly. define internal void @ptrarg.3(ptr %arg, i32 %val) inaccessiblemem_or_argmemonly nounwind { -; CHECK: Function Attrs: nounwind memory(readwrite) +; CHECK: Function Attrs: nounwind memory(readwrite, errnomem: none) ; CHECK-LABEL: @ptrarg.3( ; CHECK-NEXT: store i32 10, ptr @g, align 4 ; CHECK-NEXT: ret void @@ -110,7 +110,7 @@ define void @caller.4(ptr %ptr) { ; Here the pointer argument %arg will be replaced by a constant. We need to ; drop inaccessiblemem_or_argmemonly. define internal void @ptrarg.5(ptr %arg, i32 %val) argmemonly inaccessiblemem_or_argmemonly nounwind { -; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none) +; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none, errnomem: none) ; CHECK-LABEL: @ptrarg.5( ; CHECK-NEXT: store i32 10, ptr @g, align 4 ; CHECK-NEXT: ret void @@ -163,9 +163,9 @@ define i32 @caller.6.cs.attributes(i32 %n) { } ;. -; CHECK: attributes #[[ATTR0]] = { nounwind memory(readwrite, inaccessiblemem: none) } +; CHECK: attributes #[[ATTR0]] = { nounwind memory(readwrite, inaccessiblemem: none, errnomem: none) } ; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind memory(argmem: readwrite) } -; CHECK: attributes #[[ATTR2]] = { nounwind memory(readwrite) } +; CHECK: attributes #[[ATTR2]] = { nounwind memory(readwrite, errnomem: none) } ; CHECK: attributes #[[ATTR3:[0-9]+]] = { nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) } ; CHECK: attributes #[[ATTR4]] = { nounwind } ;. diff --git a/llvm/unittests/Support/ModRefTest.cpp b/llvm/unittests/Support/ModRefTest.cpp index 35107e50b32db7..9c13908da44bb0 100644 --- a/llvm/unittests/Support/ModRefTest.cpp +++ b/llvm/unittests/Support/ModRefTest.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ModRef.h" -#include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" #include <string> @@ -21,7 +20,8 @@ TEST(ModRefTest, PrintMemoryEffects) { std::string S; raw_string_ostream OS(S); OS << MemoryEffects::none(); - EXPECT_EQ(S, "ArgMem: NoModRef, InaccessibleMem: NoModRef, Other: NoModRef"); + EXPECT_EQ(S, "ArgMem: NoModRef, InaccessibleMem: NoModRef, ErrnoMem: " + "NoModRef, Other: NoModRef"); } } // namespace diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 51086bc655af24..80f0693fad7f5e 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2347,7 +2347,7 @@ llvm.func @readonly_function(%arg0: !llvm.ptr {llvm.readonly}) llvm.func @arg_mem_none_func() attributes { memory_effects = #llvm.memory_effects<other = readwrite, argMem = none, inaccessibleMem = readwrite>} -// CHECK: attributes #[[ATTR]] = { memory(readwrite, argmem: none) } +// CHECK: attributes #[[ATTR]] = { memory(readwrite, argmem: none, errnomem: none) } // ----- @@ -2355,7 +2355,7 @@ llvm.func @arg_mem_none_func() attributes { llvm.func @readwrite_func() attributes { memory_effects = #llvm.memory_effects<other = readwrite, argMem = readwrite, inaccessibleMem = readwrite>} -// CHECK: attributes #[[ATTR]] = { memory(readwrite) } +// CHECK: attributes #[[ATTR]] = { memory(readwrite, errnomem: none) } // ----- @@ -2613,11 +2613,11 @@ llvm.func @mem_effects_call() { // CHECK: #[[ATTRS_0]] // CHECK-SAME: memory(none) // CHECK: #[[ATTRS_1]] -// CHECK-SAME: memory(read, argmem: none, inaccessiblemem: write) +// CHECK-SAME: memory(read, argmem: none, inaccessiblemem: write, errnomem: none) // CHECK: #[[ATTRS_2]] -// CHECK-SAME: memory(read, inaccessiblemem: write) +// CHECK-SAME: memory(read, inaccessiblemem: write, errnomem: none) // CHECK: #[[ATTRS_3]] -// CHECK-SAME: memory(readwrite, argmem: read) +// CHECK-SAME: memory(readwrite, argmem: read, errnomem: none) // ----- _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits