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 <_welldefinedvalues>`. +If the value isn't well defined, the behavior is undefined. + Semantics: """""""""" diff --git a/llvm/docs/LangRef.rst.rej b/llvm/docs/LangRef.rst.rej new file mode 100644 --- /dev/null +++ b/llvm/docs/LangRef.rst.rej @@ -0,0 +1,77 @@ +diff a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst (rejected hunks) +@@ -9149,10 +9149,11 @@ + + :: + +- = load [volatile] , * [, align ][, !nontemporal !][, !invariant.load !][, !invariant.group !][, !nonnull !][, !dereferenceable !][, !dereferenceable_or_null !][, !align !] +- = load atomic [volatile] , * [syncscope("")] , align [, !invariant.group !] +- ! = !{ i32 1 } +- ! = !{i64 } ++ = 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 } + ! = !{ i64 } + + Overview: +@@ -9196,27 +9197,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 +9223,17 @@ + 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. + 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. + 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. + 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. 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 +}