diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index b122fd352eaf5..b18947952be57 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -8352,6 +8352,13 @@ 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 after the attached instruction. + + Module Flags Metadata ===================== @@ -12463,7 +12470,7 @@ Syntax: :: - = inttoptr to [, !dereferenceable !][, !dereferenceable_or_null !] ; yields ty2 + = inttoptr to [, !dereferenceable !][, !dereferenceable_or_null !][, !nofree !] ; yields ty2 Overview: """"""""" @@ -12488,6 +12495,11 @@ metadata name ```` corresponding to a metadata node with one ``i64`` entry. See ``dereferenceable_or_null`` metadata. +The optional ``!nofree`` metadata must reference a single metadata name +```` 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 after this point. + 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(this) && getMetadata(LLVMContext::MD_nofree)) + return false; + const Function *F = nullptr; if (auto *I = dyn_cast(this)) F = I->getFunction(); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index da05ff166122f..48007be924bda 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -526,6 +526,7 @@ class Verifier : public InstVisitor, 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); @@ -5023,6 +5024,13 @@ void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) { &I); } +void Verifier::visitNofreeMetadata(Instruction &I, MDNode *MD) { + Check(I.getType()->isPointerTy(), "nofree applies only to pointer types", &I); + Check((isa(I)), "nofree applies only to inttoptr instruction", + &I); + Check(MD->getNumOperands() == 0, "nofree metadata must be empty", &I); +} + void Verifier::visitProfMetadata(Instruction &I, MDNode *MD) { auto GetBranchingTerminatorNumOperands = [&]() { unsigned ExpectedNumOperands = 0; @@ -5498,6 +5506,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..e04f5b9f1c522 --- /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 +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 +}