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 } @@ -9196,27 +9196,25 @@ ``sanitize_thread`` or ``sanitize_address`` attributes. The optional ``!nontemporal`` metadata must reference a single -metadata name ```` corresponding to a metadata node with one -``i32`` entry of value 1. The existence of the ``!nontemporal`` +metadata node corresponding to a node with one ``i32`` entry of value 1. +The existence of the ``!nontemporal`` metadata on the instruction tells the optimizer and code generator that this load is not expected to be reused in the cache. The code generator may select special instructions to save cache bandwidth, such as the ``MOVNT`` instruction on x86. -The optional ``!invariant.load`` metadata must reference a single -metadata name ```` corresponding to a metadata node with no -entries. If a load instruction tagged with the ``!invariant.load`` +The optional ``!invariant.load`` metadata must reference a single metadata +node with no entries. If a load instruction tagged with the ``!invariant.load`` metadata is executed, the optimizer may assume the memory location referenced by the load contains the same value at all points in the program where the memory location is known to be dereferenceable; otherwise, the behavior is undefined. -The optional ``!invariant.group`` metadata must reference a single metadata name - ```` corresponding to a metadata node with no entries. - See ``invariant.group`` metadata :ref:`invariant.group ` +The optional ``!invariant.group`` metadata must reference a single metadata +node with no entries. See ``invariant.group`` metadata :ref:`invariant.group +` -The optional ``!nonnull`` metadata must reference a single -metadata name ```` corresponding to a metadata node with no +The optional ``!nonnull`` metadata must reference a single metadata node with no entries. The existence of the ``!nonnull`` metadata on the instruction tells the optimizer that the value loaded is known to never be null. If the value is null at runtime, the behavior is undefined. @@ -9224,18 +9222,19 @@ values. This metadata can only be applied to loads of a pointer type. The optional ``!dereferenceable`` metadata must reference a single metadata -name ```` corresponding to a metadata node with one ``i64`` -entry. +node corresponding to a node with one ``i64`` entry representing the number of +dereferenceable bytes of the loaded pointer. See ``dereferenceable`` metadata :ref:`dereferenceable ` The optional ``!dereferenceable_or_null`` metadata must reference a single -metadata name ```` corresponding to a metadata node with one -``i64`` entry. +metadata node corresponding to a node with one ``i64`` entry representing +the number of dereferenceable bytes of the loaded pointer of not null. See ``dereferenceable_or_null`` metadata :ref:`dereferenceable_or_null ` -The optional ``!align`` metadata must reference a single metadata name -```` corresponding to a metadata node with one ``i64`` entry. +The optional ``!align`` metadata must reference a single metadata node +corresponding to a node with one ``i64`` entry representing the alignment of +the loaded pointer. The existence of the ``!align`` metadata on the instruction tells the optimizer that the value loaded is known to be aligned to a boundary specified by the integer value in the metadata node. The alignment must be a power of 2. @@ -9243,6 +9242,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 node +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 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 +}