From 3e7de94dbd55957dfdb05032a5c2446451da49ac Mon Sep 17 00:00:00 2001 From: Igor Gorban Date: Thu, 21 Mar 2024 15:15:21 +0100 Subject: [PATCH] Add IAddCarry and ISubBorrow builtins (#2392) (#2451) The fix adds support for IR builtin calls __spirv_IAddCarry and __spirv_ISubBorrow. It's also first part of fix which removes noncompliance of uadd/sub_with_overflow intrinsics. SPIRVUtil changes are needed to support situations where builtin don't have corresponding store instruction. Co-authored-by: bwlodarcz --- lib/SPIRV/SPIRVReader.cpp | 12 +- lib/SPIRV/SPIRVUtil.cpp | 27 +++- lib/SPIRV/SPIRVWriter.cpp | 18 +++ test/iaddcarry_builtin.ll | 163 +++++++++++++++++++++ test/isubborrow_builtin.ll | 162 ++++++++++++++++++++ test/llvm-intrinsics/uadd.with.overflow.ll | 6 - test/llvm-intrinsics/usub.with.overflow.ll | 7 - 7 files changed, 366 insertions(+), 29 deletions(-) create mode 100644 test/iaddcarry_builtin.ll create mode 100644 test/isubborrow_builtin.ll diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp index 2a14b53f17..bf44c58df9 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -2340,20 +2340,12 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, return mapValue(BV, transRelational(static_cast(BV), BB)); case OpIAddCarry: { - 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))); + return mapValue(BV, transBuiltinFromInst("__spirv_IAddCarry", BC, 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))); + return mapValue(BV, transBuiltinFromInst("__spirv_ISubBorrow", BC, BB)); } case OpGetKernelWorkGroupSize: case OpGetKernelPreferredWorkGroupSizeMultiple: diff --git a/lib/SPIRV/SPIRVUtil.cpp b/lib/SPIRV/SPIRVUtil.cpp index 9db9309a69..5a5c9f7706 100644 --- a/lib/SPIRV/SPIRVUtil.cpp +++ b/lib/SPIRV/SPIRVUtil.cpp @@ -1892,11 +1892,23 @@ bool postProcessBuiltinReturningStruct(Function *F) { SmallVector InstToRemove; for (auto *U : F->users()) { if (auto *CI = dyn_cast(U)) { - auto *ST = cast(*(CI->user_begin())); + IRBuilder<> Builder(CI->getParent()); + Builder.SetInsertPoint(CI); + SmallVector Users(CI->users()); + Value *A = nullptr; + for (auto *U : Users) { + if (auto *SI = dyn_cast(U)) { + A = SI->getPointerOperand(); + InstToRemove.push_back(SI); + break; + } + } + if (!A) { + A = Builder.CreateAlloca(F->getReturnType()); + } std::vector ArgTys; getFunctionTypeParameterTypes(F->getFunctionType(), ArgTys); - ArgTys.insert(ArgTys.begin(), - PointerType::get(F->getReturnType(), SPIRAS_Private)); + ArgTys.insert(ArgTys.begin(), A->getType()); auto *NewF = getOrCreateFunction(M, Type::getVoidTy(*Context), ArgTys, Name); NewF->addParamAttr(0, Attribute::get(*Context, @@ -1904,10 +1916,13 @@ bool postProcessBuiltinReturningStruct(Function *F) { F->getReturnType())); NewF->setCallingConv(F->getCallingConv()); auto Args = getArguments(CI); - Args.insert(Args.begin(), ST->getPointerOperand()); - auto *NewCI = CallInst::Create(NewF, Args, CI->getName(), CI); + Args.insert(Args.begin(), A); + CallInst *NewCI = Builder.CreateCall(NewF, Args, CI->getName()); NewCI->setCallingConv(CI->getCallingConv()); - InstToRemove.push_back(ST); + SmallVector CIUsers(CI->users()); + for (auto *CIUser : CIUsers) { + CIUser->replaceUsesOfWith(CI, A); + } InstToRemove.push_back(CI); } } diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 6eef7a4227..61c9545d93 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -4364,6 +4364,24 @@ LLVMToSPIRVBase::transBuiltinToInstWithoutDecoration(Op OC, CallInst *CI, return BM->addArbFloatPointIntelInst(OC, transType(ResTy), InA, InB, Literals, BB); } + case OpIAddCarry: { + Function *F = CI->getCalledFunction(); + auto *RetTy = F->arg_begin()->getType()->getPointerElementType(); + StructType *St = cast(RetTy); + SPIRVValue *V = BM->addBinaryInst(OpIAddCarry, transType(St), + transValue(CI->getArgOperand(1), BB), + transValue(CI->getArgOperand(2), BB), BB); + return BM->addStoreInst(transValue(CI->getArgOperand(0), BB), V, {}, BB); + } + case OpISubBorrow: { + Function *F = CI->getCalledFunction(); + auto *RetTy = F->arg_begin()->getType()->getPointerElementType(); + StructType *St = cast(RetTy); + SPIRVValue *V = BM->addBinaryInst(OpISubBorrow, transType(St), + transValue(CI->getArgOperand(1), BB), + transValue(CI->getArgOperand(2), BB), BB); + return BM->addStoreInst(transValue(CI->getArgOperand(0), BB), V, {}, BB); + } default: { if (isCvtOpCode(OC) && OC != OpGenericCastToPtrExplicit) { return BM->addUnaryInst(OC, transType(CI->getType()), diff --git a/test/iaddcarry_builtin.ll b/test/iaddcarry_builtin.ll new file mode 100644 index 0000000000..d9a3b1d312 --- /dev/null +++ b/test/iaddcarry_builtin.ll @@ -0,0 +1,163 @@ +; REQUIRES: spirv-dis +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: spirv-dis --raw-id %t.spv | FileCheck --check-prefix CHECK-SPIRV %s +; RUN: 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" + +%i8struct = type {i8, i8} +%i16struct = type {i16, i16} +%i32struct = type {i32, i32} +%i64struct = type {i64, i64} +%vecstruct = type {<4 x i32>, <4 x i32>} + +; CHECK-SPIRV-DAG: [[uchar:%[a-z0-9_]+]] = OpTypeInt 8 +; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_]+]] = OpTypeInt 16 +; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32 +; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64 +; CHECK-SPIRV-DAG: [[void:%[a-z0-9_]+]] = OpTypeVoid +; CHECK-SPIRV-DAG: [[i8struct:%[a-z0-9_]+]] = OpTypeStruct [[uchar]] [[uchar]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i8struct:%[a-z0-9_]+]] = OpTypePointer Function [[i8struct]] +; CHECK-SPIRV-DAG: [[i16struct:%[a-z0-9_]+]] = OpTypeStruct [[ushort]] [[ushort]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i16struct:%[a-z0-9_]+]] = OpTypePointer Function [[i16struct]] +; CHECK-SPIRV-DAG: [[i32struct:%[a-z0-9_]+]] = OpTypeStruct [[uint]] [[uint]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i32struct:%[a-z0-9_]+]] = OpTypePointer Function [[i32struct]] +; CHECK-SPIRV-DAG: [[i64struct:%[a-z0-9_]+]] = OpTypeStruct [[ulong]] [[ulong]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i64struct:%[a-z0-9_]+]] = OpTypePointer Function [[i64struct]] +; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 4 +; CHECK-SPIRV-DAG: [[vecstruct:%[a-z0-9_]+]] = OpTypeStruct [[v4uint]] [[v4uint]] +; CHECK-SPIRV-DAG: [[_ptr_Function_vecstruct:%[a-z0-9_]+]] = OpTypePointer Function [[vecstruct]] +; CHECK-SPIRV-DAG: [[struct_anon:%[a-z0-9_.]+]] = OpTypeStruct [[uint]] [[uint]] +; CHECK-SPIRV-DAG: [[_ptr_Function_struct_anon:%[a-z0-9_]+]] = OpTypePointer Function [[struct_anon]] +; CHECK-SPIRV-DAG: [[_ptr_Generic_struct_anon:%[a-z0-9_]+]] = OpTypePointer Generic [[struct_anon]] + +; CHECK-LLVM-DAG: [[i8struct:%[a-z0-9_.]+]] = type { i8, i8 } +; CHECK-LLVM-DAG: [[i16struct:%[a-z0-9_.]+]] = type { i16, i16 } +; CHECK-LLVM-DAG: [[i32struct:%[a-z0-9_.]+]] = type { i32, i32 } +; CHECK-LLVM-DAG: [[i64struct:%[a-z0-9_.]+]] = type { i64, i64 } +; CHECK-LLVM-DAG: [[vecstruct:%[a-z0-9_.]+]] = type { <4 x i32>, <4 x i32> } +; CHECK-LLVM-DAG: [[struct_anon:%[a-z0-9_.]+]] = type { i32, i32 } + +define spir_func void @test_builtin_iaddcarrycc(i8 %a, i8 %b) { + entry: + %0 = alloca %i8struct + call void @_Z17__spirv_IAddCarrycc(%i8struct* %0, i8 %a, i8 %b) + ret void +} + +; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]] +; CHECK-SPIRV: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]] +; CHECK-SPIRV: [[entry:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_11:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i8struct]] Function +; CHECK-SPIRV: [[var_12:%[a-z0-9_]+]] = OpIAddCarry [[i8struct]] [[a]] [[b]] +; CHECK-SPIRV: OpStore [[var_11]] [[var_12]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i8struct]], align 8 +; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarrycc([[i8struct]]* sret([[i8struct]]) %0, i8 %a, i8 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_iaddcarryss(i16 %a, i16 %b) { + entry: + %0 = alloca %i16struct + call void @_Z17__spirv_IAddCarryss(%i16struct* %0, i16 %a, i16 %b) + ret void +} +; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]] +; CHECK-SPIRV: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]] +; CHECK-SPIRV: [[entry_0:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_21:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i16struct]] Function +; CHECK-SPIRV: [[var_22:%[a-z0-9_]+]] = OpIAddCarry [[i16struct]] [[a_0]] [[b_0]] +; CHECK-SPIRV: OpStore [[var_21]] [[var_22]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i16struct]], align 8 +; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryss([[i16struct]]* sret([[i16struct]]) %0, i16 %a, i16 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_iaddcarryii(i32 %a, i32 %b) { + entry: + %0 = alloca %i32struct + call void @_Z17__spirv_IAddCarryii(%i32struct* %0, i32 %a, i32 %b) + ret void +} +; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[entry_1:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_31:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function +; CHECK-SPIRV: [[var_32:%[a-z0-9_]+]] = OpIAddCarry [[i32struct]] [[a_1]] [[b_1]] +; CHECK-SPIRV: OpStore [[var_31]] [[var_32]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i32struct]], align 8 +; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryii([[i32struct]]* sret([[i32struct]]) %0, i32 %a, i32 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_iaddcarryll(i64 %a, i64 %b) { + entry: + %0 = alloca %i64struct + call void @_Z17__spirv_IAddCarryll(%i64struct* %0, i64 %a, i64 %b) + ret void +} +; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]] +; CHECK-SPIRV: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]] +; CHECK-SPIRV: [[entry_2:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_41:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i64struct]] Function +; CHECK-SPIRV: [[var_42:%[a-z0-9_]+]] = OpIAddCarry [[i64struct]] [[a_2]] [[b_2]] +; CHECK-SPIRV: OpStore [[var_41]] [[var_42]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i64struct]] +; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryll([[i64struct]]* sret([[i64struct]]) %0, i64 %a, i64 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_iaddcarryDv4_xS_(<4 x i32> %a, <4 x i32> %b) { + entry: + %0 = alloca %vecstruct + call void @_Z17__spirv_IAddCarryDv4_iS_(%vecstruct* %0, <4 x i32> %a, <4 x i32> %b) + ret void +} +; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]] +; CHECK-SPIRV: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]] +; CHECK-SPIRV: [[entry_3:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_51:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_vecstruct]] Function +; CHECK-SPIRV: [[var_52:%[a-z0-9_]+]] = OpIAddCarry [[vecstruct]] [[a_3]] [[b_3]] +; CHECK-SPIRV: OpStore [[var_51]] [[var_52]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[vecstruct]] +; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryDv4_iS_([[vecstruct]]* sret([[vecstruct]]) %0, <4 x i32> %a, <4 x i32> %b) +; CHECK-LLVM: ret void + +%struct.anon = type { i32, i32 } + +define spir_func void @test_builtin_iaddcarry_anon(i32 %a, i32 %b) { + entry: + %0 = alloca %struct.anon + %1 = addrspacecast %struct.anon* %0 to %struct.anon addrspace(4)* + call spir_func void @_Z17__spirv_IAddCarryIiiE4anonIT_T0_ES1_S2_(%struct.anon addrspace(4)* %1, i32 %a, i32 %b) + ret void +} +; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[b_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[entry_4:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_59:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_struct_anon]] Function +; CHECK-SPIRV: [[var_61:%[a-z0-9_]+]] = OpPtrCastToGeneric [[_ptr_Generic_struct_anon]] [[var_59]] +; CHECK-SPIRV: [[var_62:%[a-z0-9_]+]] = OpIAddCarry [[struct_anon]] [[a_4]] [[b_4]] +; CHECK-SPIRV: OpStore [[var_61]] [[var_62]] + +; CHECK-LLVM: %0 = alloca [[struct_anon]], align 8 +; CHECK-LLVM: %1 = addrspacecast [[struct_anon]]* %0 to [[struct_anon]] addrspace(4)* +; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryii.1([[struct_anon]] addrspace(4)* sret([[struct_anon]]) %1, i32 %a, i32 %b) +; CHECK-LLVM: ret void + +declare void @_Z17__spirv_IAddCarryIiiE4anonIT_T0_ES1_S2_(%struct.anon addrspace(4)*, i32, i32) +declare void @_Z17__spirv_IAddCarrycc(%i8struct*, i8, i8) +declare void @_Z17__spirv_IAddCarryss(%i16struct*, i16, i16) +declare void @_Z17__spirv_IAddCarryii(%i32struct*, i32, i32) +declare void @_Z17__spirv_IAddCarryll(%i64struct*, i64, i64) +declare void @_Z17__spirv_IAddCarryDv4_iS_(%vecstruct*, <4 x i32>, <4 x i32>) diff --git a/test/isubborrow_builtin.ll b/test/isubborrow_builtin.ll new file mode 100644 index 0000000000..f8cd48c997 --- /dev/null +++ b/test/isubborrow_builtin.ll @@ -0,0 +1,162 @@ +; REQUIRES: spirv-dis +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: spirv-dis --raw-id %t.spv | FileCheck --check-prefix CHECK-SPIRV %s +; RUN: 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" + +%i8struct = type {i8, i8} +%i16struct = type {i16, i16} +%i32struct = type {i32, i32} +%i64struct = type {i64, i64} +%vecstruct = type {<4 x i32>, <4 x i32>} +%struct.anon = type { i32, i32 } + +; CHECK-SPIRV-DAG: [[uchar:%[a-z0-9_]+]] = OpTypeInt 8 +; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_]+]] = OpTypeInt 16 +; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32 +; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64 +; CHECK-SPIRV-DAG: [[void:%[a-z0-9_]+]] = OpTypeVoid +; CHECK-SPIRV-DAG: [[i8struct:%[a-z0-9_]+]] = OpTypeStruct [[uchar]] [[uchar]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i8struct:%[a-z0-9_]+]] = OpTypePointer Function [[i8struct]] +; CHECK-SPIRV-DAG: [[i16struct:%[a-z0-9_]+]] = OpTypeStruct [[ushort]] [[ushort]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i16struct:%[a-z0-9_]+]] = OpTypePointer Function [[i16struct]] +; CHECK-SPIRV-DAG: [[i32struct:%[a-z0-9_]+]] = OpTypeStruct [[uint]] [[uint]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i32struct:%[a-z0-9_]+]] = OpTypePointer Function [[i32struct]] +; CHECK-SPIRV-DAG: [[i64struct:%[a-z0-9_]+]] = OpTypeStruct [[ulong]] [[ulong]] +; CHECK-SPIRV-DAG: [[_ptr_Function_i64struct:%[a-z0-9_]+]] = OpTypePointer Function [[i64struct]] +; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 4 +; CHECK-SPIRV-DAG: [[vecstruct:%[a-z0-9_]+]] = OpTypeStruct [[v4uint]] [[v4uint]] +; CHECK-SPIRV-DAG: [[_ptr_Function_vecstruct:%[a-z0-9_]+]] = OpTypePointer Function [[vecstruct]] +; CHECK-SPIRV-DAG: [[struct_anon:%[a-z0-9_.]+]] = OpTypeStruct [[uint]] [[uint]] +; CHECK-SPIRV-DAG: [[_ptr_Function_struct_anon:%[a-z0-9_]+]] = OpTypePointer Function [[struct_anon]] +; CHECK-SPIRV-DAG: [[_ptr_Generic_struct_anon:%[a-z0-9_]+]] = OpTypePointer Generic [[struct_anon]] + +; CHECK-LLVM-DAG: [[i8struct:%[a-z0-9_.]+]] = type { i8, i8 } +; CHECK-LLVM-DAG: [[i16struct:%[a-z0-9_.]+]] = type { i16, i16 } +; CHECK-LLVM-DAG: [[i32struct:%[a-z0-9_.]+]] = type { i32, i32 } +; CHECK-LLVM-DAG: [[i64struct:%[a-z0-9_.]+]] = type { i64, i64 } +; CHECK-LLVM-DAG: [[vecstruct:%[a-z0-9_.]+]] = type { <4 x i32>, <4 x i32> } +; CHECK-LLVM-DAG: [[struct_anon:%[a-z0-9_.]+]] = type { i32, i32 } + +define spir_func void @test_builtin_isubborrowcc(i8 %a, i8 %b) { + entry: + %0 = alloca %i8struct + call void @_Z18__spirv_ISubBorrowcc(%i8struct* %0, i8 %a, i8 %b) + ret void +} +; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]] +; CHECK-SPIRV: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]] +; CHECK-SPIRV: [[entry:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_11:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i8struct]] Function +; CHECK-SPIRV: [[var_12:%[a-z0-9_]+]] = OpISubBorrow [[i8struct]] [[a]] [[b]] +; CHECK-SPIRV: OpStore [[var_11]] [[var_12]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i8struct]], align 8 +; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowcc([[i8struct]]* sret([[i8struct]]) %0, i8 %a, i8 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_isubborrowss(i16 %a, i16 %b) { + entry: + %0 = alloca %i16struct + call void @_Z18__spirv_ISubBorrowss(%i16struct* %0, i16 %a, i16 %b) + ret void +} +; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]] +; CHECK-SPIRV: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]] +; CHECK-SPIRV: [[entry_0:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_21:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i16struct]] Function +; CHECK-SPIRV: [[var_22:%[a-z0-9_]+]] = OpISubBorrow [[i16struct]] [[a_0]] [[b_0]] +; CHECK-SPIRV: OpStore [[var_21]] [[var_22]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i16struct]], align 8 +; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowss([[i16struct]]* sret([[i16struct]]) %0, i16 %a, i16 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_isubborrowii(i32 %a, i32 %b) { + entry: + %0 = alloca %i32struct + call void @_Z18__spirv_ISubBorrowii(%i32struct* %0, i32 %a, i32 %b) + ret void +} +; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[entry_1:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_31:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function +; CHECK-SPIRV: [[var_32:%[a-z0-9_]+]] = OpISubBorrow [[i32struct]] [[a_1]] [[b_1]] +; CHECK-SPIRV: OpStore [[var_31]] [[var_32]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i32struct]], align 8 +; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowii([[i32struct]]* sret([[i32struct]]) %0, i32 %a, i32 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_isubborrowll(i64 %a, i64 %b) { + entry: + %0 = alloca %i64struct + call void @_Z18__spirv_ISubBorrowll(%i64struct* %0, i64 %a, i64 %b) + ret void +} +; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]] +; CHECK-SPIRV: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]] +; CHECK-SPIRV: [[entry_2:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_41:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i64struct]] Function +; CHECK-SPIRV: [[var_42:%[a-z0-9_]+]] = OpISubBorrow [[i64struct]] [[a_2]] [[b_2]] +; CHECK-SPIRV: OpStore [[var_41]] [[var_42]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[i64struct]] +; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowll([[i64struct]]* sret([[i64struct]]) %0, i64 %a, i64 %b) +; CHECK-LLVM: ret void +define spir_func void @test_builtin_isubborrowDv4_xS_(<4 x i32> %a, <4 x i32> %b) { + entry: + %0 = alloca %vecstruct + call void @_Z18__spirv_ISubBorrowDv4_iS_(%vecstruct* %0, <4 x i32> %a, <4 x i32> %b) + ret void +} +; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]] +; CHECK-SPIRV: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]] +; CHECK-SPIRV: [[entry_3:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_51:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_vecstruct]] Function +; CHECK-SPIRV: [[var_52:%[a-z0-9_]+]] = OpISubBorrow [[vecstruct]] [[a_3]] [[b_3]] +; CHECK-SPIRV: OpStore [[var_51]] [[var_52]] +; CHECK-SPIRV: OpReturn +; CHECK-SPIRV: OpFunctionEnd + +; CHECK-LLVM: %0 = alloca [[vecstruct]] +; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowDv4_iS_([[vecstruct]]* sret([[vecstruct]]) %0, <4 x i32> %a, <4 x i32> %b) +; CHECK-LLVM: ret void + + +define spir_func void @test_builtin_isubborrow_anon(i32 %a, i32 %b) { + entry: + %0 = alloca %struct.anon + %1 = addrspacecast %struct.anon* %0 to %struct.anon addrspace(4)* + call spir_func void @_Z18__spirv_ISubBorrowIiiE4anonIT_T0_ES1_S2_(%struct.anon addrspace(4)* %1, i32 %a, i32 %b) + ret void +} +; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[b_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]] +; CHECK-SPIRV: [[entry_4:%[a-z0-9_]+]] = OpLabel +; CHECK-SPIRV: [[var_59:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_struct_anon]] Function +; CHECK-SPIRV: [[var_61:%[a-z0-9_]+]] = OpPtrCastToGeneric [[_ptr_Generic_struct_anon]] [[var_59]] +; CHECK-SPIRV: [[var_62:%[a-z0-9_]+]] = OpISubBorrow [[struct_anon]] [[a_4]] [[b_4]] +; CHECK-SPIRV: OpStore [[var_61]] [[var_62]] + +; CHECK-LLVM: %0 = alloca [[struct_anon]], align 8 +; CHECK-LLVM: %1 = addrspacecast [[struct_anon]]* %0 to [[struct_anon]] addrspace(4)* +; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowii.1([[struct_anon]] addrspace(4)* sret([[struct_anon]]) %1, i32 %a, i32 %b) +; CHECK-LLVM: ret void + +declare void @_Z18__spirv_ISubBorrowIiiE4anonIT_T0_ES1_S2_(%struct.anon addrspace(4)* align 4, i32, i32) +declare void @_Z18__spirv_ISubBorrowcc(%i8struct*, i8, i8) +declare void @_Z18__spirv_ISubBorrowss(%i16struct*, i16, i16) +declare void @_Z18__spirv_ISubBorrowii(%i32struct*, i32, i32) +declare void @_Z18__spirv_ISubBorrowll(%i64struct*, i64, i64) +declare void @_Z18__spirv_ISubBorrowDv4_iS_(%vecstruct*, <4 x i32>, <4 x i32>) diff --git a/test/llvm-intrinsics/uadd.with.overflow.ll b/test/llvm-intrinsics/uadd.with.overflow.ll index 265e1f868f..7d560b5507 100644 --- a/test/llvm-intrinsics/uadd.with.overflow.ll +++ b/test/llvm-intrinsics/uadd.with.overflow.ll @@ -3,8 +3,6 @@ ; 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" @@ -22,10 +20,6 @@ target triple = "spir64-unknown-unknown" ; CHECK-SPIRV: IAddCarry [[#S1TYPE]] ; CHECK-SPIRV: IAddCarry [[#S2TYPE]] ; CHECK-SPIRV: IAddCarry [[#S3TYPE]] -; CHECK-LLVM: call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 %a, i16 %b) -; CHECK-LLVM: call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b) -; CHECK-LLVM: call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %b) -; CHECK-LLVM: call { <4 x i32>, <4 x i1> } @llvm.uadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b) define spir_func void @test_uadd_with_overflow_i16(i16 %a, i16 %b) { entry: diff --git a/test/llvm-intrinsics/usub.with.overflow.ll b/test/llvm-intrinsics/usub.with.overflow.ll index 74588ee7e3..a5df081ea9 100644 --- a/test/llvm-intrinsics/usub.with.overflow.ll +++ b/test/llvm-intrinsics/usub.with.overflow.ll @@ -3,12 +3,9 @@ ; 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 @@ -23,10 +20,6 @@ target triple = "spir64-unknown-unknown" ; 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: