diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -9271,6 +9271,12 @@ This metadata can only be applied to loads of a pointer type. If the returned value is not appropriately aligned at runtime, the behavior is undefined. +The optional ``!noundef`` metadata must reference a single metadata name +```` corresponding to a node with no entries. The existence of +``!noundef`` metadata on the instruction tells the optimizer that the value +loaded is known to be :ref:`well defined `. +If the value isn't well defined, the behavior is undefined. + Semantics: """""""""" diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def --- a/llvm/include/llvm/IR/FixedMetadataKinds.def +++ b/llvm/include/llvm/IR/FixedMetadataKinds.def @@ -41,3 +41,4 @@ LLVM_FIXED_MD_KIND(MD_preserve_access_index, "llvm.preserve.access.index", 27) LLVM_FIXED_MD_KIND(MD_misexpect, "misexpect", 28) LLVM_FIXED_MD_KIND(MD_vcall_visibility, "vcall_visibility", 29) +LLVM_FIXED_MD_KIND(MD_noundef, "noundef", 30) \ No newline at end of file diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4892,6 +4892,10 @@ return true; } + if (auto *I = dyn_cast(V)) + if (I->getMetadata(LLVMContext::MD_noundef)) + return true; + if (programUndefinedIfUndefOrPoison(V, PoisonOnly)) return true; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -522,6 +522,7 @@ break; case LLVMContext::MD_invariant_load: case LLVMContext::MD_nonnull: + case LLVMContext::MD_noundef: case LLVMContext::MD_range: case LLVMContext::MD_align: case LLVMContext::MD_dereferenceable: diff --git a/llvm/test/Transforms/InstSimplify/freeze-noundef.ll b/llvm/test/Transforms/InstSimplify/freeze-noundef.ll --- a/llvm/test/Transforms/InstSimplify/freeze-noundef.ll +++ b/llvm/test/Transforms/InstSimplify/freeze-noundef.ll @@ -104,3 +104,23 @@ %f = freeze i1 %y ret i1 %f } + +define i32 @noundef_metadata(i32* %p) { +; CHECK-LABEL: @noundef_metadata( +; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P:%.*]], align 4, !noundef !0 +; CHECK-NEXT: ret i32 [[V]] +; + %v = load i32, i32* %p, !noundef !{} + %v.fr = freeze i32 %v + ret i32 %v.fr +} + +define {i8, i32} @noundef_metadata2({i8, i32}* %p) { +; CHECK-LABEL: @noundef_metadata2( +; CHECK-NEXT: [[V:%.*]] = load { i8, i32 }, { i8, i32 }* [[P:%.*]], align 4, !noundef !0 +; CHECK-NEXT: ret { i8, i32 } [[V]] +; + %v = load {i8, i32}, {i8, i32}* %p, !noundef !{} + %v.fr = freeze {i8, i32} %v + ret {i8, i32} %v.fr +}