From: bwlodarcz Date: Fri, 13 Oct 2023 10:33:06 +0000 (+0200) Subject: [PATCH 84/85] Add support for ISubBorrow SPIRV instruction (#2168) X-Git-Tag: archive/raspbian/15.0.1-1+rpi1^2^2~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=caeb0fb926799a1b91396ecd1aab48633d58a055;p=spirv-llvm-translator-15.git [PATCH 84/85] 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. Gbp-Pq: Name 0084-Add-support-for-ISubBorrow-SPIRV-instruction-2168.patch --- diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp index 74ed304..0d6dbf2 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -2471,13 +2471,21 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, return mapValue(BV, transRelational(static_cast(BV), BB)); case OpIAddCarry: { - IRBuilder Builder(BB); + IRBuilder<> Builder(BB); auto *BC = static_cast(BV); return mapValue(BV, Builder.CreateBinaryIntrinsic( Intrinsic::uadd_with_overflow, transValue(BC->getOperand(0), F, BB), transValue(BC->getOperand(1), F, BB))); } + case OpISubBorrow: { + IRBuilder<> Builder(BB); + auto *BC = static_cast(BV); + return mapValue(BV, Builder.CreateBinaryIntrinsic( + Intrinsic::usub_with_overflow, + transValue(BC->getOperand(0), F, BB), + transValue(BC->getOperand(1), F, BB))); + } case OpGetKernelWorkGroupSize: case OpGetKernelPreferredWorkGroupSizeMultiple: return mapValue( diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 95e5bf8..ef12203 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -3364,6 +3364,7 @@ bool LLVMToSPIRVBase::isKnownIntrinsic(Intrinsic::ID Id) { case Intrinsic::trap: case Intrinsic::arithmetic_fence: case Intrinsic::uadd_with_overflow: + case Intrinsic::usub_with_overflow: return true; default: // Unknown intrinsics' declarations should always be translated @@ -3782,6 +3783,11 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, transValue(II->getArgOperand(0), BB), transValue(II->getArgOperand(1), BB), BB); } + case Intrinsic::usub_with_overflow: { + return BM->addBinaryInst(OpISubBorrow, transType(II->getType()), + transValue(II->getArgOperand(0), BB), + transValue(II->getArgOperand(1), BB), BB); + } case Intrinsic::memset: { // Generally there is no direct mapping of memset to SPIR-V. But it turns // out that memset is emitted by Clang for initialization in default diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.h b/lib/SPIRV/libSPIRV/SPIRVEntry.h index a7b2c79..9e7217a 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.h +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h @@ -1006,7 +1006,6 @@ _SPIRV_OP(ImageDrefGather) _SPIRV_OP(QuantizeToF16) _SPIRV_OP(ArrayLength) _SPIRV_OP(OuterProduct) -_SPIRV_OP(ISubBorrow) _SPIRV_OP(SMulExtended) _SPIRV_OP(UMulExtended) _SPIRV_OP(DPdx) diff --git a/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/lib/SPIRV/libSPIRV/SPIRVInstruction.h index 9eaf1db..bd18313 100644 --- a/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -664,6 +664,7 @@ _SPIRV_OP(IAdd) _SPIRV_OP(IAddCarry) _SPIRV_OP(FAdd) _SPIRV_OP(ISub) +_SPIRV_OP(ISubBorrow) _SPIRV_OP(FSub) _SPIRV_OP(IMul) _SPIRV_OP(FMul) diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCode.h b/lib/SPIRV/libSPIRV/SPIRVOpCode.h index d95ed81..173b249 100644 --- a/lib/SPIRV/libSPIRV/SPIRVOpCode.h +++ b/lib/SPIRV/libSPIRV/SPIRVOpCode.h @@ -71,7 +71,7 @@ inline bool isAtomicOpCode(Op OpCode) { } inline bool isBinaryOpCode(Op OpCode) { return ((unsigned)OpCode >= OpIAdd && (unsigned)OpCode <= OpFMod) || - OpCode == OpDot || OpCode == OpIAddCarry; + OpCode == OpDot || OpCode == OpIAddCarry || OpCode == OpISubBorrow; } inline bool isShiftOpCode(Op OpCode) { diff --git a/test/llvm-intrinsics/usub.with.overflow.ll b/test/llvm-intrinsics/usub.with.overflow.ll new file mode 100644 index 0000000..74588ee --- /dev/null +++ b/test/llvm-intrinsics/usub.with.overflow.ll @@ -0,0 +1,58 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck --check-prefix CHECK-SPIRV %s +; RUN: llvm-spirv %t.bc -o %t.spv +; Current implementation doesn't comply with specification and should be fixed in future. +; TODO: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc -o - | FileCheck --check-prefix CHECK-LLVM %s + +target triple = "spir64-unknown-unknown" + + +; CHECK-SPIRV: TypeInt [[#I16TYPE:]] 16 +; CHECK-SPIRV: TypeInt [[#I32TYPE:]] 32 +; CHECK-SPIRV: TypeInt [[#I64TYPE:]] 64 +; CHECK-SPIRV: TypeBool [[#BTYPE:]] +; CHECK-SPIRV: TypeStruct [[#S0TYPE:]] [[#I16TYPE]] [[#BTYPE]] +; CHECK-SPIRV: TypeStruct [[#S1TYPE:]] [[#I32TYPE]] [[#BTYPE]] +; CHECK-SPIRV: TypeStruct [[#S2TYPE:]] [[#I64TYPE]] [[#BTYPE]] +; CHECK-SPIRV: TypeVector [[#V4XI32TYPE:]] [[#I32TYPE]] 4 +; CHECK-SPIRV: TypeVector [[#V4XBTYPE:]] [[#BTYPE]] 4 +; CHECK-SPIRV: TypeStruct [[#S3TYPE:]] [[#V4XI32TYPE]] [[#V4XBTYPE]] +; CHECK-SPIRV: ISubBorrow [[#S0TYPE]] +; CHECK-SPIRV: ISubBorrow [[#S1TYPE]] +; CHECK-SPIRV: ISubBorrow [[#S2TYPE]] +; CHECK-SPIRV: ISubBorrow [[#S3TYPE]] +; CHECK-LLVM: call { i16, i1 } @llvm.usub.with.overflow.i16(i16 %a, i16 %b) +; CHECK-LLVM: call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %a, i32 %b) +; CHECK-LLVM: call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b) +; CHECK-LLVM: call { <4 x i32>, <4 x i1> } @llvm.usub.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b) + +define spir_func void @test_usub_with_overflow_i16(i16 %a, i16 %b) { +entry: + %res = call {i16, i1} @llvm.usub.with.overflow.i16(i16 %a, i16 %b) + ret void +} + +define spir_func void @test_usub_with_overflow_i32(i32 %a, i32 %b) { +entry: + %res = call {i32, i1} @llvm.usub.with.overflow.i32(i32 %a, i32 %b) + ret void +} + +define spir_func void @test_usub_with_overflow_i64(i64 %a, i64 %b) { +entry: + %res = call {i64, i1} @llvm.usub.with.overflow.i64(i64 %a, i64 %b) + ret void +} + +define spir_func void @test_usub_with_overflow_v4i32(<4 x i32> %a, <4 x i32> %b) { +entry: + %res = call {<4 x i32>, <4 x i1>} @llvm.usub.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b) + ret void +} + +declare {i16, i1} @llvm.usub.with.overflow.i16(i16 %a, i16 %b) +declare {i32, i1} @llvm.usub.with.overflow.i32(i32 %a, i32 %b) +declare {i64, i1} @llvm.usub.with.overflow.i64(i64 %a, i64 %b) +declare {<4 x i32>, <4 x i1>} @llvm.usub.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)