From: Ryan Taylor Date: Tue, 23 Jul 2019 17:19:56 +0000 (+0000) Subject: [IR][Verifier] Allow IntToPtrInst to be !dereferenceable X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6f13637a3e130980456f37647f7628aa7fa7a2b6;p=platform%2Fupstream%2Fllvm.git [IR][Verifier] Allow IntToPtrInst to be !dereferenceable Summary: Allow IntToPtrInst to carry !dereferenceable metadata tag. This is valid since !dereferenceable can be only be applied to pointer type values. Change-Id: If8a6e3c616f073d51eaff52ab74535c29ed497b4 Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D64954 llvm-svn: 366826 --- diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 87e8a55..f3b2802 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -5303,6 +5303,29 @@ optimizations related to compare and branch instructions. The metadata is treated as a boolean value; if it exists, it signals that the branch or switch that it is attached to is completely unpredictable. +.. _md_dereferenceable: + +'``dereferenceable``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The existence of the ``!dereferenceable`` metadata on the instruction +tells the optimizer that the value loaded is known to be dereferenceable. +The number of bytes known to be dereferenceable is specified by the integer +value in the metadata node. This is analogous to the ''dereferenceable'' +attribute on parameters and return values. + +.. _md_dereferenceable_or_null: + +'``dereferenceable_or_null``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The existence of the ``!dereferenceable_or_null`` metadata on the +instruction tells the optimizer that the value loaded is known to be either +dereferenceable or null. +The number of bytes known to be dereferenceable is specified by the integer +value in the metadata node. This is analogous to the ''dereferenceable_or_null'' +attribute on parameters and return values. + .. _llvm.loop: '``llvm.loop``' @@ -5807,6 +5830,8 @@ the irreducible loop) of 100: Irreducible loop header weights are typically based on profile data. +.. _md_invariant.group: + '``invariant.group``' Metadata ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8602,7 +8627,7 @@ otherwise, the behavior is undefined. The optional ``!invariant.group`` metadata must reference a single metadata name ```` corresponding to a metadata node with no entries. - See ``invariant.group`` metadata. + See ``invariant.group`` metadata :ref:`invariant.group ` The optional ``!nonnull`` metadata must reference a single metadata name ```` corresponding to a metadata node with no @@ -8614,22 +8639,14 @@ values. This metadata can only be applied to loads of a pointer type. The optional ``!dereferenceable`` metadata must reference a single metadata name ```` corresponding to a metadata node with one ``i64`` -entry. The existence of the ``!dereferenceable`` metadata on the instruction -tells the optimizer that the value loaded is known to be dereferenceable. -The number of bytes known to be dereferenceable is specified by the integer -value in the metadata node. This is analogous to the ''dereferenceable'' -attribute on parameters and return values. This metadata can only be applied -to loads of a pointer type. +entry. +See ``dereferenceable`` metadata :ref:`dereferenceable ` The optional ``!dereferenceable_or_null`` metadata must reference a single metadata name ```` corresponding to a metadata node with one -``i64`` entry. The existence of the ``!dereferenceable_or_null`` metadata on the -instruction tells the optimizer that the value loaded is known to be either -dereferenceable or null. -The number of bytes known to be dereferenceable is specified by the integer -value in the metadata node. This is analogous to the ''dereferenceable_or_null'' -attribute on parameters and return values. This metadata can only be applied -to loads of a pointer type. +``i64`` entry. +See ``dereferenceable_or_null`` metadata :ref:`dereferenceable_or_null +` The optional ``!align`` metadata must reference a single metadata name ```` corresponding to a metadata node with one ``i64`` entry. @@ -9626,7 +9643,7 @@ Syntax: :: - = inttoptr to ; yields ty2 + = inttoptr to [, !dereferenceable !][, !dereferenceable_or_null !` value to cast, and a type to cast it to, which must be a :ref:`pointer ` type. +The optional ``!dereferenceable`` metadata must reference a single metadata +name ```` corresponding to a metadata node with one ``i64`` +entry. +See ``dereferenceable`` metadata. + +The optional ``!dereferenceable_or_null`` metadata must reference a single +metadata name ```` corresponding to a metadata node with one +``i64`` entry. +See ``dereferenceable_or_null`` metadata. + Semantics: """""""""" diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index b7f77dc..6a743b7 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -650,6 +650,19 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, } CanBeNull = true; } + } else if (auto *IP = dyn_cast(this)) { + if (MDNode *MD = IP->getMetadata(LLVMContext::MD_dereferenceable)) { + ConstantInt *CI = mdconst::extract(MD->getOperand(0)); + DerefBytes = CI->getLimitedValue(); + } + if (DerefBytes == 0) { + if (MDNode *MD = + IP->getMetadata(LLVMContext::MD_dereferenceable_or_null)) { + ConstantInt *CI = mdconst::extract(MD->getOperand(0)); + DerefBytes = CI->getLimitedValue(); + } + CanBeNull = true; + } } else if (auto *AI = dyn_cast(this)) { if (!AI->isArrayAllocation()) { DerefBytes = DL.getTypeStoreSize(AI->getAllocatedType()); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 9346c8b..1793ba4 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3983,9 +3983,9 @@ void Verifier::verifyDominatesUse(Instruction &I, unsigned i) { void Verifier::visitDereferenceableMetadata(Instruction& I, MDNode* MD) { Assert(I.getType()->isPointerTy(), "dereferenceable, dereferenceable_or_null " "apply only to pointer types", &I); - Assert(isa(I), + Assert((isa(I) || isa(I)), "dereferenceable, dereferenceable_or_null apply only to load" - " instructions, use attributes for calls or invokes", &I); + " and inttoptr 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(MD->getOperand(0)); diff --git a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll index 2e9453f..80bc72d 100644 --- a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll +++ b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll @@ -172,6 +172,14 @@ entry: ret void } +; CHECK: The following are dereferenceable: +; CHECK: %ptr = inttoptr i32 %val to i32*, !dereferenceable !0 +define i32 @f_0(i32 %val) { + %ptr = inttoptr i32 %val to i32*, !dereferenceable !0 + %load29 = load i32, i32* %ptr, align 8 + ret i32 %load29 +} + ; Just check that we don't crash. ; CHECK-LABEL: 'opaque_type_crasher' define void @opaque_type_crasher(%TypeOpaque* dereferenceable(16) %a) { diff --git a/llvm/test/Verifier/dereferenceable-md-inttoptr.ll b/llvm/test/Verifier/dereferenceable-md-inttoptr.ll new file mode 100644 index 0000000..8c3c57e --- /dev/null +++ b/llvm/test/Verifier/dereferenceable-md-inttoptr.ll @@ -0,0 +1,6 @@ +; RUN: llvm-as < %s -o /dev/null + +define i8* @f_0(i8 %val) { + %ptr = inttoptr i8 %val to i8*, !dereferenceable_or_null !{i64 2} + ret i8* %ptr +} diff --git a/llvm/test/Verifier/dereferenceable-md.ll b/llvm/test/Verifier/dereferenceable-md.ll index 94c89c3..d1b38ab 100644 --- a/llvm/test/Verifier/dereferenceable-md.ll +++ b/llvm/test/Verifier/dereferenceable-md.ll @@ -7,7 +7,7 @@ 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: dereferenceable, dereferenceable_or_null apply only to load and inttoptr instructions, use attributes for calls or invokes ; CHECK-NEXT: call i8* @foo() define void @f2() { @@ -15,7 +15,7 @@ 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: dereferenceable, dereferenceable_or_null apply only to load and inttoptr instructions, use attributes for calls or invokes ; CHECK-NEXT: call i8* @foo() define i8 @f3(i8* %x) { @@ -83,4 +83,46 @@ entry: 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 +; CHECK-NEXT: load i8*, i8** %x + +define i8* @f_11(i8 %val) { + %ptr = inttoptr i8 %val to i8*, !dereferenceable !{i32 2} + ret i8* %ptr +} +; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64! +; CHECK-NEXT: %ptr = inttoptr i8 %val to i8*, !dereferenceable !3 + +define i8* @f_12(i8 %val) { + %ptr = inttoptr i8 %val to i8*, !dereferenceable_or_null !{i32 2} + ret i8* %ptr +} +; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64! +; CHECK-NEXT: %ptr = inttoptr i8 %val to i8*, !dereferenceable_or_null !3 + +define i8* @f_13(i8 %val) { + %ptr = inttoptr i8 %val to i8*, !dereferenceable !{} + ret i8* %ptr +} +; CHECK: dereferenceable, dereferenceable_or_null take one operand +; CHECK-NEXT: %ptr = inttoptr i8 %val to i8*, !dereferenceable !1 + +define i8* @f_14(i8 %val) { + %ptr = inttoptr i8 %val to i8*, !dereferenceable_or_null !{} + ret i8* %ptr +} +; CHECK: dereferenceable, dereferenceable_or_null take one operand +; CHECK-NEXT: %ptr = inttoptr i8 %val to i8*, !dereferenceable_or_null !1 + +define i8* @f_15(i8 %val) { + %ptr = inttoptr i8 %val to i8*, !dereferenceable !{!"str"} + ret i8* %ptr +} +; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64! +; CHECK-NEXT: %ptr = inttoptr i8 %val to i8*, !dereferenceable !2 + +define i8* @f_16(i8 %val) { + %ptr = inttoptr i8 %val to i8*, !dereferenceable_or_null !{!"str"} + ret i8* %ptr +} +; CHECK: dereferenceable, dereferenceable_or_null metadata value must be an i64! +; CHECK-NEXT: %ptr = inttoptr i8 %val to i8*, !dereferenceable_or_null !2