Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
46fe79b
[RFC][Draft] Extend MemoryEffects to Support Target-Specific Memory L…
CarolineConcatto Jul 1, 2025
0d61d31
Address review comments about tests and names
CarolineConcatto Jul 15, 2025
52133b0
Remove old function header that doesn't exist
CarolineConcatto Jul 15, 2025
b94a65e
Fix test when target memory locations are combined
CarolineConcatto Jul 16, 2025
66e3b38
Fix codegen for opencl tests
CarolineConcatto Jul 23, 2025
f386e96
Address review comments
CarolineConcatto Aug 20, 2025
2e898b1
Remove unwanted changes from the test memory-attribute.ll
CarolineConcatto Aug 20, 2025
3a7bc26
Make target memory locations generic; resolve meaning via Triple
CarolineConcatto Aug 21, 2025
8ddc872
Change ModRef.cpp to use generic memory target name
CarolineConcatto Aug 21, 2025
6d7fa02
Fix clang format
CarolineConcatto Aug 21, 2025
d2ca3e9
Remove Target Triple interface for Target Memory
CarolineConcatto Sep 17, 2025
c609105
Remove all Target specific tokens and definitions
CarolineConcatto Sep 23, 2025
25b15b6
Address review comments
CarolineConcatto Sep 30, 2025
8f87c37
Address comments in FunctionAttrs.cpp
CarolineConcatto Oct 3, 2025
231bc7c
Address review comments
CarolineConcatto Oct 6, 2025
85a89f2
Address comments about tablegen
CarolineConcatto Oct 10, 2025
c7b65eb
Address review comments
CarolineConcatto Oct 17, 2025
3de8c96
Remove unwanted changes
CarolineConcatto Oct 20, 2025
dbc1676
Set target_mem when they are not set with inaccessiblemem
CarolineConcatto Oct 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions clang/test/CodeGen/sanitize-metadata-nosanitize.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, target_mem0: none, target_mem1: none)
// CHECK-LABEL: define dso_local void @escape(
// CHECK-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !pcsections [[META6:![0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
Expand All @@ -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, target_mem0: none, target_mem1: 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 [[META8:![0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
Expand All @@ -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, target_mem0: none, target_mem1: 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:.*:]]
Expand All @@ -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, target_mem0: none, target_mem1: 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:.*:]]
Expand All @@ -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, target_mem0: none, target_mem1: 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:.*:]]
Expand All @@ -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, target_mem0: none, target_mem1: 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, target_mem0: none, target_mem1: 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, target_mem0: none, target_mem1: 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, target_mem0: none, target_mem1: 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}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenOpenCL/convergent.cl
Original file line number Diff line number Diff line change
Expand Up @@ -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, target_mem0: none, target_mem1: none) "
// CHECK: attributes #1 = { {{[^}]*}}convergent{{[^}]*}} }
// CHECK: attributes #2 = { {{[^}]*}}convergent{{[^}]*}} }
// CHECK: attributes #3 = { {{[^}]*}}convergent noduplicate{{[^}]*}} }
Expand Down
7 changes: 6 additions & 1 deletion llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2178,7 +2178,8 @@ For example:
This attribute specifies the possible memory effects of the call-site or
function. It allows specifying the possible access kinds (``none``,
``read``, ``write``, or ``readwrite``) for the possible memory location
kinds (``argmem``, ``inaccessiblemem``, ``errnomem``, as well as a default).
kinds (``argmem``, ``inaccessiblemem``, ``errnomem``, ``target_mem0``,
``target_mem1``, as well as a default).
It is best understood by example:

- ``memory(none)``: Does not access any memory.
Expand Down Expand Up @@ -2220,6 +2221,10 @@ For example:
accessing inaccessible memory itself). Inaccessible memory is often used
to model control dependencies of intrinsics.
- ``errnomem``: This refers to accesses to the ``errno`` variable.
- ``target_mem#`` : These refer to target specific state that cannot be
accessed by any other means. # is a number between 0 and 1 inclusive.


Comment on lines +2226 to +2227
Copy link
Collaborator

@paulwalker-arm paulwalker-arm Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete these extra blank lines.

