Skip to content

Commit 47b7f33

Browse files
authored
[IR] Allow llvm.ptrmask of vectors (#67434)
llvm.ptrmask is currently limited to pointers only, and does not accept vectors of pointers. This is an unnecessary limitation, especially as the underlying instructions (getelementptr etc) do support vectors of pointers. We should relax this sooner rather than later, to avoid introducing code that assumes non-vectors (#67166).
1 parent cf7eac9 commit 47b7f33

File tree

6 files changed

+86
-3
lines changed

6 files changed

+86
-3
lines changed

llvm/docs/LangRef.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26865,7 +26865,8 @@ Syntax:
2686526865
Arguments:
2686626866
""""""""""
2686726867

26868-
The first argument is a pointer. The second argument is an integer.
26868+
The first argument is a pointer or vector of pointers. The second argument is
26869+
an integer or vector of integers.
2686926870

2687026871
Overview:
2687126872
""""""""""
@@ -26880,7 +26881,7 @@ Semantics:
2688026881

2688126882
The result of ``ptrmask(ptr, mask)`` is equivalent to
2688226883
``getelementptr ptr, (ptrtoint(ptr) & mask) - ptrtoint(ptr)``. Both the returned
26883-
pointer and the first argument are based on the same underlying object (for more
26884+
pointer(s) and the first argument are based on the same underlying object (for more
2688426885
information on the *based on* terminology see
2688526886
:ref:`the pointer aliasing rules <pointeraliasing>`). If the bitwidth of the
2688626887
mask argument does not match the pointer size of the target, the mask is

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1743,7 +1743,9 @@ def int_is_constant : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty],
17431743
"llvm.is.constant">;
17441744

17451745
// Intrinsic to mask out bits of a pointer.
1746-
def int_ptrmask: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_anyint_ty],
1746+
// First argument must be pointer or vector of pointer. This is checked by the
1747+
// verifier.
1748+
def int_ptrmask: DefaultAttrsIntrinsic<[llvm_any_ty], [LLVMMatchType<0>, llvm_anyint_ty],
17471749
[IntrNoMem, IntrSpeculatable, IntrWillReturn]>;
17481750

17491751
// Intrinsic to wrap a thread local variable.

llvm/lib/IR/Verifier.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5947,6 +5947,25 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
59475947
break;
59485948
case Intrinsic::experimental_convergence_loop:
59495949
break;
5950+
case Intrinsic::ptrmask: {
5951+
Type *Ty0 = Call.getArgOperand(0)->getType();
5952+
Type *Ty1 = Call.getArgOperand(1)->getType();
5953+
Check(Ty0->isPtrOrPtrVectorTy(),
5954+
"llvm.ptrmask intrinsic first argument must be pointer or vector "
5955+
"of pointers",
5956+
&Call);
5957+
Check(
5958+
Ty0->isVectorTy() == Ty1->isVectorTy(),
5959+
"llvm.ptrmask intrinsic arguments must be both scalars or both vectors",
5960+
&Call);
5961+
if (Ty0->isVectorTy())
5962+
Check(cast<VectorType>(Ty0)->getElementCount() ==
5963+
cast<VectorType>(Ty1)->getElementCount(),
5964+
"llvm.ptrmask intrinsic arguments must have the same number of "
5965+
"elements",
5966+
&Call);
5967+
break;
5968+
}
59505969
};
59515970

59525971
// Verify that there aren't any unmediated control transfers between funclets.

llvm/test/CodeGen/X86/lower-ptrmask.ll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,16 @@ define ptr @test2(ptr %src) {
2929
%ptr = call ptr @llvm.ptrmask.p0.i32(ptr %src, i32 10000)
3030
ret ptr %ptr
3131
}
32+
33+
declare <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr>, <2 x i64>)
34+
35+
; CHECK-LABEL: name: test3
36+
; CHECK: %0:vr128 = COPY $xmm0
37+
; CHECK-NEXT: %1:vr128 = PANDrm %0, $rip, 1, $noreg, %const.0, $noreg :: (load (s128) from constant-pool)
38+
; CHECK-NEXT: $xmm0 = COPY %1
39+
; CHECK-NEXT: RET 0, $xmm0
40+
41+
define <2 x ptr> @test3(<2 x ptr> %src) {
42+
%ptr = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %src, <2 x i64> <i64 10000, i64 10000>)
43+
ret <2 x ptr> %ptr
44+
}

llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
55
declare ptr @llvm.ptrmask.p0.i32(ptr, i32)
6+
declare <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr>, <2 x i64>)
67
declare void @use.ptr(ptr)
8+
79
define ptr @fold_2x(ptr %p, i64 %m0, i64 %m1) {
810
; CHECK-LABEL: define ptr @fold_2x
911
; CHECK-SAME: (ptr [[P:%.*]], i64 [[M0:%.*]], i64 [[M1:%.*]]) {
@@ -65,3 +67,15 @@ define ptr @fold_2x_fail_type_mismatch2(ptr %p, i64 %m0, i32 %m1) {
6567
%p1 = call ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 %m1)
6668
ret ptr %p1
6769
}
70+
71+
define <2 x ptr> @fold_2x_vec(<2 x ptr> %p, <2 x i64> %m0, <2 x i64> %m1) {
72+
; CHECK-LABEL: define <2 x ptr> @fold_2x_vec
73+
; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M0:%.*]], <2 x i64> [[M1:%.*]]) {
74+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i64> [[M1]], [[M0]]
75+
; CHECK-NEXT: [[P1:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[TMP1]])
76+
; CHECK-NEXT: ret <2 x ptr> [[P1]]
77+
;
78+
%p0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m0)
79+
%p1 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p0, <2 x i64> %m1)
80+
ret <2 x ptr> %p1
81+
}

llvm/test/Verifier/ptrmask.ll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
2+
3+
declare float @llvm.ptrmask.f32.i64(float, i64)
4+
declare ptr @llvm.ptrmask.p0.v4i64(ptr, <4 x i64>)
5+
declare <2 x ptr> @llvm.ptrmask.v2p0.i64(<2 x ptr>, i64)
6+
declare <2 x ptr> @llvm.ptrmask.v2p0.v4i64(<2 x ptr>, <4 x i64>)
7+
8+
; CHECK: llvm.ptrmask intrinsic first argument must be pointer or vector of pointers
9+
; CHECK-NEXT: %1 = call float @llvm.ptrmask.f32.i64(float 0.000000e+00, i64 0)
10+
define void @not_ptr() {
11+
call float @llvm.ptrmask.f32.i64(float 0.0, i64 0)
12+
ret void
13+
}
14+
15+
; CHECK: llvm.ptrmask intrinsic arguments must be both scalars or both vectors
16+
; CHECK: %1 = call ptr @llvm.ptrmask.p0.v4i64(ptr null, <4 x i64> zeroinitializer)
17+
define void @scalar_vector_mismatch_1() {
18+
call ptr @llvm.ptrmask.p0.v4i64(ptr null, <4 x i64> zeroinitializer)
19+
ret void
20+
}
21+
22+
; CHECK: llvm.ptrmask intrinsic arguments must be both scalars or both vectors
23+
; CHECK: %1 = call <2 x ptr> @llvm.ptrmask.v2p0.i64(<2 x ptr> zeroinitializer, i64 0)
24+
define void @scalar_vector_mismatch_2() {
25+
call <2 x ptr> @llvm.ptrmask.v2p0.i64(<2 x ptr> zeroinitializer, i64 0)
26+
ret void
27+
}
28+
29+
; CHECK: llvm.ptrmask intrinsic arguments must have the same number of elements
30+
; CHECK: %1 = call <2 x ptr> @llvm.ptrmask.v2p0.v4i64(<2 x ptr> zeroinitializer, <4 x i64> zeroinitializer)
31+
define void @vector_size_mismatch() {
32+
call <2 x ptr> @llvm.ptrmask.v2p0.v4i64(<2 x ptr> zeroinitializer, <4 x i64> zeroinitializer)
33+
ret void
34+
}

0 commit comments

Comments
 (0)