[llvm] [IR] Allow nofree metadata to inttoptr (PR #153149)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 31 20:07:48 PDT 2025
https://github.com/ruiling updated https://github.com/llvm/llvm-project/pull/153149
>From 261eeb7a228dbcf94e43842e680754ae1e45b709 Mon Sep 17 00:00:00 2001
From: Ruiling Song <ruiling.song at amd.com>
Date: Tue, 12 Aug 2025 15:31:31 +0800
Subject: [PATCH 1/3] [IR] Allow nofree metadata to inttoptr
Our GPU compiler usually construct pointers through inttoptr. The memory
was pre-allocated before the shader function execution and remains valid
through the execution of the shader function. This brings back the
expected behavior of instruction hoisting for the test `hoist-speculatable-load.ll`,
which was broken by #126117.
---
llvm/docs/LangRef.rst | 16 +++++++++++++++-
llvm/include/llvm/IR/FixedMetadataKinds.def | 1 +
llvm/lib/IR/Value.cpp | 3 +++
llvm/lib/IR/Verifier.cpp | 13 +++++++++++++
.../Transforms/LICM/hoist-speculatable-load.ll | 6 +++---
llvm/test/Verifier/nofree_metadata.ll | 15 +++++++++++++++
6 files changed, 50 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/Verifier/nofree_metadata.ll
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 162208fb1c81c..2c22190079e28 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8481,6 +8481,14 @@ specific. The behavior is undefined if the runtime memory address does
resolve to an object defined in one of the indicated address spaces.
+'``nofree``' Metadata
+^^^^^^^^^^^^^^^^^^^^^
+
+The ``nofree`` metadata indicates the memory pointed by the pointer will not be
+freed during the execution of the function . This is analogous to the ``nofree``
+function argument attribute.
+
+
Module Flags Metadata
=====================
@@ -12592,7 +12600,7 @@ Syntax:
::
- <result> = inttoptr <ty> <value> to <ty2>[, !dereferenceable !<deref_bytes_node>][, !dereferenceable_or_null !<deref_bytes_node>] ; yields ty2
+ <result> = inttoptr <ty> <value> to <ty2>[, !dereferenceable !<deref_bytes_node>][, !dereferenceable_or_null !<deref_bytes_node>][, !nofree !<empty_node>] ; yields ty2
Overview:
"""""""""
@@ -12617,6 +12625,12 @@ metadata name ``<deref_bytes_node>`` corresponding to a metadata node with one
``i64`` entry.
See ``dereferenceable_or_null`` metadata.
+The optional ``!nofree`` metadata must reference a single metadata name
+``<empty_node>`` corresponding to a metadata node with no entries.
+The existence of the ``!nofree`` metadata on the instruction tells the optimizer
+that the memory pointed by the pointer will not be freed during the execution of
+the function.
+
Semantics:
""""""""""
diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def
index 90276eae13e4b..d09cc15d65ff6 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -54,3 +54,4 @@ LLVM_FIXED_MD_KIND(MD_coro_outside_frame, "coro.outside.frame", 39)
LLVM_FIXED_MD_KIND(MD_mmra, "mmra", 40)
LLVM_FIXED_MD_KIND(MD_noalias_addrspace, "noalias.addrspace", 41)
LLVM_FIXED_MD_KIND(MD_callee_type, "callee_type", 42)
+LLVM_FIXED_MD_KIND(MD_nofree, "nofree", 43)
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index 5928c89029b87..4e8f359481b81 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -836,6 +836,9 @@ bool Value::canBeFreed() const {
return false;
}
+ if (isa<IntToPtrInst>(this) && getMetadata(LLVMContext::MD_nofree))
+ return false;
+
const Function *F = nullptr;
if (auto *I = dyn_cast<Instruction>(this))
F = I->getFunction();
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 1d3c379f461fa..70349e0000796 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -527,6 +527,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
void visitRangeMetadata(Instruction &I, MDNode *Range, Type *Ty);
void visitNoaliasAddrspaceMetadata(Instruction &I, MDNode *Range, Type *Ty);
void visitDereferenceableMetadata(Instruction &I, MDNode *MD);
+ void visitNofreeMetadata(Instruction &I, MDNode *MD);
void visitProfMetadata(Instruction &I, MDNode *MD);
void visitCallStackMetadata(MDNode *MD);
void visitMemProfMetadata(Instruction &I, MDNode *MD);
@@ -5022,6 +5023,15 @@ void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) {
&I);
}
+void Verifier::visitNofreeMetadata(Instruction &I, MDNode *MD) {
+ Check(I.getType()->isPointerTy(), "nofree apply only to pointer types", &I);
+ Check((isa<IntToPtrInst>(I)),
+ "nofree applies only to inttoptr instruction,"
+ " use attributes for calls or invokes",
+ &I);
+ Check(MD->getNumOperands() == 0, "nofree metadata must be empty", &I);
+}
+
void Verifier::visitProfMetadata(Instruction &I, MDNode *MD) {
auto GetBranchingTerminatorNumOperands = [&]() {
unsigned ExpectedNumOperands = 0;
@@ -5497,6 +5507,9 @@ void Verifier::visitInstruction(Instruction &I) {
if (MDNode *MD = I.getMetadata(LLVMContext::MD_dereferenceable_or_null))
visitDereferenceableMetadata(I, MD);
+ if (MDNode *MD = I.getMetadata(LLVMContext::MD_nofree))
+ visitNofreeMetadata(I, MD);
+
if (MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa))
TBAAVerifyHelper.visitTBAAMetadata(I, TBAA);
diff --git a/llvm/test/Transforms/LICM/hoist-speculatable-load.ll b/llvm/test/Transforms/LICM/hoist-speculatable-load.ll
index a4a38c2eaadc3..31236e8f29d60 100644
--- a/llvm/test/Transforms/LICM/hoist-speculatable-load.ll
+++ b/llvm/test/Transforms/LICM/hoist-speculatable-load.ll
@@ -4,19 +4,19 @@
define void @f(i32 %ptr_i, ptr %ptr2, i1 %cond) {
; CHECK-LABEL: @f(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[PTR:%.*]] = inttoptr i32 [[PTR_I:%.*]] to ptr
+; CHECK-NEXT: [[PTR:%.*]] = inttoptr i32 [[PTR_I:%.*]] to ptr, !nofree [[META0:![0-9]+]]
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i32 16), "dereferenceable"(ptr [[PTR]], i32 16) ]
; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR_BODY_LR_PH:%.*]], label [[IF0:%.*]]
; CHECK: if0:
; CHECK-NEXT: store i32 0, ptr [[PTR2:%.*]], align 4
; CHECK-NEXT: br label [[FOR_BODY_LR_PH]]
; CHECK: for.body.lr.ph:
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_08:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
; CHECK-NEXT: br i1 [[COND]], label [[IF_END]], label [[IF:%.*]]
; CHECK: if:
-; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[PTR]], align 4, !invariant.load [[META0:![0-9]+]]
; CHECK-NEXT: store i32 [[TMP0]], ptr [[PTR2]], align 4
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
@@ -27,7 +27,7 @@ define void @f(i32 %ptr_i, ptr %ptr2, i1 %cond) {
; CHECK-NEXT: ret void
;
entry:
- %ptr = inttoptr i32 %ptr_i to ptr
+ %ptr = inttoptr i32 %ptr_i to ptr, !nofree !{}
call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i32 16), "dereferenceable"(ptr %ptr, i32 16) ]
br i1 %cond, label %for.body.lr.ph, label %if0
diff --git a/llvm/test/Verifier/nofree_metadata.ll b/llvm/test/Verifier/nofree_metadata.ll
new file mode 100644
index 0000000000000..e4db00987355a
--- /dev/null
+++ b/llvm/test/Verifier/nofree_metadata.ll
@@ -0,0 +1,15 @@
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+
+declare ptr @dummy()
+
+; CHECK: nofree applies only to inttoptr instruction, use attributes for calls or invokes
+define void @test_not_inttoptr() {
+ call ptr @dummy(), !nofree !{}
+ ret void
+}
+
+; CHECK: nofree metadata must be empty
+define void @test_invalid_arg(i32 %p) {
+ inttoptr i32 %p to ptr, !nofree !{i32 0}
+ ret void
+}
>From 9741f68bafd510cdb85f6ac4acdaf7732564c1e4 Mon Sep 17 00:00:00 2001
From: Ruiling Song <ruiling.song at amd.com>
Date: Thu, 21 Aug 2025 10:01:47 +0800
Subject: [PATCH 2/3] Address review comments
---
llvm/docs/LangRef.rst | 5 ++---
llvm/lib/IR/Verifier.cpp | 2 +-
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 2c22190079e28..bd7c426643f73 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8485,7 +8485,7 @@ resolve to an object defined in one of the indicated address spaces.
^^^^^^^^^^^^^^^^^^^^^
The ``nofree`` metadata indicates the memory pointed by the pointer will not be
-freed during the execution of the function . This is analogous to the ``nofree``
+freed after the attached instruction. This is analogous to the ``nofree``
function argument attribute.
@@ -12628,8 +12628,7 @@ See ``dereferenceable_or_null`` metadata.
The optional ``!nofree`` metadata must reference a single metadata name
``<empty_node>`` corresponding to a metadata node with no entries.
The existence of the ``!nofree`` metadata on the instruction tells the optimizer
-that the memory pointed by the pointer will not be freed during the execution of
-the function.
+that the memory pointed by the pointer will not be freed after this point.
Semantics:
""""""""""
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 70349e0000796..171ae0c34114b 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5024,7 +5024,7 @@ void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) {
}
void Verifier::visitNofreeMetadata(Instruction &I, MDNode *MD) {
- Check(I.getType()->isPointerTy(), "nofree apply only to pointer types", &I);
+ Check(I.getType()->isPointerTy(), "nofree applies only to pointer types", &I);
Check((isa<IntToPtrInst>(I)),
"nofree applies only to inttoptr instruction,"
" use attributes for calls or invokes",
>From 64e1781bf872db1ab50661c71084bfbede085140 Mon Sep 17 00:00:00 2001
From: Ruiling Song <ruiling.song at amd.com>
Date: Mon, 1 Sep 2025 11:06:21 +0800
Subject: [PATCH 3/3] Address review comment
---
llvm/docs/LangRef.rst | 3 +--
llvm/lib/IR/Verifier.cpp | 4 +---
llvm/test/Verifier/nofree_metadata.ll | 2 +-
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index bd7c426643f73..4012d28d3a396 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8485,8 +8485,7 @@ resolve to an object defined in one of the indicated address spaces.
^^^^^^^^^^^^^^^^^^^^^
The ``nofree`` metadata indicates the memory pointed by the pointer will not be
-freed after the attached instruction. This is analogous to the ``nofree``
-function argument attribute.
+freed after the attached instruction.
Module Flags Metadata
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 171ae0c34114b..55c100af5b8b6 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5025,9 +5025,7 @@ void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) {
void Verifier::visitNofreeMetadata(Instruction &I, MDNode *MD) {
Check(I.getType()->isPointerTy(), "nofree applies only to pointer types", &I);
- Check((isa<IntToPtrInst>(I)),
- "nofree applies only to inttoptr instruction,"
- " use attributes for calls or invokes",
+ Check((isa<IntToPtrInst>(I)), "nofree applies only to inttoptr instruction",
&I);
Check(MD->getNumOperands() == 0, "nofree metadata must be empty", &I);
}
diff --git a/llvm/test/Verifier/nofree_metadata.ll b/llvm/test/Verifier/nofree_metadata.ll
index e4db00987355a..e04f5b9f1c522 100644
--- a/llvm/test/Verifier/nofree_metadata.ll
+++ b/llvm/test/Verifier/nofree_metadata.ll
@@ -2,7 +2,7 @@
declare ptr @dummy()
-; CHECK: nofree applies only to inttoptr instruction, use attributes for calls or invokes
+; CHECK: nofree applies only to inttoptr instruction
define void @test_not_inttoptr() {
call ptr @dummy(), !nofree !{}
ret void
More information about the llvm-commits
mailing list