diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 7e01331b20c57..ef45995339a0d 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -29153,6 +29153,45 @@ attach various forms of information to operands that dominate specific uses. It is not meant for general use, only for building temporary renaming forms that require value splits at certain points. +.. _int_dereferenceable: + +'``llvm.dereferenceable``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare void @llvm.dereferenceable(ptr %p, i64 ) + +Overview: +""""""""" + +The ``llvm.dereferenceable`` allows the optimizer to assume that the returned +pointer is dereferenceable at the point the intrinsic is called. + +Arguments: +"""""""""" + +The arguments of the call are the pointer which will be marked as +dereferenceable and the number of bytes known to be dereferenceable. ```` +must be a constant. + +Semantics: +"""""""""" + +The intrinsic returns the input pointer. The returned pointer is dereferenceable +at the point the intrinsic is called. A pointer that is dereferenceable can be +loaded from speculatively without a risk of trapping. This implies that the +input pointer is not null and neither undef or poison. The number of bytes known +to be dereferenceable is provided as second argument. It is legal for the number +of bytes to be less than the size of the pointee type. + +The semantics above match the semantics of the ``dereferenceable()`` +parameter attribute. + + .. _type.test: '``llvm.type.test``' Intrinsic diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index ee877349a3314..cdf2fb0f74529 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -954,6 +954,10 @@ def int_call_preallocated_teardown : DefaultAttrsIntrinsic<[], [llvm_token_ty]>; def int_callbr_landingpad : Intrinsic<[llvm_any_ty], [LLVMMatchType<0>], [IntrNoMerge]>; +// Attach dereferenceability information to a pointer. +def int_dereferenceable: DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_i64_ty], + [IntrInaccessibleMemOnly, ImmArg>]>; + //===------------------- Standard C Library Intrinsics --------------------===// // diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index f8d7c3ef7bbe7..da975c9a2a61a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -8293,6 +8293,9 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, visitVectorExtractLastActive(I, Intrinsic); return; } + case Intrinsic::dereferenceable: + setValue(&I, getValue(I.getArgOperand(0))); + return; } } diff --git a/llvm/test/CodeGen/AArch64/dereferenceable-intrinsics.ll b/llvm/test/CodeGen/AArch64/dereferenceable-intrinsics.ll new file mode 100644 index 0000000000000..293cd31e3969e --- /dev/null +++ b/llvm/test/CodeGen/AArch64/dereferenceable-intrinsics.ll @@ -0,0 +1,14 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=arm64-apple-macosx -o - %s | FileCheck %s + +declare ptr @llvm.dereferenceable(ptr, i64 immarg) + +define i64 @foo(ptr %a) { +; CHECK-LABEL: foo: +; CHECK: ; %bb.0: +; CHECK-NEXT: ldr x0, [x0] +; CHECK-NEXT: ret + %d = call ptr @llvm.dereferenceable(ptr %a, i64 4) + %l = load i64, ptr %d + ret i64 %l +} diff --git a/llvm/test/Verifier/dereferenceable-intrinsics.ll b/llvm/test/Verifier/dereferenceable-intrinsics.ll new file mode 100644 index 0000000000000..92948daf2c5a4 --- /dev/null +++ b/llvm/test/Verifier/dereferenceable-intrinsics.ll @@ -0,0 +1,11 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s + +declare ptr @llvm.dereferenceable(ptr, i64 immarg) + +define void @transpose(ptr %p, i64 %x) { +; CHECK: immarg operand has non-immediate parameter + %d.0 = call ptr @llvm.dereferenceable(ptr %p, i64 4) + %d.1 = call ptr @llvm.dereferenceable(ptr %p, i64 %x) + ret void +} +