- The default access kind (specified without a location prefix) applies to
all locations that haven't been specified explicitly, including those that
don't currently have a dedicated location kind (e.g. accesses to globals
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ enum Kind {
kw_readwrite,
kw_argmem,
kw_inaccessiblemem,
kw_target_mem0,
kw_target_mem1,
kw_errnomem,

// Legacy attributes:
Expand Down
19 changes: 19 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,25 @@ def IntrInaccessibleMemOnly : IntrinsicProperty;
// by the module being compiled. This is a weaker form of IntrArgMemOnly.
def IntrInaccessibleMemOrArgMemOnly : IntrinsicProperty;

// Tablegen representation of IRMemLocation.
class IntrinsicMemoryLocation;

// TODO: Populate with all IRMemLocation enum values and update
// getValueAsIRMemLocation accordingly.
def InaccessibleMem : IntrinsicMemoryLocation;
def TargetMem0 : IntrinsicMemoryLocation;
def TargetMem1 : IntrinsicMemoryLocation;

// The list of IRMemoryLocations that are read from.
class IntrRead<list<IntrinsicMemoryLocation> idx> : IntrinsicProperty {
list<IntrinsicMemoryLocation> MemLoc=idx;
}

// The list of IRMemoryLocations that are write to.
class IntrWrite<list<IntrinsicMemoryLocation> idx> : IntrinsicProperty {
list<IntrinsicMemoryLocation> MemLoc=idx;
}

// Commutative - This intrinsic is commutative: X op Y == Y op X.
def Commutative : IntrinsicProperty;

Expand Down
14 changes: 12 additions & 2 deletions llvm/include/llvm/Support/ModRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,15 @@ enum class IRMemLocation {
ErrnoMem = 2,
/// Any other memory.
Other = 3,
/// Represents target specific state.
TargetMem0 = 4,
TargetMem1 = 5,

/// Helpers to iterate all locations in the MemoryEffectsBase class.
First = ArgMem,
Last = Other,
FirstTarget = TargetMem0,
// TargetMem IDs must be at the end of the list.
Last = TargetMem1,
};

template <typename LocationEnum> class MemoryEffectsBase {
Expand Down Expand Up @@ -232,7 +237,10 @@ template <typename LocationEnum> class MemoryEffectsBase {

/// Whether this function only (at most) accesses inaccessible memory.
bool onlyAccessesInaccessibleMem() const {
return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory();
return getWithoutLoc(Location::InaccessibleMem)
.getWithoutLoc(IRMemLocation::TargetMem0)
.getWithoutLoc(IRMemLocation::TargetMem1)
.doesNotAccessMemory();
}

/// Whether this function only (at most) accesses errno memory.
Expand All @@ -245,6 +253,8 @@ template <typename LocationEnum> class MemoryEffectsBase {
bool onlyAccessesInaccessibleOrArgMem() const {
return getWithoutLoc(Location::InaccessibleMem)
.getWithoutLoc(Location::ArgMem)
.getWithoutLoc(Location::TargetMem0)
.getWithoutLoc(Location::TargetMem1)
.doesNotAccessMemory();
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,8 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(write);
KEYWORD(readwrite);
KEYWORD(argmem);
KEYWORD(target_mem0);
KEYWORD(target_mem1);
KEYWORD(inaccessiblemem);
KEYWORD(errnomem);
KEYWORD(argmemonly);
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2552,6 +2552,10 @@ static std::optional<MemoryEffects::Location> keywordToLoc(lltok::Kind Tok) {
return IRMemLocation::InaccessibleMem;
case lltok::kw_errnomem:
return IRMemLocation::ErrnoMem;
case lltok::kw_target_mem0:
return IRMemLocation::TargetMem0;
case lltok::kw_target_mem1:
return IRMemLocation::TargetMem1;
default:
return std::nullopt;
}
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,12 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
break;
case IRMemLocation::Other:
llvm_unreachable("This is represented as the default access kind");
case IRMemLocation::TargetMem0:
OS << "target_mem0: ";
break;
case IRMemLocation::TargetMem1:
OS << "target_mem1: ";
break;
}
OS << getModRefStr(MR);
}
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Support/ModRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, MemoryEffects ME) {
case IRMemLocation::Other:
OS << "Other: ";
break;
case IRMemLocation::TargetMem0:
OS << "TargetMem0: ";
break;
case IRMemLocation::TargetMem1:
OS << "TargetMem1: ";
break;
}
OS << ME.getModRef(Loc);
});
Expand Down
55 changes: 55 additions & 0 deletions llvm/test/Assembler/memory-attribute.ll
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,58 @@ declare void @fn_argmem_read_inaccessiblemem_write()
; CHECK: @fn_argmem_read_inaccessiblemem_write_reordered()
declare void @fn_argmem_read_inaccessiblemem_write_reordered()
memory(inaccessiblemem: write, argmem: read)

