Add verification for align, dereferenceable, dereferenceable_or_null load metadata
authorArtur Pilipenko <apilipenko@azulsystems.com>
Fri, 9 Oct 2015 17:41:29 +0000 (17:41 +0000)
committerArtur Pilipenko <apilipenko@azulsystems.com>
Fri, 9 Oct 2015 17:41:29 +0000 (17:41 +0000)
Reviewed By: reames

Differential Revision: http://reviews.llvm.org/D13428

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

lib/IR/Verifier.cpp
test/Verifier/align-md.ll [new file with mode: 0644]
test/Verifier/dereferenceable-md.ll [new file with mode: 0644]

index 0207fe8150bc145866130702327e7197de695e87..8973d0356520cf60e6d42bec8b24e9b6d66062d8 100644 (file)
@@ -306,6 +306,7 @@ private:
   void visitFunction(const Function &F);
   void visitBasicBlock(BasicBlock &BB);
   void visitRangeMetadata(Instruction& I, MDNode* Range, Type* Ty);
+  void visitDereferenceableMetadata(Instruction& I, MDNode* MD);
 
   template <class Ty> bool isValidMetadataArray(const MDTuple &N);
 #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N);
@@ -3072,6 +3073,19 @@ void Verifier::verifyDominatesUse(Instruction &I, unsigned i) {
          "Instruction does not dominate all uses!", Op, &I);
 }
 
+void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) {
+  Assert(I.getType()->isPointerTy(), "dereferenceable, dereferenceable_or_null "
+         "apply only to pointer types", &I);
+  Assert(isa<LoadInst>(I),
+         "dereferenceable, dereferenceable_or_null apply only to load"
+         " instructions, use attributes for calls or invokes", &I);
+  Assert(MD->getNumOperands() == 1, "dereferenceable, dereferenceable_or_null "
+         "take one operand!", &I);
+  ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(MD->getOperand(0));
+  Assert(CI && CI->getType()->isIntegerTy(64), "dereferenceable, "
+         "dereferenceable_or_null metadata value must be an i64!", &I);
+}
+
 /// verifyInstruction - Verify that an instruction is well formed.
 ///
 void Verifier::visitInstruction(Instruction &I) {
@@ -3208,6 +3222,28 @@ void Verifier::visitInstruction(Instruction &I) {
            &I);
   }
 
