Skip to content

Commit 4b45084

Browse files
authored
[SPIR-V 1.4] Support OpPtrEqual, OpPtrNotEqual and OpPtrDiff to compare pointers (#2482)
This addresses p.2 and p.3 of #2460
1 parent 8518a6f commit 4b45084

File tree

6 files changed

+155
-0
lines changed

6 files changed

+155
-0
lines changed

lib/SPIRV/SPIRVReader.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -2164,6 +2164,28 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
21642164
return mapValue(BV, V);
21652165
}
21662166

2167+
case OpPtrEqual:
2168+
case OpPtrNotEqual: {
2169+
auto *BC = static_cast<SPIRVBinary *>(BV);
2170+
auto Ops = transValue(BC->getOperands(), F, BB);
2171+
2172+
IRBuilder<> Builder(BB);
2173+
Value *Op1 = Builder.CreatePtrToInt(Ops[0], Type::getInt64Ty(*Context));
2174+
Value *Op2 = Builder.CreatePtrToInt(Ops[1], Type::getInt64Ty(*Context));
2175+
CmpInst::Predicate P =
2176+
OC == OpPtrEqual ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE;
2177+
Value *V = Builder.CreateICmp(P, Op1, Op2);
2178+
return mapValue(BV, V);
2179+
}
2180+
2181+
case OpPtrDiff: {
2182+
auto *BC = static_cast<SPIRVBinary *>(BV);
2183+
auto Ops = transValue(BC->getOperands(), F, BB);
2184+
IRBuilder<> Builder(BB);
2185+
Value *V = Builder.CreatePtrDiff(transType(BC->getType()), Ops[0], Ops[1]);
2186+
return mapValue(BV, V);
2187+
}
2188+
21672189
case OpCompositeConstruct: {
21682190
auto *CC = static_cast<SPIRVCompositeConstruct *>(BV);
21692191
auto Constituents = transValue(CC->getOperands(), F, BB);

lib/SPIRV/libSPIRV/SPIRVInstruction.h

+14
Original file line numberDiff line numberDiff line change
@@ -681,10 +681,21 @@ class SPIRVBinary : public SPIRVInstTemplateBase {
681681
"Invalid type for bitwise instruction");
682682
assert((Op1Ty->getIntegerBitWidth() == Op2Ty->getIntegerBitWidth()) &&
683683
"Inconsistent BitWidth");
684+
} else if (isBinaryPtrOpCode(OpCode)) {
685+
assert((Op1Ty->isTypePointer() && Op2Ty->isTypePointer()) &&
686+
"Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction");
687+
assert(static_cast<SPIRVTypePointer *>(Op1Ty)->getElementType() ==
688+
static_cast<SPIRVTypePointer *>(Op2Ty)->getElementType() &&
689+
"Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction");
684690
} else {
685691
assert(0 && "Invalid op code!");
686692
}
687693
}
694+
VersionNumber getRequiredSPIRVVersion() const override {
695+
if (isBinaryPtrOpCode(OpCode))
696+
return VersionNumber::SPIRV_1_4;
697+
return VersionNumber::SPIRV_1_0;
698+
}
688699
};
689700

690701
template <Op OC>
@@ -719,6 +730,9 @@ _SPIRV_OP(BitwiseAnd)
719730
_SPIRV_OP(BitwiseOr)
720731
_SPIRV_OP(BitwiseXor)
721732
_SPIRV_OP(Dot)
733+
_SPIRV_OP(PtrEqual)
734+
_SPIRV_OP(PtrNotEqual)
735+
_SPIRV_OP(PtrDiff)
722736
#undef _SPIRV_OP
723737

