[PATCH] D89050: Add support for !noundef metatdata on loads

Juneyoung Lee via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 8 08:40:04 PDT 2020


aqjune created this revision.
aqjune added reviewers: jdoerfert, reames, efriedma, nikic, fhahn.
Herald added subscribers: llvm-commits, hiraditya.
Herald added a project: LLVM.
aqjune requested review of this revision.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89050

Files:
  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


Index: llvm/test/Transforms/InstSimplify/freeze-noundef.ll
===================================================================
--- llvm/test/Transforms/InstSimplify/freeze-noundef.ll
+++ 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
+}
Index: llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
===================================================================
--- llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ 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:
Index: llvm/lib/Analysis/ValueTracking.cpp
===================================================================
--- llvm/lib/Analysis/ValueTracking.cpp
+++ llvm/lib/Analysis/ValueTracking.cpp
@@ -4960,6 +4960,10 @@
       return true;
   }
 
+  if (auto *I = dyn_cast<LoadInst>(V))
+    if (I->getMetadata(LLVMContext::MD_noundef))
+      return true;
+
   if (programUndefinedIfUndefOrPoison(V, PoisonOnly))
     return true;
 
Index: llvm/include/llvm/IR/FixedMetadataKinds.def
===================================================================
--- llvm/include/llvm/IR/FixedMetadataKinds.def
+++ 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
Index: llvm/docs/LangRef.rst
===================================================================
--- llvm/docs/LangRef.rst
+++ llvm/docs/LangRef.rst
@@ -9149,7 +9149,7 @@
 
 ::
 
-      <result> = load [volatile] <ty>, <ty>* <pointer>[, align <alignment>][, !nontemporal !<index>][, !invariant.load !<index>][, !invariant.group !<index>][, !nonnull !<index>][, !dereferenceable !<deref_bytes_node>][, !dereferenceable_or_null !<deref_bytes_node>][, !align !<align_node>]
+      <result> = load [volatile] <ty>, <ty>* <pointer>[, align <alignment>][, !nontemporal !<index>][, !invariant.load !<index>][, !invariant.group !<index>][, !nonnull !<index>][, !dereferenceable !<deref_bytes_node>][, !dereferenceable_or_null !<deref_bytes_node>][, !align !<align_node>][, !noundef !<index>]
       <result> = load atomic [volatile] <ty>, <ty>* <pointer> [syncscope("<target-scope>")] <ordering>, align <alignment> [, !invariant.group !<index>]
       !<index> = !{ i32 1 }
       !<deref_bytes_node> = !{i64 <dereferenceable_bytes>}
@@ -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
+``<index>`` 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:
 """"""""""
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D89050.296980.patch
Type: text/x-patch
Size: 3930 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20201008/4d7a6cda/attachment.bin>


More information about the llvm-commits mailing list