This patch adds a ptrmask intrinsic which allows masking out bits of a
pointer that must be zero when accessing it, because of ABI alignment
requirements or a restriction of the meaningful bits of a pointer
through the data layout.
This avoids doing a ptrtoint/inttoptr round trip in some cases (e.g. tagged
pointers) and allows us to not lose information about the underlying
object.
Reviewers: nlopes, efriedma, hfinkel, sanjoy, jdoerfert, aqjune
Reviewed by: sanjoy, jdoerfert
Differential Revision: https://reviews.llvm.org/D59065
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@368986
91177308-0d34-0410-b5e6-
96231b3b80d8
On the other hand, if constant folding is not run, it will never
evaluate to true, even in simple cases.
+.. _int_ptrmask:
+
+'``llvm.ptrmask``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+ declare ptrty llvm.ptrmask(ptrty %ptr, intty %mask) readnone speculatable
+
+Arguments:
+""""""""""
+
+The first argument is a pointer. The second argument is an integer.
+
+Overview:
+""""""""""
+
+The ``llvm.ptrmask`` intrinsic masks out bits of the pointer according to a mask.
+This allows stripping data from tagged pointers without converting them to an
+integer (ptrtoint/inttoptr). As a consequence, we can preserve more information
+to facilitate alias analysis and underlying-object detection.
+
+Semantics:
+""""""""""
+
+The result of ``ptrmask(ptr, mask)`` is equivalent to
+``getelementptr ptr, (ptrtoint(ptr) & mask) - ptrtoint(ptr)``. Both the returned
+pointer and the first argument are based on the same underlying object (for more
+information on the *based on* terminology see
+:ref:`the pointer aliasing rules <pointeraliasing>`). If the bitwidth of the
+mask argument does not match the pointer size of the target, the mask is
+zero-extended or truncated accordingly.
+
Stack Map Intrinsics
--------------------
// Intrinsic to detect whether its argument is a constant.
def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem, IntrWillReturn], "llvm.is.constant">;
+// Intrinsic to mask out bits of a pointer.
+def int_ptrmask: Intrinsic<[llvm_anyptr_ty], [llvm_anyptr_ty, llvm_anyint_ty],
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
+
//===-------------------------- Masked Intrinsics -------------------------===//
//
def int_masked_store : Intrinsic<[], [llvm_anyvector_ty,
setValue(&I, Val);
return;
}
+ case Intrinsic::ptrmask: {
+ SDValue Ptr = getValue(I.getOperand(0));
+ SDValue Const = getValue(I.getOperand(1));
+
+ EVT DestVT =
+ EVT(DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()));
+
+ setValue(&I, DAG.getNode(ISD::AND, getCurSDLoc(), DestVT, Ptr,
+ DAG.getZExtOrTrunc(Const, getCurSDLoc(), DestVT)));
+ return;
+ }
}
}
--- /dev/null
+; RUN: llc -mtriple=arm64-apple-iphoneos -stop-after=finalize-isel %s -o - | FileCheck %s
+
+declare i8* @llvm.ptrmask.p0i8.i64(i8* , i64)
+
+; CHECK-LABEL: name: test1
+; CHECK: %0:gpr64 = COPY $x0
+; CHECK-NEXT: %1:gpr64sp = ANDXri %0, 8052
+; CHECK-NEXT: $x0 = COPY %1
+; CHECK-NEXT: RET_ReallyLR implicit $x0
+
+define i8* @test1(i8* %src) {
+ %ptr = call i8* @llvm.ptrmask.p0i8.i64(i8* %src, i64 72057594037927928)
+ ret i8* %ptr
+}
+
+declare i8* @llvm.ptrmask.p0i8.i32(i8*, i32)
+
+; CHECK-LABEL: name: test2
+; CHECK: %0:gpr64 = COPY $x0
+; CHECK-NEXT: %1:gpr32 = MOVi32imm 10000
+; CHECK-NEXT: %2:gpr64 = SUBREG_TO_REG 0, killed %1, %subreg.sub_32
+; CHECK-NEXT: %3:gpr64 = ANDXrr %0, killed %2
+; CHECK-NEXT: $x0 = COPY %3
+; CHECK-NEXT: RET_ReallyLR implicit $x0
+
+define i8* @test2(i8* %src) {
+ %ptr = call i8* @llvm.ptrmask.p0i8.i32(i8* %src, i32 10000)
+ ret i8* %ptr
+}
--- /dev/null
+; RUN: llc -mtriple=x86_64-apple-macosx -stop-after=finalize-isel %s -o - | FileCheck %s
+
+declare i8* @llvm.ptrmask.p0i8.i64(i8* , i64)
+
+; CHECK-LABEL: name: test1
+; CHECK: %0:gr64 = COPY $rdi
+; CHECK-NEXT: %1:gr64 = MOV64ri 72057594037927928
+; CHECK-NEXT: %2:gr64 = AND64rr %0, killed %1, implicit-def dead $eflags
+; CHECK-NEXT: $rax = COPY %2
+; CHECK-NEXT: RET 0, $rax
+
+define i8* @test1(i8* %src) {
+ %ptr = call i8* @llvm.ptrmask.p0i8.i64(i8* %src, i64 72057594037927928)
+ ret i8* %ptr
+}
+
+declare i8* @llvm.ptrmask.p0i8.i32(i8*, i32)
+
+; CHECK-LABEL: name: test2
+; CHECK: %0:gr64 = COPY $rdi
+; CHECK-NEXT: %1:gr32 = COPY %0.sub_32bit
+; CHECK-NEXT: %2:gr32 = AND32ri %1, 10000, implicit-def dead $eflags
+; CHECK-NEXT: %3:gr64 = SUBREG_TO_REG 0, killed %2, %subreg.sub_32bit
+; CHECK-NEXT: $rax = COPY %3
+; CHECK-NEXT: RET 0, $rax
+
+
+define i8* @test2(i8* %src) {
+ %ptr = call i8* @llvm.ptrmask.p0i8.i32(i8* %src, i32 10000)
+ ret i8* %ptr
+}