Skip to content

Commit d54b2ce

Browse files
bwlodarczMrSidims
authored andcommitted
Add support for ISubBorrow SPIRV instruction (#2168)
This commit implements bidirectional translation of the llvm.usub.with.overflow and the ISubBorrow intrinsic. Intrinsic llvm.usub.with.overflow returns struct which second element have a type of i1. The llvm type i1 is, in llvm-spirv, directly translated to BoolType. SPIRV specification requires that the composite which returns from ISubBorrow needs to have both elements of the same type. In result, current implementation is not compliant and should be considered temporary.
1 parent 8c72a01 commit d54b2ce

File tree

6 files changed

+75
-3
lines changed

6 files changed

+75
-3
lines changed

lib/SPIRV/SPIRVReader.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2469,13 +2469,21 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
24692469
return mapValue(BV,
24702470
transRelational(static_cast<SPIRVInstruction *>(BV), BB));
24712471
case OpIAddCarry: {
2472-
IRBuilder Builder(BB);
2472+
IRBuilder<> Builder(BB);
24732473
auto *BC = static_cast<SPIRVBinary *>(BV);
24742474
return mapValue(BV, Builder.CreateBinaryIntrinsic(
24752475
Intrinsic::uadd_with_overflow,
24762476
transValue(BC->getOperand(0), F, BB),
24772477
transValue(BC->getOperand(1), F, BB)));
24782478
}
2479+
case OpISubBorrow: {
2480+
IRBuilder<> Builder(BB);
2481+
auto *BC = static_cast<SPIRVBinary *>(BV);
2482+
return mapValue(BV, Builder.CreateBinaryIntrinsic(
2483+
Intrinsic::usub_with_overflow,
2484+
transValue(BC->getOperand(0), F, BB),
2485+
transValue(BC->getOperand(1), F, BB)));
2486+
}
24792487
case OpGetKernelWorkGroupSize:
24802488
case OpGetKernelPreferredWorkGroupSizeMultiple:
24812489
return mapValue(

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3390,6 +3390,7 @@ bool LLVMToSPIRVBase::isKnownIntrinsic(Intrinsic::ID Id) {
33903390
case Intrinsic::trap:
33913391
case Intrinsic::arithmetic_fence:
33923392
case Intrinsic::uadd_with_overflow:
3393+
case Intrinsic::usub_with_overflow:
33933394
return true;
33943395
default:
33953396
// Unknown intrinsics' declarations should always be translated
@@ -3807,6 +3808,11 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
38073808
transValue(II->getArgOperand(0), BB),
38083809
transValue(II->getArgOperand(1), BB), BB);
38093810
}
3811+
case Intrinsic::usub_with_overflow: {
3812+
return BM->addBinaryInst(OpISubBorrow, transType(II->getType()),
3813+
transValue(II->getArgOperand(0), BB),
3814+
transValue(II->getArgOperand(1), BB), BB);
3815+
}
38103816
case Intrinsic::memset: {
38113817
// Generally there is no direct mapping of memset to SPIR-V. But it turns
38123818
// out that memset is emitted by Clang for initialization in default

lib/SPIRV/libSPIRV/SPIRVEntry.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,6 @@ _SPIRV_OP(ImageDrefGather)
10061006
_SPIRV_OP(QuantizeToF16)
10071007
_SPIRV_OP(ArrayLength)
10081008
_SPIRV_OP(OuterProduct)
1009-
_SPIRV_OP(ISubBorrow)
10101009
_SPIRV_OP(SMulExtended)
10111010
_SPIRV_OP(UMulExtended)
10121011
_SPIRV_OP(DPdx)

lib/SPIRV/libSPIRV/SPIRVInstruction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@ _SPIRV_OP(IAdd)
668668
_SPIRV_OP(IAddCarry)
669669
_SPIRV_OP(FAdd)
670670
_SPIRV_OP(ISub)
671+
_SPIRV_OP(ISubBorrow)
671672
_SPIRV_OP(FSub)
672673
_SPIRV_OP(IMul)
673674
_SPIRV_OP(FMul)

lib/SPIRV/libSPIRV/SPIRVOpCode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ inline bool isAtomicOpCode(Op OpCode) {
7171
}
7272
inline bool isBinaryOpCode(Op OpCode) {
7373
return ((unsigned)OpCode >= OpIAdd && (unsigned)OpCode <= OpFMod) ||
74-
OpCode == OpDot || OpCode == OpIAddCarry;
74+
OpCode == OpDot || OpCode == OpIAddCarry || OpCode == OpISubBorrow;
7575
}
7676

7777
inline bool isShiftOpCode(Op OpCode) {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck --check-prefix CHECK-SPIRV %s
3+
; RUN: llvm-spirv %t.bc -o %t.spv
4+
; Current implementation doesn't comply with specification and should be fixed in future.
5+
; TODO: spirv-val %t.spv
6+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
7+
; RUN: llvm-dis %t.rev.bc -o - | FileCheck --check-prefix CHECK-LLVM %s
8+
9+
target triple = "spir64-unknown-unknown"
10+
11+
12+
; CHECK-SPIRV: TypeInt [[#I16TYPE:]] 16
13+
; CHECK-SPIRV: TypeInt [[#I32TYPE:]] 32
14+
; CHECK-SPIRV: TypeInt [[#I64TYPE:]] 64
15+
; CHECK-SPIRV: TypeBool [[#BTYPE:]]
16+
; CHECK-SPIRV: TypeStruct [[#S0TYPE:]] [[#I16TYPE]] [[#BTYPE]]
17+
; CHECK-SPIRV: TypeStruct [[#S1TYPE:]] [[#I32TYPE]] [[#BTYPE]]
18+
; CHECK-SPIRV: TypeStruct [[#S2TYPE:]] [[#I64TYPE]] [[#BTYPE]]
19+
; CHECK-SPIRV: TypeVector [[#V4XI32TYPE:]] [[#I32TYPE]] 4
20+
; CHECK-SPIRV: TypeVector [[#V4XBTYPE:]] [[#BTYPE]] 4
21+
; CHECK-SPIRV: TypeStruct [[#S3TYPE:]] [[#V4XI32TYPE]] [[#V4XBTYPE]]
22+
; CHECK-SPIRV: ISubBorrow [[#S0TYPE]]
23+
; CHECK-SPIRV: ISubBorrow [[#S1TYPE]]
24+
; CHECK-SPIRV: ISubBorrow [[#S2TYPE]]
25+
; CHECK-SPIRV: ISubBorrow [[#S3TYPE]]
26+
; CHECK-LLVM: call { i16, i1 } @llvm.usub.with.overflow.i16(i16 %a, i16 %b)
27+
; CHECK-LLVM: call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %a, i32 %b)
28+
; CHECK-LLVM: call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
29+
; CHECK-LLVM: call { <4 x i32>, <4 x i1> } @llvm.usub.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
30+
31+
define spir_func void @test_usub_with_overflow_i16(i16 %a, i16 %b) {
32+
entry:
33+
%res = call {i16, i1} @llvm.usub.with.overflow.i16(i16 %a, i16 %b)
34+
ret void
35+
}
36+
37+
define spir_func void @test_usub_with_overflow_i32(i32 %a, i32 %b) {
38+
entry:
39+
%res = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %a, i32 %b)
40+
ret void
41+
}
42+
43+
define spir_func void @test_usub_with_overflow_i64(i64 %a, i64 %b) {
44+
entry:
45+
%res = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
46+
ret void
47+
}
48+
49+
define spir_func void @test_usub_with_overflow_v4i32(<4 x i32> %a, <4 x i32> %b) {
50+
entry:
51+
%res = call {<4 x i32>, <4 x i1>} @llvm.usub.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
52+
ret void
53+
}
54+
55+
declare {i16, i1} @llvm.usub.with.overflow.i16(i16 %a, i16 %b)
56+
declare {i32, i1} @llvm.usub.with.overflow.i32(i32 %a, i32 %b)
57+
declare {i64, i1} @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
58+
declare {<4 x i32>, <4 x i1>} @llvm.usub.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)

0 commit comments

Comments
 (0)