https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/120783
>From 196421e40425290aa1296f63c8fd9fbf205ea4b9 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 | 5 ++ llvm/include/llvm/Bitcode/LLVMBitCodes.h | 4 ++ llvm/include/llvm/IR/Function.h | 20 ++++++ llvm/include/llvm/IR/InstrTypes.h | 20 ++++++ llvm/include/llvm/Support/ModRef.h | 68 +++++++++++++++++- llvm/lib/AsmParser/LLLexer.cpp | 5 ++ llvm/lib/AsmParser/LLParser.cpp | 16 ++++- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 37 ++++++++++ llvm/lib/IR/Attributes.cpp | 3 + llvm/lib/IR/Function.cpp | 39 ++++++++++ llvm/lib/IR/Instructions.cpp | 39 ++++++++++ llvm/lib/Support/ModRef.cpp | 3 + llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 14 ++++ .../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-errnomem.ll | 71 +++++++++++++++++++ .../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 +-- 28 files changed, 413 insertions(+), 61 deletions(-) create mode 100644 llvm/test/Transforms/FunctionAttrs/read-write-errnomem.ll diff --git a/clang/test/CodeGen/sanitize-metadata-nosanitize.c b/clang/test/CodeGen/sanitize-metadata-nosanitize.c index eabcbd1409fe2b..ff98d0b21e3f11 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 noundef readonly captures(none) [[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 noundef readonly captures(none) [[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 noundef readonly captures(none) [[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 noundef readonly captures(none) [[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 300d50c0959b7c..233fe7f78964b0 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -201,11 +201,16 @@ enum Kind { kw_readwrite, kw_argmem, kw_inaccessiblemem, + kw_errnomem, // Legacy attributes: kw_argmemonly, kw_inaccessiblememonly, kw_inaccessiblemem_or_argmemonly, + kw_inaccessiblemem_or_errnomemonly, + kw_argmem_or_errnomemonly, + kw_inaccessiblemem_or_argmem_or_errnomemonly, + kw_errnomemonly, kw_nocapture, // Captures attribute: diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 9eb38c3e448291..1dd72b479fb93e 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -789,6 +789,10 @@ 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_ARGMEM_OR_ERRNOMEMONLY = 105, + ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEM_OR_ERRNOMEMONLY = 106, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h index fcd5396ccfdbc8..ef41582bf63535 100644 --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -587,11 +587,31 @@ 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 pointed to by its arguments or errno memory. + bool onlyAccessesArgMemOrErrnoMem() const; + void setOnlyAccessesArgMemOrErrnoMem(); + + /// 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 26be02d4b193de..5d4e24bc423cd0 100644 --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -1915,11 +1915,31 @@ 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 pointed to by its arguments or errno memory. + bool onlyAccessesArgMemOrErrnoMem() const; + void setOnlyAccessesArgMemOrErrnoMem(); + + /// 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 a8ce9a8e6e69c4..f54deb911c7c80 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,36 @@ 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 argument or errno memory. + static MemoryEffectsBase + argumentOrErrnoMemOnly(ModRefInfo MR = ModRefInfo::ModRef) { + MemoryEffectsBase FRMB = none(); + FRMB.setModRef(Location::ArgMem, MR); + FRMB.setModRef(Location::ErrnoMem, 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) { @@ -212,6 +249,11 @@ template <typename LocationEnum> class MemoryEffectsBase { 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 +262,30 @@ 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 argument and errno memory. + bool onlyAccessesArgumentOrErrnoMem() const { + return getWithoutLoc(Location::ArgMem) + .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 d2549b79a43058..9e34655241d138 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -701,9 +701,14 @@ 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(argmem_or_errnomemonly); + KEYWORD(inaccessiblemem_or_argmem_or_errnomemonly); KEYWORD(nocapture); KEYWORD(address_is_null); KEYWORD(address); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 642d7cc403610a..579d2bca4f7426 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1671,9 +1671,21 @@ 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_argmem_or_errnomemonly: + ME &= MemoryEffects::argumentOrErrnoMemOnly(); + return true; + case lltok::kw_inaccessiblemem_or_argmem_or_errnomemonly: + ME &= MemoryEffects::inaccessibleOrArgOrErrnoMemOnly(); + return true; default: return false; } @@ -2497,6 +2509,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; } @@ -2545,7 +2559,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 1a09e80c4fbb2d..fcf3999e3efbe9 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1910,6 +1910,11 @@ 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 ArgumentMemOrErrnoMemOnly, which is upgraded separately. + // 7ULL << 39 is InaccessibleMemOrArgOrErrnoMemOnly, which is upgraded + // separately. default: // Other attributes are not supported in the raw format, // as we ran out of space. @@ -1982,6 +1987,26 @@ 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)) { + // ArgumentMemOrErrnoMemOnly + Attrs &= ~(7ULL << 38); + ME &= MemoryEffects::argumentOrErrnoMemOnly(); + } + if (Attrs & (7ULL << 39)) { + // InaccessibleMemOrArgOrErrnoMemOnly + Attrs &= ~(7ULL << 39); + ME &= MemoryEffects::inaccessibleOrArgOrErrnoMemOnly(); + } if (ME != MemoryEffects::unknown()) B.addMemoryAttr(ME); } @@ -2293,9 +2318,21 @@ 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_ARGMEM_OR_ERRNOMEMONLY: + ME &= MemoryEffects::argumentOrErrnoMemOnly(); + 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 ef0591ef317440..8da1dfe914818c 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -647,6 +647,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 e6f0d64d071ba6..53e9d310000c1d 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,37 @@ 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 pointed to by its arguments or errno memory. +bool Function::onlyAccessesArgMemOrErrnoMem() const { + return getMemoryEffects().onlyAccessesArgumentOrErrnoMem(); +} +void Function::setOnlyAccessesArgMemOrErrnoMem() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::argumentOrErrnoMemOnly()); +} + +/// 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 1fdf0eab548fdd..fe835e2def011d 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -682,6 +682,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 { @@ -692,6 +700,37 @@ 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 pointed to by its arguments or errno memory. +bool CallBase::onlyAccessesArgMemOrErrnoMem() const { + return getMemoryEffects().onlyAccessesArgumentOrErrnoMem(); +} +void CallBase::setOnlyAccessesArgMemOrErrnoMem() { + setMemoryEffects(getMemoryEffects() & + MemoryEffects::argumentOrErrnoMemOnly()); +} + +/// 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()); +} + CaptureInfo CallBase::getCaptureInfo(unsigned OpNo) const { if (OpNo < arg_size()) { // If the argument is passed byval, the callee does not have access to the 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/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index cf56f67e4de3f5..a8a479eb44a15c 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -128,6 +128,17 @@ static void addLocAccess(MemoryEffects &ME, const MemoryLocation &Loc, ME |= MemoryEffects::argMemOnly(MR); return; } + if (isa<CallInst>(UO)) { + static constexpr auto ErrnoFnNames = {"__errno_location", "_errno", + "__errno", "___errno" }; + auto *Callee = cast<CallInst>(UO)->getCalledFunction(); + if (Callee && llvm::any_of(ErrnoFnNames, [&](const auto Fn) { + return Fn == Callee->getName(); + })) { + ME |= MemoryEffects::errnoMemOnly(MR); + return; + } + } // If it's not an identified object, it might be an argument. if (!isIdentifiedObject(UO)) @@ -210,6 +221,9 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR, if (isa<PseudoProbeInst>(I)) continue; + // Merge callee's memory effects into caller's ones, including + // inaccessible and errno memory, but excluding argument memory, which is + // handled separately. ME |= CallME.getWithoutLoc(IRMemLocation::ArgMem); // If the call accesses captured memory (currently part of "other") and 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 42e0e94c1cee3d..01b4ef43a93f68 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 readonly captures(none) [[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 writeonly captures(none) 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 readonly captures(none) [[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 readonly captures(none) [[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 captures(none) [[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 readonly captures(none) [[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 readonly captures(none) [[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 readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[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 readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] { ; FNATTRS-NEXT: entry: diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll index 4a27bcd9853d4a..78459ea2c7400b 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 captures(none) [[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) captures(none) [[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 captures(none) [[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 readnone captures(none) [[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 readnone captures(none) [[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 readnone captures(none) [[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 readnone captures(none) [[X3:%.*]], ptr readnone captures(none) [[Y3:%.*]], ptr readnone captures(none) [[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 readnone captures(none) [[X4_2:%.*]], ptr readnone returned [[Y4_2:%.*]], ptr readnone captures(none) [[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-errnomem.ll b/llvm/test/Transforms/FunctionAttrs/read-write-errnomem.ll new file mode 100644 index 00000000000000..97683ad7e64609 --- /dev/null +++ b/llvm/test/Transforms/FunctionAttrs/read-write-errnomem.ll @@ -0,0 +1,71 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2 +; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=FNATTRS %s +; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=ATTRIBUTOR %s + +define i32 @test_read_errno() { +; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(errnomem: read) +; FNATTRS-LABEL: define i32 @test_read_errno +; FNATTRS-SAME: () #[[ATTR0:[0-9]+]] { +; FNATTRS-NEXT: [[CALL:%.*]] = tail call ptr @__errno_location() #[[ATTR4:[0-9]+]] +; FNATTRS-NEXT: [[ERRNO:%.*]] = load i32, ptr [[CALL]], align 4 +; FNATTRS-NEXT: ret i32 [[ERRNO]] +; +; ATTRIBUTOR: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(read) +; ATTRIBUTOR-LABEL: define i32 @test_read_errno +; ATTRIBUTOR-SAME: () #[[ATTR0:[0-9]+]] { +; ATTRIBUTOR-NEXT: [[CALL:%.*]] = tail call ptr @__errno_location() #[[ATTR4:[0-9]+]] +; ATTRIBUTOR-NEXT: [[ERRNO:%.*]] = load i32, ptr [[CALL]], align 4 +; ATTRIBUTOR-NEXT: ret i32 [[ERRNO]] +; + %call = tail call ptr @__errno_location() #2 + %errno = load i32, ptr %call + ret i32 %errno +} + +define ptr @test_write_errno() { +; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(errnomem: write) +; FNATTRS-LABEL: define noundef ptr @test_write_errno +; FNATTRS-SAME: () #[[ATTR1:[0-9]+]] { +; FNATTRS-NEXT: [[CALL:%.*]] = tail call ptr @__errno_location() #[[ATTR4]] +; FNATTRS-NEXT: store i32 0, ptr [[CALL]], align 4 +; FNATTRS-NEXT: ret ptr [[CALL]] +; +; ATTRIBUTOR: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write) +; ATTRIBUTOR-LABEL: define ptr @test_write_errno +; ATTRIBUTOR-SAME: () #[[ATTR1:[0-9]+]] { +; ATTRIBUTOR-NEXT: [[CALL:%.*]] = tail call ptr @__errno_location() #[[ATTR4]] +; ATTRIBUTOR-NEXT: store i32 0, ptr [[CALL]], align 4 +; ATTRIBUTOR-NEXT: ret ptr [[CALL]] +; + %call = tail call ptr @__errno_location() #2 + store i32 0, ptr %call + ret ptr %call +} + +define i32 @test_readwrite_errno() { +; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(errnomem: readwrite) +; FNATTRS-LABEL: define i32 @test_readwrite_errno +; FNATTRS-SAME: () #[[ATTR2:[0-9]+]] { +; FNATTRS-NEXT: [[CALL:%.*]] = tail call ptr @__errno_location() #[[ATTR4]] +; FNATTRS-NEXT: store i32 0, ptr [[CALL]], align 4 +; FNATTRS-NEXT: [[ERRNO:%.*]] = load i32, ptr [[CALL]], align 4 +; FNATTRS-NEXT: ret i32 [[ERRNO]] +; +; ATTRIBUTOR: Function Attrs: mustprogress nofree nosync nounwind willreturn +; ATTRIBUTOR-LABEL: define i32 @test_readwrite_errno +; ATTRIBUTOR-SAME: () #[[ATTR2:[0-9]+]] { +; ATTRIBUTOR-NEXT: [[CALL:%.*]] = tail call ptr @__errno_location() #[[ATTR4]] +; ATTRIBUTOR-NEXT: store i32 0, ptr [[CALL]], align 4 +; ATTRIBUTOR-NEXT: [[ERRNO:%.*]] = load i32, ptr [[CALL]], align 4 +; ATTRIBUTOR-NEXT: ret i32 [[ERRNO]] +; + %call = tail call ptr @__errno_location() #2 + store i32 0, ptr %call + %errno = load i32, ptr %call + ret i32 %errno +} + +declare ptr @__errno_location() #1 + +attributes #1 = { mustprogress nofree nosync nounwind willreturn memory(none) } +attributes #2 = { nounwind willreturn memory(none) } 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 b24c097ad54d08..554670479ab8d4 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 88c60316136970..fdf9734ebda84f 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 readnone captures(none) [[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 52aa69f4c481f9..91cfb04e3b4401 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