; CHECK: Function Attrs: memory(target_mem0: write)
; CHECK: @fn_write_mem_target0()
declare void @fn_write_mem_target0()
memory(target_mem0: write)

; CHECK: Function Attrs: memory(target_mem0: read)
; CHECK: @fn_read_mem_target0()
declare void @fn_read_mem_target0()
memory(target_mem0: read)

; CHECK: Function Attrs: memory(target_mem1: write)
; CHECK: @fn_write_target_mem1()
declare void @fn_write_target_mem1()
memory(target_mem1: write)

; CHECK: Function Attrs: memory(target_mem1: read)
; CHECK: @fn_read_target_mem1()
declare void @fn_read_target_mem1()
memory(target_mem1: read)

; CHECK: Function Attrs: memory(target_mem0: read, target_mem1: write)
; CHECK: @fn_read_target_mem0_write_mem_target1()
declare void @fn_read_target_mem0_write_mem_target1()
memory(target_mem0: read, target_mem1: write)

; CHECK: Function Attrs: memory(inaccessiblemem: write)
; CHECK: @fn_inaccessiblemem_write_new()
declare void @fn_inaccessiblemem_write_new()
memory(inaccessiblemem: write)

; CHECK: Function Attrs: memory(inaccessiblemem: read, target_mem0: read, target_mem1: read)
; CHECK: @fn_inaccessiblemem_target_mem0_1read()
declare void @fn_inaccessiblemem_target_mem0_1read()
memory(inaccessiblemem: read, target_mem0: read, target_mem1: read)

; CHECK: Function Attrs: memory(target_mem0: read)
; CHECK: @fn_inaccessiblemem_none_target_mem0_read()
declare void @fn_inaccessiblemem_none_target_mem0_read()
memory(inaccessiblemem: none, target_mem0: read)

; CHECK: Function Attrs: memory(write, inaccessiblemem: read)
; CHECK: @fn_write_inaccessiblemem_read_target_mem0_write
declare void @fn_write_inaccessiblemem_read_target_mem0_write()
memory(write, inaccessiblemem: read, target_mem0: write)

; CHECK: Function Attrs: memory(write, target_mem0: read)
; CHECK: @fn_write_inaccessiblemem_write_target_mem0_read()
declare void @fn_write_inaccessiblemem_write_target_mem0_read()
memory(write, inaccessiblemem: write, target_mem0: read)

; CHECK: Function Attrs: memory(write, target_mem0: read)
; CHECK: @fn_write_target_mem0_readwrite()
declare void @fn_write_target_mem0_readwrite()
memory(write, target_mem0: read)
4 changes: 2 additions & 2 deletions llvm/test/Bitcode/memory-attribute-upgrade.ll
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
; RUN: llvm-dis < %S/Inputs/memory-attribute-upgrade.bc | FileCheck %s

; CHECK: ; Function Attrs: memory(write, argmem: read)
; CHECK: ; Function Attrs: memory(write, argmem: read, target_mem0: none, target_mem1: none)
; CHECK-NEXT: define void @test_any_write_argmem_read(ptr %p)

; CHECK: ; Function Attrs: memory(read, argmem: readwrite, inaccessiblemem: none)
; CHECK: ; Function Attrs: memory(read, argmem: readwrite, inaccessiblemem: none, target_mem0: none, target_mem1: none)
; CHECK-NEXT: define void @test_any_read_argmem_readwrite(ptr %p)
Loading
Loading