724738
template <Op TheOpCode> class SPIRVInstNoOperand : public SPIRVInstruction {

lib/SPIRV/libSPIRV/SPIRVOpCode.h

+4
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ inline bool isBinaryOpCode(Op OpCode) {
7474
OpCode == OpDot || OpCode == OpIAddCarry || OpCode == OpISubBorrow;
7575
}
7676

77+
inline bool isBinaryPtrOpCode(Op OpCode) {
78+
return (unsigned)OpCode >= OpPtrEqual && (unsigned)OpCode <= OpPtrDiff;
79+
}
80+
7781
inline bool isShiftOpCode(Op OpCode) {
7882
return (unsigned)OpCode >= OpShiftRightLogical &&
7983
(unsigned)OpCode <= OpShiftLeftLogical;

lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h

+3
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@ _SPIRV_OP(GroupNonUniformBitwiseXor, 361)
329329
_SPIRV_OP(GroupNonUniformLogicalAnd, 362)
330330
_SPIRV_OP(GroupNonUniformLogicalOr, 363)
331331
_SPIRV_OP(GroupNonUniformLogicalXor, 364)
332+
_SPIRV_OP(PtrEqual, 401)
333+
_SPIRV_OP(PtrNotEqual, 402)
334+
_SPIRV_OP(PtrDiff, 403)
332335
_SPIRV_OP(CopyLogical, 400)
333336
_SPIRV_OP(GroupNonUniformRotateKHR, 4431)
334337
_SPIRV_OP(SDotKHR, 4450)

test/transcoding/ptr_diff.ll

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
; Check support of OpPtrDiff instruction that was added in SPIR-V 1.4
2+
3+
; RUN: llvm-as %s -o %t.bc
4+
; RUN: not llvm-spirv --spirv-max-version=1.3 %t.bc 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
5+
6+
; RUN: llvm-spirv %t.bc -o %t.spv
7+
; RUN: llvm-spirv %t.spv -to-text -o %t.spt
8+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
9+
; RUN: spirv-val %t.spv
10+
11+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
12+
; RUN: llvm-dis %t.rev.bc
13+
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM
14+
15+
; CHECK-ERROR: RequiresVersion: Cannot fulfill SPIR-V version restriction:
16+
; CHECK-ERROR-NEXT: SPIR-V version was restricted to at most 1.3 (66304) but a construct from the input requires SPIR-V version 1.4 (66560) or above
17+
18+
; SPIR-V 1.4
19+
; CHECK-SPIRV: 66560
20+
; CHECK-SPIRV: TypeInt [[#TypeInt:]] 32 0
21+
; CHECK-SPIRV: TypeFloat [[#TypeFloat:]] 32
22+
; CHECK-SPIRV: TypePointer [[#TypePointer:]] [[#]] [[#TypeFloat]]
23+
24+
; CHECK-SPIRV: Variable [[#TypePointer]] [[#Var:]]
25+
; CHECK-SPIRV: PtrDiff [[#TypeInt]] [[#]] [[#Var]] [[#Var]]
26+
27+
target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
28+
target triple = "spir64-unknown-unknown"
29+
30+
; Function Attrs: nounwind
31+
define spir_kernel void @test(float %a) local_unnamed_addr #0 {
32+
entry:
33+
%0 = alloca float, align 4
34+
store float %a, ptr %0, align 4
35+
; CHECK-LLVM: %[[#Arg1:]] = ptrtoint ptr %[[#]] to i64
36+
; CHECK-LLVM: %[[#Arg2:]] = ptrtoint ptr %[[#]] to i64
37+
; CHECK-LLVM: %[[#Sub:]] = sub i64 %[[#Arg1]], %[[#Arg2]]
38+
; CHECK-LLVM: sdiv exact i64 %[[#Sub]], ptrtoint (ptr getelementptr (i32, ptr null, i32 1) to i64)
39+
%1 = call spir_func noundef i32 @_Z15__spirv_PtrDiff(ptr %0, ptr %0)
40+
ret void
41+
}
42+
43+
declare spir_func noundef i32 @_Z15__spirv_PtrDiff(ptr, ptr)
44+
45+
attributes #0 = { convergent nounwind writeonly }
46+
47+
!llvm.module.flags = !{!0}
48+
!opencl.ocl.version = !{!1}
49+
!opencl.spir.version = !{!1}
50+
51+
!0 = !{i32 1, !"wchar_size", i32 4}
52+
!1 = !{i32 2, i32 0}

test/transcoding/ptr_not_equal.ll

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
; Check support of OpPtrEqual and OpPtrNotEqual instructions that were added in SPIR-V 1.4
2+
3+
; RUN: llvm-as %s -o %t.bc
4+
; RUN: not llvm-spirv --spirv-max-version=1.3 %t.bc 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
5+
6+
; RUN: llvm-spirv %t.bc -o %t.spv
7+
; RUN: llvm-spirv %t.spv -to-text -o %t.spt
8+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
9+
; RUN: spirv-val %t.spv
10+
11+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
12+
; RUN: llvm-dis %t.rev.bc
13+
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM
14+
15+
; CHECK-ERROR: RequiresVersion: Cannot fulfill SPIR-V version restriction:
16+
; CHECK-ERROR-NEXT: SPIR-V version was restricted to at most 1.3 (66304) but a construct from the input requires SPIR-V version 1.4 (66560) or above
17+
18+
; SPIR-V 1.4
19+
; CHECK-SPIRV: 66560
20+
; CHECK-SPIRV: TypeFloat [[#TypeFloat:]] 32
21+
; CHECK-SPIRV: TypePointer [[#TypePointer:]] [[#]] [[#TypeFloat]]
22+
; CHECK-SPIRV: TypeBool [[#TypeBool:]]
23+
24+
; CHECK-SPIRV: Variable [[#TypePointer]] [[#Var1:]]
25+
; CHECK-SPIRV: Variable [[#TypePointer]] [[#Var2:]]
26+
; CHECK-SPIRV: PtrEqual [[#TypeBool]] [[#]] [[#Var1]] [[#Var2]]
27+
; CHECK-SPIRV: PtrNotEqual [[#TypeBool]] [[#]] [[#Var1]] [[#Var2]]
28+
29+
target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
30+
target triple = "spir64-unknown-unknown"
31+
32+
; Function Attrs: nounwind
33+
define spir_kernel void @test(float %a, float %b) local_unnamed_addr #0 {
34+
entry:
35+
%0 = alloca float, align 4
36+
%1 = alloca float, align 4
37+
store float %a, ptr %0, align 4
38+
store float %b, ptr %1, align 4
39+
; CHECK-LLVM: %[[#Arg1:]] = ptrtoint ptr %[[#]] to i64
40+
; CHECK-LLVM: %[[#Arg2:]] = ptrtoint ptr %[[#]] to i64
41+
; CHECK-LLVM: icmp eq i64 %[[#Arg1]], %[[#Arg2]]
42+
%2 = call spir_func noundef i1 @_Z16__spirv_PtrEqual(ptr %0, ptr %1)
43+
; CHECK-LLVM: %[[#Arg3:]] = ptrtoint ptr %[[#]] to i64
44+
; CHECK-LLVM: %[[#Arg4:]] = ptrtoint ptr %[[#]] to i64
45+
; CHECK-LLVM: icmp ne i64 %[[#Arg3]], %[[#Arg4]]
46+
%3 = call spir_func noundef i1 @_Z19__spirv_PtrNotEqual(ptr %0, ptr %1)
47+
ret void
48+
}
49+
50+
declare spir_func noundef i1 @_Z16__spirv_PtrEqual(ptr, ptr)
51+
declare spir_func noundef i1 @_Z19__spirv_PtrNotEqual(ptr, ptr)
52+
53+
attributes #0 = { convergent nounwind writeonly }
54+
55+
!llvm.module.flags = !{!0}
56+
!opencl.ocl.version = !{!1}
57+
!opencl.spir.version = !{!1}
58+
59+
!0 = !{i32 1, !"wchar_size", i32 4}
60+
!1 = !{i32 2, i32 0}

0 commit comments

Comments
 (0)