First part of PR12251. Add documentation and verifier support for the range
authorRafael Espindola <rafael.espindola@gmail.com>
Sat, 24 Mar 2012 00:14:51 +0000 (00:14 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Sat, 24 Mar 2012 00:14:51 +0000 (00:14 +0000)
metadata.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@153359 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LangRef.html
include/llvm/LLVMContext.h
lib/VMCore/LLVMContext.cpp
lib/VMCore/Verifier.cpp
test/Verifier/range-1.ll [new file with mode: 0644]
test/Verifier/range-2.ll [new file with mode: 0644]

index 81dabc91af76698b0165836a06e15be13c52bba7..cfe489031e0bed9086468d445bfcd8732ce69df2 100644 (file)
         <ol>
           <li><a href="#tbaa">'<tt>tbaa</tt>' Metadata</a></li>
           <li><a href="#fpaccuracy">'<tt>fpaccuracy</tt>' Metadata</a></li>
+          <li><a href="#range">'<tt>range</tt>' Metadata</a></li>
         </ol>
       </li>
     </ol>
@@ -3028,6 +3029,39 @@ call void @llvm.dbg.value(metadata !24, i64 0, metadata !25)
 </pre>
 </div>
 
+<!-- _______________________________________________________________________ -->
+<h4>
+  <a name="range">'<tt>range</tt>' Metadata</a>
+</h4>
+
+<div>
+<p><tt>range</tt> metadata may be attached only to loads of integer types. It
+   expresses the possible ranges the loaded value is in. The ranges are
+   represented with a flattened list of integers. The loaded value is known to
+   be in the union of the ranges defined by each consecutive pair. Each pair
+   has the following properties:</p>
+<ul>
+   <li>The type must match the type loaded by the instruction.</li>
+   <li>The pair <tt>a,b</tt> represents the range <tt>[a,b)</tt>.</li>
+   <li>Both <tt>a</tt> and <tt>b</tt> are constants.</li>
+   <li>The range is allowed to wrap.</li>
+   <li>The range should not represent the full or empty set. That is,
+       <tt>a!=b</tt>. </li>
+</ul>
+
+<p>Examples:</p>
+<div class="doc_code">
+<pre>
+  %a = load i8* %x, align 1, !range !0 ; Can only be 0 or 1
+  %b = load i8* %y, align 1, !range !1 ; Can only be 255 (-1), 0 or 1
+  %c = load i8* %z, align 1, !range !2 ; Can only be 0, 1, 3, 4 or 5
+...
+!0 = metadata !{ i8 0, i8 2 }
+!1 = metadata !{ i8 255, i8 2 }
+!2 = metadata !{ i8 0, i8 2, i8 3, i8 6 }
+</pre>
+</div>
+</div>
 </div>
 
 </div>
index 47d2eaab03a95d4d8dbd6234928200ee0f866fff..18adcd1e3c2359966f560baea0da4834230221ba 100644 (file)
@@ -42,7 +42,8 @@ public:
     MD_dbg = 0,  // "dbg"
     MD_tbaa = 1, // "tbaa"
     MD_prof = 2,  // "prof"
-    MD_fpaccuracy = 3  // "fpaccuracy"
+    MD_fpaccuracy = 3,  // "fpaccuracy"
+    MD_range = 4 // "range"
   };
   
   /// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
index d77e996b5e454da57f7b510ff068f783dd81c5cd..68c56212bc6cd83d7dc2599de938c0e6e19b516f 100644 (file)
@@ -48,6 +48,11 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
   unsigned FPAccuracyID = getMDKindID("fpaccuracy");
   assert(FPAccuracyID == MD_fpaccuracy && "fpaccuracy kind id drifted");
   (void)FPAccuracyID;
+
+  // Create the 'range' metadata kind.
+  unsigned RangeID = getMDKindID("range");
+  assert(RangeID == MD_range && "range kind id drifted");
+  (void)RangeID;
 }
 LLVMContext::~LLVMContext() { delete pImpl; }
 
index 5b9b2a5258c60150772947f9d1211fae0aa941aa..f62441bea7aab8dfcf321dabe2504456d2777508 100644 (file)
@@ -51,6 +51,7 @@
 #include "llvm/DerivedTypes.h"
 #include "llvm/InlineAsm.h"
 #include "llvm/IntrinsicInst.h"
+#include "llvm/LLVMContext.h"
 #include "llvm/Metadata.h"
 #include "llvm/Module.h"
 #include "llvm/Pass.h"