+  if (MDNode *MD = I.getMetadata(LLVMContext::MD_dereferenceable))
+    visitDereferenceableMetadata(I, MD);
+
+  if (MDNode *MD = I.getMetadata(LLVMContext::MD_dereferenceable_or_null))
+    visitDereferenceableMetadata(I, MD);
+
+  if (MDNode *AlignMD = I.getMetadata(LLVMContext::MD_align)) {
+    Assert(I.getType()->isPointerTy(), "align applies only to pointer types",
+           &I);
+    Assert(isa<LoadInst>(I), "align applies only to load instructions, "
+           "use attributes for calls or invokes", &I);
+    Assert(AlignMD->getNumOperands() == 1, "align takes one operand!", &I);
+    ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(AlignMD->getOperand(0));
+    Assert(CI && CI->getType()->isIntegerTy(64),
+           "align metadata value must be an i64!", &I);
+    uint64_t Align = CI->getZExtValue();
+    Assert(isPowerOf2_64(Align),
+           "align metadata value must be a power of 2!", &I);
+    Assert(Align <= Value::MaximumAlignment,
+           "alignment is larger that implementation defined limit", &I);
+  }
+
   if (MDNode *N = I.getDebugLoc().getAsMDNode()) {
     Assert(isa<DILocation>(N), "invalid !dbg metadata attachment", &I, N);
     visitMDNode(*N);
diff --git a/test/Verifier/align-md.ll b/test/Verifier/align-md.ll
new file mode 100644 (file)
index 0000000..2de489e
--- /dev/null
@@ -0,0 +1,59 @@
+; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
+
+declare i8* @foo()
+
+define void @f1() {
+entry:
+  call i8* @foo(), !align !{i64 2}
+  ret void
+}
+; CHECK: align applies only to load instructions
+; CHECK-NEXT: call i8* @foo()
+
+define i8 @f2(i8* %x) {
+entry:
+  %y = load i8, i8* %x, !align !{i64 2}
+  ret i8 %y
+}
+; CHECK: align applies only to pointer types
+; CHECK-NEXT: load i8, i8* %x
+
+define i8* @f3(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !align !{}
+  ret i8* %y
+}
+; CHECK: align takes one operand
+; CHECK-NEXT: load i8*, i8** %x
+
+define i8* @f4(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !align !{!"str"}
+  ret i8* %y
+}
+; CHECK: align metadata value must be an i64!
+; CHECK-NEXT: load i8*, i8** %x
+
+define i8* @f5(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !align !{i32 2}
+  ret i8* %y
+}
+; CHECK: align metadata value must be an i64!
+; CHECK-NEXT: load i8*, i8** %x
+
+define i8* @f6(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !align !{i64 3}
+  ret i8* %y
+}
+; CHECK: align metadata value must be a power of 2!
+; CHECK-NEXT: load i8*, i8** %x
+
+define i8* @f7(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !align !{i64 1073741824}
+  ret i8* %y
+}
+; CHECK: alignment is larger that implementation defined limit
+; CHECK-NEXT: load i8*, i8** %x
\ No newline at end of file
diff --git a/test/Verifier/dereferenceable-md.ll b/test/Verifier/dereferenceable-md.ll
new file mode 100644 (file)
index 0000000..94c89c3
--- /dev/null
@@ -0,0 +1,86 @@
+; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
+
+declare i8* @foo()
+
+define void @f1() {
+entry:
+  call i8* @foo(), !dereferenceable !{i64 2}
+  ret void
+}
+; CHECK: dereferenceable, dereferenceable_or_null apply only to load instructions, use attributes for calls or invokes
+; CHECK-NEXT: call i8* @foo()
+
+define void @f2() {
+entry:
+  call i8* @foo(), !dereferenceable_or_null !{i64 2}
+  ret void
+}
+; CHECK: dereferenceable, dereferenceable_or_null apply only to load instructions, use attributes for calls or invokes
+; CHECK-NEXT: call i8* @foo()
+
+define i8 @f3(i8* %x) {
+entry:
+  %y = load i8, i8* %x, !dereferenceable !{i64 2}
+  ret i8 %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null apply only to pointer types
+; CHECK-NEXT: load i8, i8* %x
+
+define i8 @f4(i8* %x) {
+entry:
+  %y = load i8, i8* %x, !dereferenceable_or_null !{i64 2}
+  ret i8 %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null apply only to pointer types
+; CHECK-NEXT: load i8, i8* %x
+
+define i8* @f5(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !dereferenceable !{}
+  ret i8* %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null take one operand
+; CHECK-NEXT: load i8*, i8** %x
+
+
+define i8* @f6(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !dereferenceable_or_null !{}
+  ret i8* %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null take one operand
+; CHECK-NEXT: load i8*, i8** %x
+
+define i8* @f7(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !dereferenceable !{!"str"}
+  ret i8* %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64!
+; CHECK-NEXT: load i8*, i8** %x
+
+
+define i8* @f8(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !dereferenceable_or_null !{!"str"}
+  ret i8* %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64!
+; CHECK-NEXT: load i8*, i8** %x
+
+define i8* @f9(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !dereferenceable !{i32 2}
+  ret i8* %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64!
+; CHECK-NEXT: load i8*, i8** %x
+
+
+define i8* @f10(i8** %x) {
+entry:
+  %y = load i8*, i8** %x, !dereferenceable_or_null !{i32 2}
+  ret i8* %y
+}
+; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64!
+; CHECK-NEXT: load i8*, i8** %x
\ No newline at end of file