From ef9f5504eaf0c2f8a365c75d9ed7bc6ff363a52e Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Sat, 24 Mar 2012 00:14:51 +0000 Subject: [PATCH] First part of PR12251. Add documentation and verifier support for the range metadata. llvm-svn: 153359 --- llvm/docs/LangRef.html | 34 ++++++++++++++ llvm/include/llvm/LLVMContext.h | 3 +- llvm/lib/VMCore/LLVMContext.cpp | 5 +++ llvm/lib/VMCore/Verifier.cpp | 24 ++++++++++ llvm/test/Verifier/range-1.ll | 78 +++++++++++++++++++++++++++++++++ llvm/test/Verifier/range-2.ll | 22 ++++++++++ 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Verifier/range-1.ll create mode 100644 llvm/test/Verifier/range-2.ll diff --git a/llvm/docs/LangRef.html b/llvm/docs/LangRef.html index 81dabc91af76..cfe489031e0b 100644 --- a/llvm/docs/LangRef.html +++ b/llvm/docs/LangRef.html @@ -104,6 +104,7 @@
  1. 'tbaa' Metadata
  2. 'fpaccuracy' Metadata
  3. +
  4. 'range' Metadata
@@ -3028,6 +3029,39 @@ call void @llvm.dbg.value(metadata !24, i64 0, metadata !25) + +

+ 'range' Metadata +

+ +
+

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

+ + +

Examples:

+
+
+  %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 }
+
+
+
diff --git a/llvm/include/llvm/LLVMContext.h b/llvm/include/llvm/LLVMContext.h index 47d2eaab03a9..18adcd1e3c23 100644 --- a/llvm/include/llvm/LLVMContext.h +++ b/llvm/include/llvm/LLVMContext.h @@ -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. diff --git a/llvm/lib/VMCore/LLVMContext.cpp b/llvm/lib/VMCore/LLVMContext.cpp index d77e996b5e45..68c56212bc6c 100644 --- a/llvm/lib/VMCore/LLVMContext.cpp +++ b/llvm/lib/VMCore/LLVMContext.cpp @@ -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; } diff --git a/llvm/lib/VMCore/Verifier.cpp b/llvm/lib/VMCore/Verifier.cpp index 5b9b2a5258c6..f62441bea7aa 100644 --- a/llvm/lib/VMCore/Verifier.cpp +++ b/llvm/lib/VMCore/Verifier.cpp @@ -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(Range->getOperand(2*i)); + Assert1(Low, "The lower limit must be an integer!", Low); + ConstantInt *High = dyn_cast(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(I), "Ranges are only for loads!", &I); + InstsInThisBlock.insert(&I); } diff --git a/llvm/test/Verifier/range-1.ll b/llvm/test/Verifier/range-1.ll new file mode 100644 index 000000000000..611933a1ec30 --- /dev/null +++ b/llvm/test/Verifier/range-1.ll @@ -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/llvm/test/Verifier/range-2.ll b/llvm/test/Verifier/range-2.ll new file mode 100644 index 000000000000..ef542c8c9380 --- /dev/null +++ b/llvm/test/Verifier/range-2.ll @@ -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}