[Mlir-commits] [clang] [llvm] [mlir] [IR][ModRef] Introduce `errno` memory location (PR #120783)
Antonio Frighetto
llvmlistbot at llvm.org
Wed Feb 5 14:46:33 PST 2025
https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/120783
>From 8d64748bb7093866ba2900916237f58a203cb511 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 20 Dec 2024 19:30:59 +0100
Subject: [PATCH 1/2] [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 eabcbd1409fe2b8..ff98d0b21e3f115 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 123adba7b40d2c1..d64915205aabf6c 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 300d50c0959b7cd..233fe7f78964b01 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 9eb38c3e4482910..1dd72b479fb93e3 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 fcd5396ccfdbc87..ef41582bf635351 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 26be02d4b193de6..5d4e24bc423cd0c 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 a8ce9a8e6e69c47..f54deb911c7c80d 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 d2549b79a430582..9e34655241d1386 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 642d7cc403610a6..579d2bca4f7426a 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 1a09e80c4fbb2dd..fcf3999e3efbe99 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 ef0591ef3174409..8da1dfe914818ce 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 e6f0d64d071ba67..53e9d310000c1dd 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 1fdf0eab548fdda..fe835e2def011da 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 d3b3dd11171f16d..2bb9bc945bd2e2b 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 cf56f67e4de3f53..45a293003ba36b7 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 1fba90362e79b90..2eed11d9465d586 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 2f7d3980eb378b5..effd4ce7c454836 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 42e0e94c1cee3d1..01b4ef43a93f680 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 4a27bcd9853d4af..78459ea2c7400b8 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 000000000000000..97683ad7e646098
--- /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 be61990fd6278b7..6dd48a04f3145fb 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 b24c097ad54d08c..554670479ab8d45 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 88c603161369702..fdf9734ebda84f8 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 c8568272d320fb5..36791ae60fed608 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 2795333effd76ba..8e212040d66515c 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 22726e0cac1f12b..5e8c7cd21324d8a 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 35107e50b32db78..9c13908da44bb00 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 52aa69f4c481f98..91cfb04e3b4401a 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)
// -----
>From bf42779ef7cc2b4f4af07f7b13f2b7ad99719e80 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Wed, 5 Feb 2025 23:29:44 +0100
Subject: [PATCH 2/2] !fixup accesses <= sizeof(int) may be aliasing errno
---
llvm/include/llvm/Analysis/MemoryLocation.h | 4 ++
llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 2 +
.../Transforms/FunctionAttrs/argmemonly.ll | 70 +++++++++----------
llvm/test/Transforms/FunctionAttrs/atomic.ll | 2 +-
.../Transforms/FunctionAttrs/initializes.ll | 60 ++++++++--------
.../Transforms/FunctionAttrs/nocapture.ll | 32 ++++-----
llvm/test/Transforms/FunctionAttrs/nofree.ll | 2 +-
llvm/test/Transforms/FunctionAttrs/nosync.ll | 27 ++++---
.../Transforms/FunctionAttrs/readattrs.ll | 22 +++---
.../Transforms/FunctionAttrs/willreturn.ll | 26 ++++---
.../Transforms/FunctionAttrs/writeonly.ll | 14 ++--
11 files changed, 136 insertions(+), 125 deletions(-)
diff --git a/llvm/include/llvm/Analysis/MemoryLocation.h b/llvm/include/llvm/Analysis/MemoryLocation.h
index ea29e21bd18f2fa..0c7e9ffe7c9ee28 100644
--- a/llvm/include/llvm/Analysis/MemoryLocation.h
+++ b/llvm/include/llvm/Analysis/MemoryLocation.h
@@ -194,6 +194,10 @@ class LocationSize {
return hasValue() && getValue() == Other;
}
+ bool operator<=(const LocationSize &Other) const {
+ return Value <= Other.Value;
+ }
+
bool operator!=(const LocationSize &Other) const { return !(*this == Other); }
bool operator!=(const TypeSize &Other) const { return !(*this == Other); }
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 45a293003ba36b7..a745865f6926cd7 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -126,6 +126,8 @@ static void addLocAccess(MemoryEffects &ME, const MemoryLocation &Loc,
return;
if (isa<Argument>(UO)) {
ME |= MemoryEffects::argMemOnly(MR);
+ if (Loc.Size <= LocationSize::precise(sizeof(int)))
+ ME |= MemoryEffects::errnoMemOnly(MR);
return;
}
if (isa<CallInst>(UO)) {
diff --git a/llvm/test/Transforms/FunctionAttrs/argmemonly.ll b/llvm/test/Transforms/FunctionAttrs/argmemonly.ll
index 01b4ef43a93f680..cba4ceb20af4c62 100644
--- a/llvm/test/Transforms/FunctionAttrs/argmemonly.ll
+++ b/llvm/test/Transforms/FunctionAttrs/argmemonly.ll
@@ -16,7 +16,7 @@ entry:
}
define i32 @test_only_read_arg(ptr %ptr) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: define i32 @test_only_read_arg
; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] {
; FNATTRS-NEXT: entry:
@@ -38,7 +38,7 @@ entry:
define i32 @test_only_read_arg_already_has_argmemonly(ptr %ptr) argmemonly {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; FNATTRS-LABEL: define i32 @test_only_read_arg_already_has_argmemonly
-; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
+; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR2:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr [[PTR]], align 4
; FNATTRS-NEXT: ret i32 [[L]]
@@ -58,7 +58,7 @@ entry:
define i32 @test_read_global() {
; 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-SAME: () #[[ATTR3:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[L:%.*]] = load i32, ptr @g, align 4
; FNATTRS-NEXT: ret i32 [[L]]
@@ -78,7 +78,7 @@ entry:
define i32 @test_read_loaded_ptr(ptr %ptr) {
; 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-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR4:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[L:%.*]] = load ptr, ptr [[PTR]], align 8
; FNATTRS-NEXT: [[L_2:%.*]] = load i32, ptr [[L]], align 4
@@ -99,9 +99,9 @@ entry:
}
define void @test_only_write_arg(ptr %ptr) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; FNATTRS-LABEL: define void @test_only_write_arg
-; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR4:[0-9]+]] {
+; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR5:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: store i32 0, ptr [[PTR]], align 4
; FNATTRS-NEXT: ret void
@@ -121,7 +121,7 @@ entry:
define void @test_write_global() {
; 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-SAME: () #[[ATTR6:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: store i32 0, ptr @g, align 4
; FNATTRS-NEXT: ret void
@@ -154,9 +154,9 @@ entry:
declare i32 @fn_readnone() readnone
define void @test_call_readnone(ptr %ptr) {
-; FNATTRS: Function Attrs: memory(argmem: write)
+; FNATTRS: Function Attrs: memory(argmem: write, errnomem: write)
; FNATTRS-LABEL: define void @test_call_readnone
-; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR7:[0-9]+]] {
+; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR8:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[C:%.*]] = call i32 @fn_readnone()
; FNATTRS-NEXT: store i32 [[C]], ptr [[PTR]], align 4
@@ -181,7 +181,7 @@ declare i32 @fn_argmemonly(ptr) argmemonly
define i32 @test_call_argmemonly(ptr %ptr) {
; FNATTRS: Function Attrs: memory(argmem: readwrite)
; FNATTRS-LABEL: define i32 @test_call_argmemonly
-; FNATTRS-SAME: (ptr [[PTR:%.*]]) #[[ATTR8:[0-9]+]] {
+; FNATTRS-SAME: (ptr [[PTR:%.*]]) #[[ATTR9:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]])
; FNATTRS-NEXT: ret i32 [[C]]
@@ -199,7 +199,7 @@ entry:
}
define i32 @test_call_fn_where_argmemonly_can_be_inferred(ptr %ptr) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred
; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
; FNATTRS-NEXT: entry:
@@ -221,7 +221,7 @@ entry:
define void @test_memcpy_argonly(ptr %dst, ptr %src) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; FNATTRS-LABEL: define void @test_memcpy_argonly
-; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR9:[0-9]+]] {
+; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR10:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 32, i1 false)
; FNATTRS-NEXT: ret void
@@ -245,7 +245,7 @@ declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
define void @test_memcpy_src_global(ptr %dst) {
; 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-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]]) #[[ATTR12:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr @arr, i64 32, i1 false)
; FNATTRS-NEXT: ret void
@@ -265,7 +265,7 @@ entry:
define void @test_memcpy_dst_global(ptr %src) {
; 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-SAME: (ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR12]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr [[SRC]], i64 32, i1 false)
; FNATTRS-NEXT: ret void
@@ -283,7 +283,7 @@ entry:
}
define i32 @test_read_arg_access_alloca(ptr %ptr) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: define i32 @test_read_arg_access_alloca
; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
; FNATTRS-NEXT: entry:
@@ -316,7 +316,7 @@ declare void @fn_inaccessiblememonly() inaccessiblememonly
define void @test_inaccessiblememonly() {
; FNATTRS: Function Attrs: memory(inaccessiblemem: readwrite)
; FNATTRS-LABEL: define void @test_inaccessiblememonly
-; FNATTRS-SAME: () #[[ATTR12:[0-9]+]] {
+; FNATTRS-SAME: () #[[ATTR13:[0-9]+]] {
; FNATTRS-NEXT: call void @fn_inaccessiblememonly()
; FNATTRS-NEXT: ret void
;
@@ -333,8 +333,8 @@ define void @test_inaccessiblememonly() {
define void @test_inaccessiblememonly_readonly() {
; FNATTRS: Function Attrs: nofree memory(inaccessiblemem: read)
; FNATTRS-LABEL: define void @test_inaccessiblememonly_readonly
-; FNATTRS-SAME: () #[[ATTR13:[0-9]+]] {
-; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19:[0-9]+]]
+; FNATTRS-SAME: () #[[ATTR14:[0-9]+]] {
+; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR20:[0-9]+]]
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(inaccessiblemem: read)
@@ -348,11 +348,11 @@ define void @test_inaccessiblememonly_readonly() {
}
define void @test_inaccessibleorargmemonly_readonly(ptr %arg) {
-; FNATTRS: Function Attrs: nofree memory(argmem: read, inaccessiblemem: read)
+; FNATTRS: Function Attrs: nofree memory(argmem: read, inaccessiblemem: read, errnomem: read)
; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readonly
-; FNATTRS-SAME: (ptr readonly captures(none) [[ARG:%.*]]) #[[ATTR14:[0-9]+]] {
+; FNATTRS-SAME: (ptr readonly captures(none) [[ARG:%.*]]) #[[ATTR15:[0-9]+]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4
-; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19]]
+; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR20]]
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(argmem: read, inaccessiblemem: read)
@@ -368,11 +368,11 @@ define void @test_inaccessibleorargmemonly_readonly(ptr %arg) {
}
define void @test_inaccessibleorargmemonly_readwrite(ptr %arg) {
-; FNATTRS: Function Attrs: memory(argmem: write, inaccessiblemem: read)
+; FNATTRS: Function Attrs: memory(argmem: write, inaccessiblemem: read, errnomem: write)
; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readwrite
-; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[ARG:%.*]]) #[[ATTR15:[0-9]+]] {
+; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[ARG:%.*]]) #[[ATTR16:[0-9]+]] {
; FNATTRS-NEXT: store i32 0, ptr [[ARG]], align 4
-; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR19]]
+; FNATTRS-NEXT: call void @fn_inaccessiblememonly() #[[ATTR20]]
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(argmem: readwrite, inaccessiblemem: readwrite)
@@ -390,7 +390,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, errnomem: none)
; FNATTRS-LABEL: define void @test_recursive_argmem_read
-; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] {
+; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] {
; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; FNATTRS-NEXT: call void @test_recursive_argmem_read(ptr [[PVAL]])
; FNATTRS-NEXT: ret void
@@ -408,9 +408,9 @@ 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, errnomem: none)
+; FNATTRS: Function Attrs: nofree nosync nounwind memory(readwrite, inaccessiblemem: none, errnomem: write)
; FNATTRS-LABEL: define void @test_recursive_argmem_readwrite
-; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] {
+; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR18:[0-9]+]] {
; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; FNATTRS-NEXT: store i32 0, ptr [[P]], align 4
; FNATTRS-NEXT: call void @test_recursive_argmem_readwrite(ptr [[PVAL]])
@@ -431,9 +431,9 @@ define void @test_recursive_argmem_readwrite(ptr %p) {
}
define void @test_recursive_argmem_read_alloca(ptr %p) {
-; FNATTRS: Function Attrs: nofree nosync nounwind memory(argmem: read)
+; FNATTRS: Function Attrs: nofree nosync nounwind memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: define void @test_recursive_argmem_read_alloca
-; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR18:[0-9]+]] {
+; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR19:[0-9]+]] {
; FNATTRS-NEXT: [[A:%.*]] = alloca ptr, align 8
; FNATTRS-NEXT: [[TMP1:%.*]] = load i32, ptr [[P]], align 4
; FNATTRS-NEXT: call void @test_recursive_argmem_read_alloca(ptr [[A]])
@@ -456,7 +456,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, errnomem: none)
; FNATTRS-LABEL: define void @test_scc_argmem_read_1
-; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] {
+; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR17]] {
; FNATTRS-NEXT: [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
; FNATTRS-NEXT: call void @test_scc_argmem_read_2(ptr [[PVAL]])
; FNATTRS-NEXT: ret void
@@ -476,7 +476,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, errnomem: none)
; FNATTRS-LABEL: define void @test_scc_argmem_read_2
-; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] {
+; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR17]] {
; FNATTRS-NEXT: call void @test_scc_argmem_read_1(ptr [[P]])
; FNATTRS-NEXT: ret void
;
@@ -493,7 +493,7 @@ define void @test_scc_argmem_read_2(ptr %p) {
define i64 @select_same_obj(i1 %c, ptr %p, i64 %x) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; FNATTRS-LABEL: define i64 @select_same_obj
-; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
+; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR2]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
; FNATTRS-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
@@ -520,7 +520,7 @@ entry:
define i64 @select_different_obj(i1 %c, ptr %p, ptr %p2) {
; 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-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR4]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
; FNATTRS-NEXT: [[R:%.*]] = load i64, ptr [[P3]], align 4
@@ -543,7 +543,7 @@ entry:
define i64 @phi_same_obj(i1 %c, ptr %p, i64 %x) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; FNATTRS-LABEL: define i64 @phi_same_obj
-; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
+; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR2]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
; FNATTRS-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
@@ -582,7 +582,7 @@ join:
define i64 @phi_different_obj(i1 %c, ptr %p, ptr %p2) {
; 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-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR4]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
; FNATTRS: if:
diff --git a/llvm/test/Transforms/FunctionAttrs/atomic.ll b/llvm/test/Transforms/FunctionAttrs/atomic.ll
index 8635f2bbdc49802..9121264dacc96c2 100644
--- a/llvm/test/Transforms/FunctionAttrs/atomic.ll
+++ b/llvm/test/Transforms/FunctionAttrs/atomic.ll
@@ -21,7 +21,7 @@ entry:
; A function with an Acquire load is not readonly.
define i32 @test2(ptr %x) uwtable ssp {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind ssp willreturn memory(argmem: readwrite) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind ssp willreturn memory(argmem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[R:%.*]] = load atomic i32, ptr [[X:%.*]] seq_cst, align 4
diff --git a/llvm/test/Transforms/FunctionAttrs/initializes.ll b/llvm/test/Transforms/FunctionAttrs/initializes.ll
index 861c61d683ae0ad..d5c2e99a83f44b4 100644
--- a/llvm/test/Transforms/FunctionAttrs/initializes.ll
+++ b/llvm/test/Transforms/FunctionAttrs/initializes.ll
@@ -63,7 +63,7 @@ define void @store_pointer_to_itself(ptr %p) {
}
define void @load_before_store(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; CHECK-LABEL: define void @load_before_store(
; CHECK-SAME: ptr captures(none) [[P:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4
@@ -76,9 +76,9 @@ define void @load_before_store(ptr %p) {
}
define void @partial_load_before_store(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, errnomem: read)
; CHECK-LABEL: define void @partial_load_before_store(
-; CHECK-SAME: ptr captures(none) initializes((4, 8)) [[P:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr captures(none) initializes((4, 8)) [[P:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: store i64 123, ptr [[P]], align 4
; CHECK-NEXT: ret void
@@ -115,9 +115,9 @@ define void @call_clobber_after_store(ptr %p) {
}
define void @store_offset(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; CHECK-LABEL: define void @store_offset(
-; CHECK-SAME: ptr writeonly captures(none) initializes((8, 12)) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr writeonly captures(none) initializes((8, 12)) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 8
; CHECK-NEXT: store i32 123, ptr [[G]], align 4
; CHECK-NEXT: ret void
@@ -128,9 +128,9 @@ define void @store_offset(ptr %p) {
}
define void @store_volatile(ptr %p) {
-; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)
+; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite)
; CHECK-LABEL: define void @store_volatile(
-; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] {
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 8
; CHECK-NEXT: store volatile i32 123, ptr [[G]], align 4
; CHECK-NEXT: ret void
@@ -141,9 +141,9 @@ define void @store_volatile(ptr %p) {
}
define void @merge_store_ranges(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; CHECK-LABEL: define void @merge_store_ranges(
-; CHECK-SAME: ptr writeonly captures(none) initializes((0, 8)) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr writeonly captures(none) initializes((0, 8)) [[P:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 4
; CHECK-NEXT: store i32 123, ptr [[G]], align 4
; CHECK-NEXT: store i32 123, ptr [[P]], align 4
@@ -156,9 +156,9 @@ define void @merge_store_ranges(ptr %p) {
}
define void @partially_overlapping_stores_branches(ptr %p, i1 %i) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, errnomem: read)
; CHECK-LABEL: define void @partially_overlapping_stores_branches(
-; CHECK-SAME: ptr captures(none) initializes((4, 8)) [[P:%.*]], i1 [[I:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr captures(none) initializes((4, 8)) [[P:%.*]], i1 [[I:%.*]]) #[[ATTR2]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 4
@@ -384,7 +384,7 @@ define void @call_initializes_escape_bundle(ptr %p) {
define void @access_bundle() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define void @access_bundle(
-; CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
+; CHECK-SAME: ) #[[ATTR5:[0-9]+]] {
; CHECK-NEXT: [[SINK:%.*]] = alloca i64, align 8
; CHECK-NEXT: store i64 123, ptr [[SINK]], align 4
; CHECK-NEXT: ret void
@@ -397,7 +397,7 @@ define void @access_bundle() {
define void @call_operand_bundle(ptr %p) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
; CHECK-LABEL: define void @call_operand_bundle(
-; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR4:[0-9]+]] {
+; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR6:[0-9]+]] {
; CHECK-NEXT: call void @access_bundle() [ "unknown"(ptr [[P]]) ]
; CHECK-NEXT: ret void
;
@@ -445,7 +445,7 @@ define void @memset_neg(ptr %p) {
define void @memset_volatile(ptr %p) {
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: write)
; CHECK-LABEL: define void @memset_volatile(
-; CHECK-SAME: ptr writeonly [[P:%.*]]) #[[ATTR5:[0-9]+]] {
+; CHECK-SAME: ptr writeonly [[P:%.*]]) #[[ATTR7:[0-9]+]] {
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[P]], i8 2, i64 9, i1 true)
; CHECK-NEXT: ret void
;
@@ -469,7 +469,7 @@ declare void @llvm.memcpy(ptr, ptr, i64 ,i1)
define void @memcpy(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memcpy(
-; CHECK-SAME: ptr writeonly captures(none) initializes((0, 9)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) initializes((0, 9)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR8:[0-9]+]] {
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[P]], ptr [[P2]], i64 9, i1 false)
; CHECK-NEXT: ret void
;
@@ -480,7 +480,7 @@ define void @memcpy(ptr %p, ptr %p2) {
define void @memcpy_volatile(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memcpy_volatile(
-; CHECK-SAME: ptr writeonly [[P:%.*]], ptr readonly [[P2:%.*]]) #[[ATTR6:[0-9]+]] {
+; CHECK-SAME: ptr writeonly [[P:%.*]], ptr readonly [[P2:%.*]]) #[[ATTR9:[0-9]+]] {
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[P]], ptr [[P2]], i64 9, i1 true)
; CHECK-NEXT: ret void
;
@@ -491,7 +491,7 @@ define void @memcpy_volatile(ptr %p, ptr %p2) {
define void @memcpy_offset(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memcpy_offset(
-; CHECK-SAME: ptr writeonly captures(none) initializes((3, 12)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) initializes((3, 12)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 3
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[G]], ptr [[P2]], i64 9, i1 false)
; CHECK-NEXT: ret void
@@ -504,7 +504,7 @@ define void @memcpy_offset(ptr %p, ptr %p2) {
define void @memcpy_src(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memcpy_src(
-; CHECK-SAME: ptr captures(none) initializes((96, 128)) [[P:%.*]], ptr captures(none) initializes((0, 96)) [[P2:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr captures(none) initializes((96, 128)) [[P:%.*]], ptr captures(none) initializes((0, 96)) [[P2:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[P2]], ptr [[P]], i64 96, i1 false)
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 64
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[G]], ptr [[P2]], i64 64, i1 false)
@@ -519,7 +519,7 @@ define void @memcpy_src(ptr %p, ptr %p2) {
define void @memcpy_non_constant(ptr %p, ptr %p2, i64 %i) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memcpy_non_constant(
-; CHECK-SAME: ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]], i64 [[I:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]], i64 [[I:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[P]], ptr [[P2]], i64 [[I]], i1 false)
; CHECK-NEXT: ret void
;
@@ -532,7 +532,7 @@ declare void @llvm.memmove(ptr, ptr, i64 ,i1)
define void @memmove(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memmove(
-; CHECK-SAME: ptr writeonly captures(none) initializes((0, 9)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) initializes((0, 9)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[P]], ptr [[P2]], i64 9, i1 false)
; CHECK-NEXT: ret void
;
@@ -543,7 +543,7 @@ define void @memmove(ptr %p, ptr %p2) {
define void @memmove_volatile(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memmove_volatile(
-; CHECK-SAME: ptr writeonly [[P:%.*]], ptr readonly [[P2:%.*]]) #[[ATTR6]] {
+; CHECK-SAME: ptr writeonly [[P:%.*]], ptr readonly [[P2:%.*]]) #[[ATTR9]] {
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[P]], ptr [[P2]], i64 9, i1 true)
; CHECK-NEXT: ret void
;
@@ -554,7 +554,7 @@ define void @memmove_volatile(ptr %p, ptr %p2) {
define void @memmove_offset(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memmove_offset(
-; CHECK-SAME: ptr writeonly captures(none) initializes((3, 12)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) initializes((3, 12)) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 3
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[G]], ptr [[P2]], i64 9, i1 false)
; CHECK-NEXT: ret void
@@ -567,7 +567,7 @@ define void @memmove_offset(ptr %p, ptr %p2) {
define void @memmove_src(ptr %p, ptr %p2) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memmove_src(
-; CHECK-SAME: ptr captures(none) initializes((96, 128)) [[P:%.*]], ptr captures(none) initializes((0, 96)) [[P2:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr captures(none) initializes((96, 128)) [[P:%.*]], ptr captures(none) initializes((0, 96)) [[P2:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[P2]], ptr [[P]], i64 96, i1 false)
; CHECK-NEXT: [[G:%.*]] = getelementptr i8, ptr [[P]], i64 64
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[G]], ptr [[P2]], i64 64, i1 false)
@@ -582,7 +582,7 @@ define void @memmove_src(ptr %p, ptr %p2) {
define void @memmove_non_constant(ptr %p, ptr %p2, i64 %i) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memmove_non_constant(
-; CHECK-SAME: ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]], i64 [[I:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]], i64 [[I:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[P]], ptr [[P2]], i64 [[I]], i1 false)
; CHECK-NEXT: ret void
;
@@ -591,9 +591,9 @@ define void @memmove_non_constant(ptr %p, ptr %p2, i64 %i) {
}
define void @callee_byval(ptr byval(i32) %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; CHECK-LABEL: define void @callee_byval(
-; CHECK-SAME: ptr writeonly byval(i32) captures(none) initializes((0, 4)) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr writeonly byval(i32) captures(none) initializes((0, 4)) [[P:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: store i32 0, ptr [[P]], align 4
; CHECK-NEXT: ret void
;
@@ -602,9 +602,9 @@ define void @callee_byval(ptr byval(i32) %p) {
}
define void @caller_byval(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; CHECK-LABEL: define void @caller_byval(
-; CHECK-SAME: ptr readonly captures(none) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr readonly captures(none) [[P:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: call void @callee_byval(ptr byval(i32) [[P]])
; CHECK-NEXT: ret void
;
@@ -615,7 +615,7 @@ define void @caller_byval(ptr %p) {
define void @memset_offset_0_size_0(ptr %dst, ptr %src) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memset_offset_0_size_0(
-; CHECK-SAME: ptr writeonly captures(none) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 0, i1 false)
; CHECK-NEXT: ret void
;
@@ -626,7 +626,7 @@ define void @memset_offset_0_size_0(ptr %dst, ptr %src) {
define void @memset_offset_1_size_0(ptr %dst, ptr %src) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define void @memset_offset_1_size_0(
-; CHECK-SAME: ptr writeonly captures(none) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR1]] {
+; CHECK-SAME: ptr writeonly captures(none) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR8]] {
; CHECK-NEXT: [[DST_1:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 1
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr [[DST_1]], ptr [[SRC]], i64 0, i1 false)
; CHECK-NEXT: ret void
diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
index 78459ea2c7400b8..e9f46369c2fb65f 100644
--- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
@@ -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, errnomem: none)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: write)
; 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, errnomem: none)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: write)
; 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, errnomem: none)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none, errnomem: write)
; 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)
@@ -576,7 +576,7 @@ define void @test6_2(ptr %x6_2, ptr %y6_2, ptr %z6_2) {
}
define void @test_cmpxchg(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; FNATTRS-LABEL: define void @test_cmpxchg
; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR11:[0-9]+]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = cmpxchg ptr [[P]], i32 0, i32 1 acquire monotonic, align 4
@@ -595,7 +595,7 @@ define void @test_cmpxchg(ptr %p) {
define void @test_cmpxchg_ptr(ptr %p, ptr %q) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
; FNATTRS-LABEL: define void @test_cmpxchg_ptr
-; FNATTRS-SAME: (ptr captures(none) [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR11]] {
+; FNATTRS-SAME: (ptr captures(none) [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR12:[0-9]+]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = cmpxchg ptr [[P]], ptr null, ptr [[Q]] acquire monotonic, align 8
; FNATTRS-NEXT: ret void
;
@@ -610,7 +610,7 @@ define void @test_cmpxchg_ptr(ptr %p, ptr %q) {
}
define void @test_atomicrmw(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; FNATTRS-LABEL: define void @test_atomicrmw
; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR11]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P]], i32 1 seq_cst, align 4
@@ -627,9 +627,9 @@ define void @test_atomicrmw(ptr %p) {
}
define void @test_volatile(ptr %x) {
-; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)
+; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite)
; FNATTRS-LABEL: define void @test_volatile
-; FNATTRS-SAME: (ptr [[X:%.*]]) #[[ATTR12:[0-9]+]] {
+; FNATTRS-SAME: (ptr [[X:%.*]]) #[[ATTR13:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[X]], i64 1
; FNATTRS-NEXT: store volatile i32 0, ptr [[GEP]], align 4
@@ -650,9 +650,9 @@ entry:
}
define void @nocaptureLaunder(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, inaccessiblemem: readwrite)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, inaccessiblemem: readwrite, errnomem: write)
; FNATTRS-LABEL: define void @nocaptureLaunder
-; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
+; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR14:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]])
; FNATTRS-NEXT: store i8 42, ptr [[B]], align 1
@@ -676,7 +676,7 @@ entry:
define void @captureLaunder(ptr %p) {
; 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-SAME: (ptr [[P:%.*]]) #[[ATTR15:[0-9]+]] {
; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]])
; FNATTRS-NEXT: store ptr [[B]], ptr @g2, align 8
; FNATTRS-NEXT: ret void
@@ -694,9 +694,9 @@ define void @captureLaunder(ptr %p) {
}
define void @nocaptureStrip(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; FNATTRS-LABEL: define void @nocaptureStrip
-; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
+; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]])
; FNATTRS-NEXT: store i8 42, ptr [[B]], align 1
@@ -831,7 +831,7 @@ define i1 @nocaptureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x)
define i1 @captureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) null_pointer_is_valid {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
; FNATTRS-LABEL: define noundef i1 @captureDereferenceableOrNullICmp
-; FNATTRS-SAME: (ptr readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR16:[0-9]+]] {
+; FNATTRS-SAME: (ptr readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR17:[0-9]+]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
; FNATTRS-NEXT: ret i1 [[TMP1]]
;
@@ -886,8 +886,8 @@ define void @recurse_fptr(ptr %f, ptr %p) {
define void @readnone_indirec(ptr %f, ptr %p) {
; FNATTRS: Function Attrs: nofree nosync memory(none)
; FNATTRS-LABEL: define void @readnone_indirec
-; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr readnone [[P:%.*]]) #[[ATTR17:[0-9]+]] {
-; FNATTRS-NEXT: call void [[F]](ptr [[P]]) #[[ATTR20:[0-9]+]]
+; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr readnone [[P:%.*]]) #[[ATTR18:[0-9]+]] {
+; FNATTRS-NEXT: call void [[F]](ptr [[P]]) #[[ATTR21:[0-9]+]]
; FNATTRS-NEXT: ret void
;
; ATTRIBUTOR: Function Attrs: nosync memory(none)
diff --git a/llvm/test/Transforms/FunctionAttrs/nofree.ll b/llvm/test/Transforms/FunctionAttrs/nofree.ll
index 16711890db802eb..5789c015905c097 100644
--- a/llvm/test/Transforms/FunctionAttrs/nofree.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nofree.ll
@@ -33,7 +33,7 @@ entry:
declare void @free(ptr nocapture) local_unnamed_addr #2
define i32 @_Z4foo3Pi(ptr nocapture readonly %a) local_unnamed_addr #3 {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, errnomem: read) uwtable
; CHECK-LABEL: @_Z4foo3Pi(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A:%.*]], align 4
diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/FunctionAttrs/nosync.ll
index de5398f17ce51d4..334ac56175b5051 100644
--- a/llvm/test/Transforms/FunctionAttrs/nosync.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nosync.ll
@@ -48,7 +48,7 @@ define i32 @test4(i32 %a, i32 %b) {
; negative case - explicit sync
define void @test5(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; CHECK-LABEL: @test5(
; CHECK-NEXT: store atomic i8 0, ptr [[P:%.*]] seq_cst, align 1
; CHECK-NEXT: ret void
@@ -59,7 +59,7 @@ define void @test5(ptr %p) {
; negative case - explicit sync
define i8 @test6(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; CHECK-LABEL: @test6(
; CHECK-NEXT: [[V:%.*]] = load atomic i8, ptr [[P:%.*]] seq_cst, align 1
; CHECK-NEXT: ret i8 [[V]]
@@ -70,7 +70,7 @@ define i8 @test6(ptr %p) {
; negative case - explicit sync
define void @test7(ptr %p) {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P:%.*]], i8 0 seq_cst, align 1
; CHECK-NEXT: ret void
@@ -103,7 +103,7 @@ define void @test9(ptr %p) {
; atomic load with monotonic ordering
define i32 @load_monotonic(ptr nocapture readonly %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @load_monotonic(
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] monotonic, align 4
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -114,7 +114,7 @@ define i32 @load_monotonic(ptr nocapture readonly %0) norecurse nounwind uwtable
; atomic store with monotonic ordering.
define void @store_monotonic(ptr nocapture %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @store_monotonic(
; CHECK-NEXT: store atomic i32 10, ptr [[TMP0:%.*]] monotonic, align 4
; CHECK-NEXT: ret void
@@ -126,7 +126,7 @@ define void @store_monotonic(ptr nocapture %0) norecurse nounwind uwtable {
; negative, should not deduce nosync
; atomic load with acquire ordering.
define i32 @load_acquire(ptr nocapture readonly %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @load_acquire(
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] acquire, align 4
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -136,7 +136,7 @@ define i32 @load_acquire(ptr nocapture readonly %0) norecurse nounwind uwtable {
}
define i32 @load_unordered(ptr nocapture readonly %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, errnomem: read) uwtable
; CHECK-LABEL: @load_unordered(
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] unordered, align 4
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -147,7 +147,7 @@ define i32 @load_unordered(ptr nocapture readonly %0) norecurse nounwind uwtable
; atomic store with unordered ordering.
define void @store_unordered(ptr nocapture %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write) uwtable
; CHECK-LABEL: @store_unordered(
; CHECK-NEXT: store atomic i32 10, ptr [[TMP0:%.*]] unordered, align 4
; CHECK-NEXT: ret void
@@ -160,7 +160,7 @@ define void @store_unordered(ptr nocapture %0) norecurse nounwind uwtable {
; negative, should not deduce nosync
; atomic load with release ordering
define void @load_release(ptr nocapture %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
+; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @load_release(
; CHECK-NEXT: store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4
; CHECK-NEXT: ret void
@@ -171,7 +171,7 @@ define void @load_release(ptr nocapture %0) norecurse nounwind uwtable {
; negative volatile, relaxed atomic
define void @load_volatile_release(ptr nocapture %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
+; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @load_volatile_release(
; CHECK-NEXT: store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4
; CHECK-NEXT: ret void
@@ -182,7 +182,7 @@ define void @load_volatile_release(ptr nocapture %0) norecurse nounwind uwtable
; volatile store.
define void @volatile_store(ptr %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
+; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @volatile_store(
; CHECK-NEXT: store volatile i32 14, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: ret void
@@ -194,7 +194,7 @@ define void @volatile_store(ptr %0) norecurse nounwind uwtable {
; negative, should not deduce nosync
; volatile load.
define i32 @volatile_load(ptr %0) norecurse nounwind uwtable {
-; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
+; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite) uwtable
; CHECK-LABEL: @volatile_load(
; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, ptr [[TMP0:%.*]], align 4
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -204,7 +204,6 @@ define i32 @volatile_load(ptr %0) norecurse nounwind uwtable {
}
; CHECK: Function Attrs: noinline nosync nounwind uwtable
-; CHECK-NEXT: declare void @nosync_function()
declare void @nosync_function() noinline nounwind uwtable nosync
define void @call_nosync_function() nounwind uwtable noinline {
@@ -218,7 +217,6 @@ define void @call_nosync_function() nounwind uwtable noinline {
}
; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK-NEXT: declare void @might_sync()
declare void @might_sync() noinline nounwind uwtable
define void @call_might_sync() nounwind uwtable noinline {
@@ -280,7 +278,6 @@ define void @convergent_readnone(){
}
; CHECK: Function Attrs: nounwind
-; CHECK-NEXT: declare void @llvm.x86.sse2.clflush(ptr)
declare void @llvm.x86.sse2.clflush(ptr)
@a = common global i32 0, align 4
diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
index 554670479ab8d45..8148bbf5ccb4ce5 100644
--- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll
+++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
@@ -218,9 +218,9 @@ entry:
}
define void @test8_2(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; FNATTRS-LABEL: define {{[^@]+}}@test8_2
-; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR4]] {
+; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR6:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr [[P]])
; FNATTRS-NEXT: store i32 10, ptr [[CALL]], align 4
@@ -253,7 +253,7 @@ declare void @llvm.masked.scatter.v4i32.v4p0(<4 x i32>%val, <4 x ptr>, i32, <4 x
define void @test9(<4 x ptr> %ptrs, <4 x i32>%val) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
; FNATTRS-LABEL: define {{[^@]+}}@test9
-; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR7:[0-9]+]] {
+; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR8:[0-9]+]] {
; FNATTRS-NEXT: call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>)
; FNATTRS-NEXT: ret void
;
@@ -277,7 +277,7 @@ declare <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr>, i32, <4 x i1>, <4 x
define <4 x i32> @test10(<4 x ptr> %ptrs) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
; FNATTRS-LABEL: define {{[^@]+}}@test10
-; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR9:[0-9]+]] {
+; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR10:[0-9]+]] {
; FNATTRS-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef)
; FNATTRS-NEXT: ret <4 x i32> [[RES]]
;
@@ -301,7 +301,7 @@ declare <4 x i32> @test11_1(<4 x ptr>) argmemonly nounwind readonly
define <4 x i32> @test11_2(<4 x ptr> %ptrs) {
; FNATTRS: Function Attrs: nofree nounwind memory(argmem: read)
; FNATTRS-LABEL: define {{[^@]+}}@test11_2
-; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR11:[0-9]+]] {
+; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR12:[0-9]+]] {
; FNATTRS-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]])
; FNATTRS-NEXT: ret <4 x i32> [[RES]]
;
@@ -325,7 +325,7 @@ declare <4 x i32> @test12_1(<4 x ptr>) argmemonly nounwind
define <4 x i32> @test12_2(<4 x ptr> %ptrs) {
; FNATTRS: Function Attrs: nounwind memory(argmem: readwrite)
; FNATTRS-LABEL: define {{[^@]+}}@test12_2
-; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR12:[0-9]+]] {
+; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR13:[0-9]+]] {
; FNATTRS-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]])
; FNATTRS-NEXT: ret <4 x i32> [[RES]]
;
@@ -346,9 +346,9 @@ define <4 x i32> @test12_2(<4 x ptr> %ptrs) {
}
define i32 @volatile_load(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite)
; FNATTRS-LABEL: define {{[^@]+}}@volatile_load
-; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR13:[0-9]+]] {
+; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR14:[0-9]+]] {
; FNATTRS-NEXT: [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4
; FNATTRS-NEXT: ret i32 [[LOAD]]
;
@@ -570,7 +570,7 @@ define void @fptr_test2c(ptr %p, ptr %f) {
define void @alloca_recphi() {
; FNATTRS: Function Attrs: nofree norecurse nosync nounwind memory(none)
; FNATTRS-LABEL: define {{[^@]+}}@alloca_recphi
-; FNATTRS-SAME: () #[[ATTR14:[0-9]+]] {
+; FNATTRS-SAME: () #[[ATTR15:[0-9]+]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[A:%.*]] = alloca [8 x i32], align 4
; FNATTRS-NEXT: [[A_END:%.*]] = getelementptr i32, ptr [[A]], i64 8
@@ -721,9 +721,9 @@ define void @op_bundle_readonly_unknown(ptr %p) {
}
define i32 @writable_readonly(ptr writable dereferenceable(4) %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: define {{[^@]+}}@writable_readonly
-; FNATTRS-SAME: (ptr readonly captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
+; FNATTRS-SAME: (ptr readonly captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR16:[0-9]+]] {
; FNATTRS-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4
; FNATTRS-NEXT: ret i32 [[V]]
;
diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/FunctionAttrs/willreturn.ll
index dc0280288b4fe3b..f846d5c7a7ea3cc 100644
--- a/llvm/test/Transforms/FunctionAttrs/willreturn.ll
+++ b/llvm/test/Transforms/FunctionAttrs/willreturn.ll
@@ -25,7 +25,7 @@ while.body:
}
define i32 @mustprogress_load(ptr %ptr) mustprogress {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: @mustprogress_load(
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: br label [[WHILE_BODY:%.*]]
@@ -50,13 +50,21 @@ while.body:
}
define void @mustprogress_store(ptr %ptr) mustprogress {
-; COMMON: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write)
-; COMMON-LABEL: @mustprogress_store(
-; COMMON-NEXT: entry:
-; COMMON-NEXT: br label [[WHILE_BODY:%.*]]
-; COMMON: while.body:
-; COMMON-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
-; COMMON-NEXT: br label [[WHILE_BODY]]
+; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write, errnomem: write)
+; FNATTRS-LABEL: @mustprogress_store(
+; FNATTRS-NEXT: entry:
+; FNATTRS-NEXT: br label [[WHILE_BODY:%.*]]
+; FNATTRS: while.body:
+; FNATTRS-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
+; FNATTRS-NEXT: br label [[WHILE_BODY]]
+;
+; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write)
+; ATTRIBUTOR-LABEL: @mustprogress_store(
+; ATTRIBUTOR-NEXT: entry:
+; ATTRIBUTOR-NEXT: br label [[WHILE_BODY:%.*]]
+; ATTRIBUTOR: while.body:
+; ATTRIBUTOR-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
+; ATTRIBUTOR-NEXT: br label [[WHILE_BODY]]
;
entry:
br label %while.body
@@ -79,7 +87,7 @@ define void @mustprogress_call_unknown_fn() mustprogress {
}
define i32 @mustprogress_call_known_functions(ptr %ptr) mustprogress {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: @mustprogress_call_known_functions(
; FNATTRS-NEXT: call void @mustprogress_readnone()
; FNATTRS-NEXT: [[R:%.*]] = call i32 @mustprogress_load(ptr [[PTR:%.*]])
diff --git a/llvm/test/Transforms/FunctionAttrs/writeonly.ll b/llvm/test/Transforms/FunctionAttrs/writeonly.ll
index fdf9734ebda84f8..8af4c7ef819f894 100644
--- a/llvm/test/Transforms/FunctionAttrs/writeonly.ll
+++ b/llvm/test/Transforms/FunctionAttrs/writeonly.ll
@@ -20,7 +20,7 @@ nouses-argworn-funrn_entry:
}
define void @nouses-argworn-funro(ptr writeonly %.aaa, ptr %.bbb) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read, errnomem: read)
; FNATTRS-LABEL: define {{[^@]+}}@nouses-argworn-funro
; FNATTRS-SAME: (ptr readnone captures(none) [[DOTAAA:%.*]], ptr readonly captures(none) [[DOTBBB:%.*]]) #[[ATTR1:[0-9]+]] {
; FNATTRS-NEXT: nouses-argworn-funro_entry:
@@ -64,7 +64,7 @@ nouses-argworn-funwo_entry:
}
define void @test_store(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; FNATTRS-LABEL: define {{[^@]+}}@test_store
; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 1)) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
; FNATTRS-NEXT: store i8 0, ptr [[P]], align 1
@@ -105,7 +105,7 @@ define i8 @test_store_capture(ptr %p) {
}
define void @test_addressing(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; FNATTRS-LABEL: define {{[^@]+}}@test_addressing
; FNATTRS-SAME: (ptr writeonly captures(none) initializes((8, 12)) [[P:%.*]]) #[[ATTR3]] {
; FNATTRS-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
@@ -125,7 +125,7 @@ define void @test_addressing(ptr %p) {
}
define void @test_readwrite(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; FNATTRS-LABEL: define {{[^@]+}}@test_readwrite
; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR5:[0-9]+]] {
; FNATTRS-NEXT: [[V:%.*]] = load i8, ptr [[P]], align 1
@@ -145,7 +145,7 @@ define void @test_readwrite(ptr %p) {
}
define void @test_volatile(ptr %p) {
-; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)
+; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: readwrite)
; FNATTRS-LABEL: define {{[^@]+}}@test_volatile
; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR6:[0-9]+]] {
; FNATTRS-NEXT: store volatile i8 0, ptr [[P]], align 1
@@ -162,7 +162,7 @@ define void @test_volatile(ptr %p) {
}
define void @test_atomicrmw(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, errnomem: readwrite)
; FNATTRS-LABEL: define {{[^@]+}}@test_atomicrmw
; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR7:[0-9]+]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = atomicrmw add ptr [[P]], i8 0 seq_cst, align 1
@@ -179,7 +179,7 @@ define void @test_atomicrmw(ptr %p) {
}
define void @test_ptrmask(ptr %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, errnomem: write)
; FNATTRS-LABEL: define {{[^@]+}}@test_ptrmask
; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR3]] {
; FNATTRS-NEXT: [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -5)
More information about the Mlir-commits
mailing list