diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -9149,7 +9149,7 @@ :: - = load [volatile] , * [, align ][, !nontemporal !][, !invariant.load !][, !invariant.group !][, !nonnull !][, !dereferenceable !][, !dereferenceable_or_null !][, !align !] + = load [volatile] , * [, align ][, !nontemporal !][, !invariant.load !][, !invariant.group !][, !nonnull !][, !dereferenceable !][, !dereferenceable_or_null !][, !align !][, !noundef !] = load atomic [volatile] , * [syncscope("")] , align [, !invariant.group !] ! = !{ i32 1 } ! = !{i64 } @@ -9243,6 +9243,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 metadata node with no entries. The existence of +``!noundef`` metadata on the instruction tells the optimizer that the value +loaded is known to be 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 @@ -4960,6 +4960,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 @@ -488,6 +488,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 +}