[llvm] 62a0ec1 - Add support for !noundef metatdata on loads

Juneyoung Lee via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 16 21:50:28 PDT 2020


Author: Juneyoung Lee
Date: 2020-10-17T13:50:10+09:00
New Revision: 62a0ec1612bd6dee94f900f971afd409ddb62859

URL: https://github.com/llvm/llvm-project/commit/62a0ec1612bd6dee94f900f971afd409ddb62859
DIFF: https://github.com/llvm/llvm-project/commit/62a0ec1612bd6dee94f900f971afd409ddb62859.diff

LOG: Add support for !noundef metatdata on loads

This patch adds metadata !noundef and makes load instructions can optionally have it.
A load with !noundef always return a well-defined value (has no undef bit or isn't poison).
If the loaded value isn't well defined, the behavior is undefined.

This metadata can be used to encode the assumption from C/C++ that certain reads of variables should have well-defined values.
It is helpful for optimizing freeze instructions away, because freeze can be removed when its operand has well-defined value, and showing that a load from arbitrary location is well-defined is usually hard otherwise.

The same information can be encoded with llvm.assume with operand bundle; using metadata is chosen because I wasn't sure whether code motion can be freely done when llvm.assume is inserted from clang instead.
The existing codebase already is stripping unknown metadata when doing code motion, so using metadata is UB-safe as well.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D89050

Added: 
    

Modified: 
    llvm/docs/LangRef.rst
    llvm/include/llvm/IR/FixedMetadataKinds.def
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
    llvm/test/Transforms/InstSimplify/freeze-noundef.ll

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index a0365758489e..087cf1f1d4d7 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -9271,6 +9271,12 @@ This is analogous to the ''align'' attribute on parameters and return values.
 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
+``<empty_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 :ref:`well defined <welldefinedvalues>`.
+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
index 0e1ffef58672..1585b6b62878 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -41,3 +41,4 @@ LLVM_FIXED_MD_KIND(MD_callback, "callback", 26)
 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
index c44ad00ae4cf..4dd536e76d06 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4892,6 +4892,10 @@ static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
       return true;
   }
 
+  if (auto *I = dyn_cast<LoadInst>(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
index 9112cd594f88..e3b22aaefc9e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -522,6 +522,7 @@ static StoreInst *combineStoreToNewValue(InstCombinerImpl &IC, StoreInst &SI,
       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
index 6a52bd5b257f..2260f2aa3e58 100644
--- a/llvm/test/Transforms/InstSimplify/freeze-noundef.ll
+++ b/llvm/test/Transforms/InstSimplify/freeze-noundef.ll
@@ -104,3 +104,23 @@ define i1 @used_by_fncall(i1 %x) {
   %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
+}


        


More information about the llvm-commits mailing list