@@ -1369,6 +1370,25 @@ void Verifier::visitLoadInst(LoadInst &LI) {
     Assert1(LI.getSynchScope() == CrossThread,
             "Non-atomic load cannot have SynchronizationScope specified", &LI);
   }
+
+  if (MDNode *Range = LI.getMetadata(LLVMContext::MD_range)) {
+    unsigned NumOperands = Range->getNumOperands();
+    Assert1(NumOperands % 2 == 0, "Unfinished range!", Range);
+    unsigned NumRanges = NumOperands / 2;
+    Assert1(NumRanges >= 1, "It should have at least one range!", Range);
+    for (unsigned i = 0; i < NumRanges; ++i) {
+      ConstantInt *Low = dyn_cast<ConstantInt>(Range->getOperand(2*i));
+      Assert1(Low, "The lower limit must be an integer!", Low);
+      ConstantInt *High = dyn_cast<ConstantInt>(Range->getOperand(2*i + 1));
+      Assert1(High, "The upper limit must be an integer!", High);
+      Assert1(High->getType() == Low->getType() &&
+              High->getType() == ElTy, "Range types must match load type!",
+              &LI);
+      Assert1(High->getValue() != Low->getValue(), "Range must not be empty!",
+              Range);
+    }
+  }
+
   visitInstruction(LI);
 }
 
@@ -1641,6 +1661,10 @@ void Verifier::visitInstruction(Instruction &I) {
               "Cannot take the address of an inline asm!", &I);
     }
   }
+
+  MDNode *MD = I.getMetadata(LLVMContext::MD_range);
+  Assert1(!MD || isa<LoadInst>(I), "Ranges are only for loads!", &I);
+
   InstsInThisBlock.insert(&I);
 }
 
diff --git a/test/Verifier/range-1.ll b/test/Verifier/range-1.ll
new file mode 100644 (file)
index 0000000..611933a
--- /dev/null
@@ -0,0 +1,78 @@
+; RUN: not llvm-as < %s -o /dev/null |& FileCheck %s
+
+define void @f1(i8* %x) {
+entry:
+  store i8 0, i8* %x, align 1, !range !0
+  ret void
+}
+!0 = metadata !{i8 0, i8 1}
+; CHECK: Ranges are only for loads!
+; CHECK-NEXT: store i8 0, i8* %x, align 1, !range !0
+
+define i8 @f2(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !1
+  ret i8 %y
+}
+!1 = metadata !{}
+; CHECK: It should have at least one range!
+; CHECK-NEXT: metadata
+
+define i8 @f3(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !2
+  ret i8 %y
+}
+!2 = metadata !{i8 0}
+; CHECK: Unfinished range!
+
+define i8 @f4(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !3
+  ret i8 %y
+}
+!3 = metadata !{double 0.0, i8 0}
+; CHECK: The lower limit must be an integer!
+
+define i8 @f5(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !4
+  ret i8 %y
+}
+!4 = metadata !{i8 0, double 0.0}
+; CHECK: The upper limit must be an integer!
+
+define i8 @f6(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !5
+  ret i8 %y
+}
+!5 = metadata !{i32 0, i8 0}
+; CHECK: Range types must match load type!
+; CHECK:  %y = load
+
+define i8 @f7(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !6
+  ret i8 %y
+}
+!6 = metadata !{i8 0, i32 0}
+; CHECK: Range types must match load type!
+; CHECK:  %y = load
+
+define i8 @f8(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !7
+  ret i8 %y
+}
+!7 = metadata !{i32 0, i32 0}
+; CHECK: Range types must match load type!
+; CHECK:  %y = load
+
+define i8 @f9(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !8
+  ret i8 %y
+}
+!8 = metadata !{i8 0, i8 0}
+; CHECK: Range must not be empty!
diff --git a/test/Verifier/range-2.ll b/test/Verifier/range-2.ll
new file mode 100644 (file)
index 0000000..ef542c8
--- /dev/null
@@ -0,0 +1,22 @@
+; RUN: llvm-as < %s -o /dev/null
+
+define i8 @f1(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !0
+  ret i8 %y
+}
+!0 = metadata !{i8 0, i8 1}
+
+define i8 @f2(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !1
+  ret i8 %y
+}
+!1 = metadata !{i8 255, i8 1}
+
+define i8 @f3(i8* %x) {
+entry:
+  %y = load i8* %x, align 1, !range !2
+  ret i8 %y
+}
+!2 = metadata !{i8 1, i8 3, i8 5, i8 42}