Skip to content

Commit

Permalink
Translate OpIAddCarry and OpISubBorrow back to llvm intrinsics (#2877)
Browse files Browse the repository at this point in the history
Semantically we can translate `OpIAddCarry` and `OpISubBorrow` back into `@llvm.uadd.with.overflow` and `@llvm.usub.with.overflow` respectively.
It require small transformation as there is a difference between return
types in SPIR-V and LLVM IR - e.g., SPIR-V instructions return {i32, i32} struct, but LLVM intrinsics return {i32, i1}.
  • Loading branch information
vmaksimo authored Nov 28, 2024
1 parent 926a92a commit 44bd69e
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 99 deletions.
34 changes: 29 additions & 5 deletions lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2714,13 +2714,37 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
case OpSignBitSet:
return mapValue(BV,
transRelational(static_cast<SPIRVInstruction *>(BV), BB));
case OpIAddCarry: {
auto *BC = static_cast<SPIRVBinary *>(BV);
return mapValue(BV, transBuiltinFromInst("__spirv_IAddCarry", BC, BB));
}
case OpIAddCarry:
case OpISubBorrow: {
IRBuilder Builder(BB);
auto *BC = static_cast<SPIRVBinary *>(BV);
return mapValue(BV, transBuiltinFromInst("__spirv_ISubBorrow", BC, BB));
Intrinsic::ID ID = OC == OpIAddCarry ? Intrinsic::uadd_with_overflow
: Intrinsic::usub_with_overflow;
auto *Inst =
Builder.CreateBinaryIntrinsic(ID, transValue(BC->getOperand(0), F, BB),
transValue(BC->getOperand(1), F, BB));

// Extract components of the result.
auto *Result = Builder.CreateExtractValue(Inst, 0); // iN result
auto *Carry = Builder.CreateExtractValue(Inst, 1); // i1 overflow

// Convert {iN, i1} into {iN, iN} for SPIR-V compatibility.
Value *CarryInt;
if (Carry->getType()->isVectorTy()) {
CarryInt = Builder.CreateZExt(
Carry, VectorType::get(
cast<VectorType>(Result->getType())->getElementType(),
cast<VectorType>(Carry->getType())->getElementCount()));
} else {
CarryInt = Builder.CreateZExt(Carry, Result->getType());
}
auto *ResultStruct =
Builder.CreateInsertValue(UndefValue::get(StructType::get(
Result->getType(), CarryInt->getType())),
Result, 0);
ResultStruct = Builder.CreateInsertValue(ResultStruct, CarryInt, 1);

return mapValue(BV, ResultStruct);
}
case OpSMulExtended: {
auto *BC = static_cast<SPIRVBinary *>(BV);
Expand Down
4 changes: 2 additions & 2 deletions test/builtin_returns_struct.spvasm
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
OpBranch %20
%20 = OpLabel
%e = OpPhi %uint %a %19 %math %21
%16 = OpIAddCarry %_struct_7 %e %uint_1
%16 = OpUMulExtended %_struct_7 %e %uint_1
%math = OpCompositeExtract %uint %16 0
%17 = OpCompositeExtract %uint %16 1
%ov = OpINotEqual %bool %17 %10
Expand All @@ -47,6 +47,6 @@
OpFunctionEnd

; CHECK: %[[#Var:]] = alloca %structtype, align 8
; CHECK: call spir_func void @_Z17__spirv_IAddCarryii(ptr sret(%structtype) %[[#Var:]]
; CHECK: call spir_func void @_Z20__spirv_UMulExtendedii(ptr sret(%structtype) %[[#Var:]]
; CHECK: %[[#Load:]] = load %structtype, ptr %[[#Var]], align 4
; CHECK-2: extractvalue %structtype %[[#Load:]]
48 changes: 42 additions & 6 deletions test/iaddcarry_builtin.ll
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ define spir_func void @test_builtin_iaddcarrycc(i8 %a, i8 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i8struct]], align 8
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarrycc(ptr sret([[i8struct]]) %0, i8 %a, i8 %b)
; CHECK-LLVM: %1 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %a, i8 %b)
; CHECK-LLVM: %2 = extractvalue { i8, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i8, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i8
; CHECK-LLVM: %5 = insertvalue { i8, i8 } undef, i8 %2, 0
; CHECK-LLVM: %6 = insertvalue { i8, i8 } %5, i8 %4, 1
; CHECK-LLVM: store { i8, i8 } %6, ptr %0, align 1
; CHECK-LLVM: ret void
define spir_func void @test_builtin_iaddcarryss(i16 %a, i16 %b) {
entry:
Expand All @@ -75,7 +81,13 @@ define spir_func void @test_builtin_iaddcarryss(i16 %a, i16 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i16struct]], align 8
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryss(ptr sret([[i16struct]]) %0, i16 %a, i16 %b)
; CHECK-LLVM: %1 = call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 %a, i16 %b)
; CHECK-LLVM: %2 = extractvalue { i16, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i16, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i16
; CHECK-LLVM: %5 = insertvalue { i16, i16 } undef, i16 %2, 0
; CHECK-LLVM: %6 = insertvalue { i16, i16 } %5, i16 %4, 1
; CHECK-LLVM: store { i16, i16 } %6, ptr %0, align 2
; CHECK-LLVM: ret void
define spir_func void @test_builtin_iaddcarryii(i32 %a, i32 %b) {
entry:
Expand All @@ -93,7 +105,13 @@ define spir_func void @test_builtin_iaddcarryii(i32 %a, i32 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i32struct]], align 8
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryii(ptr sret([[i32struct]]) %0, i32 %a, i32 %b)
; CHECK-LLVM: %1 = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
; CHECK-LLVM: %2 = extractvalue { i32, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i32, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i32
; CHECK-LLVM: %5 = insertvalue { i32, i32 } undef, i32 %2, 0
; CHECK-LLVM: %6 = insertvalue { i32, i32 } %5, i32 %4, 1
; CHECK-LLVM: store { i32, i32 } %6, ptr %0, align 4
; CHECK-LLVM: ret void
define spir_func void @test_builtin_iaddcarryll(i64 %a, i64 %b) {
entry:
Expand All @@ -111,7 +129,13 @@ define spir_func void @test_builtin_iaddcarryll(i64 %a, i64 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i64struct]]
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryll(ptr sret([[i64struct]]) %0, i64 %a, i64 %b)
; CHECK-LLVM: %1 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
; CHECK-LLVM: %2 = extractvalue { i64, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i64, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i64
; CHECK-LLVM: %5 = insertvalue { i64, i64 } undef, i64 %2, 0
; CHECK-LLVM: %6 = insertvalue { i64, i64 } %5, i64 %4, 1
; CHECK-LLVM: store { i64, i64 } %6, ptr %0, align 8
; CHECK-LLVM: ret void
define spir_func void @test_builtin_iaddcarryDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
entry:
Expand All @@ -129,7 +153,13 @@ define spir_func void @test_builtin_iaddcarryDv4_xS_(<4 x i32> %a, <4 x i32> %b)
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[vecstruct]]
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryDv4_iS_(ptr sret([[vecstruct]]) %0, <4 x i32> %a, <4 x i32> %b)
; CHECK-LLVM: %1 = call { <4 x i32>, <4 x i1> } @llvm.uadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
; CHECK-LLVM: %2 = extractvalue { <4 x i32>, <4 x i1> } %1, 0
; CHECK-LLVM: %3 = extractvalue { <4 x i32>, <4 x i1> } %1, 1
; CHECK-LLVM: %4 = zext <4 x i1> %3 to <4 x i32>
; CHECK-LLVM: %5 = insertvalue { <4 x i32>, <4 x i32> } undef, <4 x i32> %2, 0
; CHECK-LLVM: %6 = insertvalue { <4 x i32>, <4 x i32> } %5, <4 x i32> %4, 1
; CHECK-LLVM: store { <4 x i32>, <4 x i32> } %6, ptr %0, align 16
; CHECK-LLVM: ret void

%struct.anon = type { i32, i32 }
Expand All @@ -151,7 +181,13 @@ define spir_func void @test_builtin_iaddcarry_anon(i32 %a, i32 %b) {

; CHECK-LLVM: %0 = alloca [[struct_anon]], align 8
; CHECK-LLVM: %1 = addrspacecast ptr %0 to ptr addrspace(4)
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryii.1(ptr addrspace(4) sret([[struct_anon]]) %1, i32 %a, i32 %b)
; CHECK-LLVM: %2 = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
; CHECK-LLVM: %3 = extractvalue { i32, i1 } %2, 0
; CHECK-LLVM: %4 = extractvalue { i32, i1 } %2, 1
; CHECK-LLVM: %5 = zext i1 %4 to i32
; CHECK-LLVM: %6 = insertvalue { i32, i32 } undef, i32 %3, 0
; CHECK-LLVM: %7 = insertvalue { i32, i32 } %6, i32 %5, 1
; CHECK-LLVM: store { i32, i32 } %7, ptr addrspace(4) %1, align 4
; CHECK-LLVM: ret void

declare void @_Z17__spirv_IAddCarryIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4, i32, i32)
Expand Down
48 changes: 42 additions & 6 deletions test/isubborrow_builtin.ll
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ define spir_func void @test_builtin_isubborrowcc(i8 %a, i8 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i8struct]], align 8
; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowcc(ptr sret([[i8struct]]) %0, i8 %a, i8 %b)
; CHECK-LLVM: %1 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 %b)
; CHECK-LLVM: %2 = extractvalue { i8, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i8, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i8
; CHECK-LLVM: %5 = insertvalue { i8, i8 } undef, i8 %2, 0
; CHECK-LLVM: %6 = insertvalue { i8, i8 } %5, i8 %4, 1
; CHECK-LLVM: store { i8, i8 } %6, ptr %0, align 1
; CHECK-LLVM: ret void
define spir_func void @test_builtin_isubborrowss(i16 %a, i16 %b) {
entry:
Expand All @@ -76,7 +82,13 @@ define spir_func void @test_builtin_isubborrowss(i16 %a, i16 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i16struct]], align 8
; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowss(ptr sret([[i16struct]]) %0, i16 %a, i16 %b)
; CHECK-LLVM: %1 = call { i16, i1 } @llvm.usub.with.overflow.i16(i16 %a, i16 %b)
; CHECK-LLVM: %2 = extractvalue { i16, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i16, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i16
; CHECK-LLVM: %5 = insertvalue { i16, i16 } undef, i16 %2, 0
; CHECK-LLVM: %6 = insertvalue { i16, i16 } %5, i16 %4, 1
; CHECK-LLVM: store { i16, i16 } %6, ptr %0, align 2
; CHECK-LLVM: ret void
define spir_func void @test_builtin_isubborrowii(i32 %a, i32 %b) {
entry:
Expand All @@ -94,7 +106,13 @@ define spir_func void @test_builtin_isubborrowii(i32 %a, i32 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i32struct]], align 8
; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowii(ptr sret([[i32struct]]) %0, i32 %a, i32 %b)
; CHECK-LLVM: %1 = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %a, i32 %b)
; CHECK-LLVM: %2 = extractvalue { i32, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i32, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i32
; CHECK-LLVM: %5 = insertvalue { i32, i32 } undef, i32 %2, 0
; CHECK-LLVM: %6 = insertvalue { i32, i32 } %5, i32 %4, 1
; CHECK-LLVM: store { i32, i32 } %6, ptr %0, align 4
; CHECK-LLVM: ret void
define spir_func void @test_builtin_isubborrowll(i64 %a, i64 %b) {
entry:
Expand All @@ -112,7 +130,13 @@ define spir_func void @test_builtin_isubborrowll(i64 %a, i64 %b) {
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[i64struct]]
; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowll(ptr sret([[i64struct]]) %0, i64 %a, i64 %b)
; CHECK-LLVM: %1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
; CHECK-LLVM: %2 = extractvalue { i64, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i64, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i64
; CHECK-LLVM: %5 = insertvalue { i64, i64 } undef, i64 %2, 0
; CHECK-LLVM: %6 = insertvalue { i64, i64 } %5, i64 %4, 1
; CHECK-LLVM: store { i64, i64 } %6, ptr %0, align 8
; CHECK-LLVM: ret void
define spir_func void @test_builtin_isubborrowDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
entry:
Expand All @@ -130,7 +154,13 @@ define spir_func void @test_builtin_isubborrowDv4_xS_(<4 x i32> %a, <4 x i32> %b
; CHECK-SPIRV: OpFunctionEnd

; CHECK-LLVM: %0 = alloca [[vecstruct]]
; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowDv4_iS_(ptr sret([[vecstruct]]) %0, <4 x i32> %a, <4 x i32> %b)
; CHECK-LLVM: %1 = call { <4 x i32>, <4 x i1> } @llvm.usub.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
; CHECK-LLVM: %2 = extractvalue { <4 x i32>, <4 x i1> } %1, 0
; CHECK-LLVM: %3 = extractvalue { <4 x i32>, <4 x i1> } %1, 1
; CHECK-LLVM: %4 = zext <4 x i1> %3 to <4 x i32>
; CHECK-LLVM: %5 = insertvalue { <4 x i32>, <4 x i32> } undef, <4 x i32> %2, 0
; CHECK-LLVM: %6 = insertvalue { <4 x i32>, <4 x i32> } %5, <4 x i32> %4, 1
; CHECK-LLVM: store { <4 x i32>, <4 x i32> } %6, ptr %0, align 16
; CHECK-LLVM: ret void


Expand All @@ -151,7 +181,13 @@ define spir_func void @test_builtin_isubborrow_anon(i32 %a, i32 %b) {

; CHECK-LLVM: %0 = alloca [[struct_anon]], align 8
; CHECK-LLVM: %1 = addrspacecast ptr %0 to ptr addrspace(4)
; CHECK-LLVM: call spir_func void @_Z18__spirv_ISubBorrowii.1(ptr addrspace(4) sret([[struct_anon]]) %1, i32 %a, i32 %b)
; CHECK-LLVM: %2 = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %a, i32 %b)
; CHECK-LLVM: %3 = extractvalue { i32, i1 } %2, 0
; CHECK-LLVM: %4 = extractvalue { i32, i1 } %2, 1
; CHECK-LLVM: %5 = zext i1 %4 to i32
; CHECK-LLVM: %6 = insertvalue { i32, i32 } undef, i32 %3, 0
; CHECK-LLVM: %7 = insertvalue { i32, i32 } %6, i32 %5, 1
; CHECK-LLVM: store { i32, i32 } %7, ptr addrspace(4) %1, align 4
; CHECK-LLVM: ret void

declare void @_Z18__spirv_ISubBorrowIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4, i32, i32)
Expand Down
104 changes: 64 additions & 40 deletions test/llvm-intrinsics/uadd.with.overflow.ll
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,22 @@ entry:
; CHECK-SPIRV: OpReturnValue [[var_23]]

; CHECK-LLVM: %0 = alloca [[structtype]], align 8
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryss(ptr sret([[structtype]]) %0, i16 %a, i16 %b)
; CHECK-LLVM: %1 = load [[structtype]], ptr %0, align 2
; CHECK-LLVM: %2 = extractvalue [[structtype]] %1, 0
; CHECK-LLVM: %3 = extractvalue [[structtype]] %1, 1
; CHECK-LLVM: %4 = icmp ne i16 %3, 0
; CHECK-LLVM: %5 = insertvalue [[structtype_0]] undef, i16 %2, 0
; CHECK-LLVM: %6 = insertvalue [[structtype_0]] %5, i1 %4, 1
; CHECK-LLVM: %7 = extractvalue [[structtype_0]] %6, 0
; CHECK-LLVM: %8 = extractvalue [[structtype_0]] %6, 1
; CHECK-LLVM: ret i1 %8
; CHECK-LLVM: %1 = call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 %a, i16 %b)
; CHECK-LLVM: %2 = extractvalue { i16, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i16, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i16
; CHECK-LLVM: %5 = insertvalue { i16, i16 } undef, i16 %2, 0
; CHECK-LLVM: %6 = insertvalue { i16, i16 } %5, i16 %4, 1
; CHECK-LLVM: store { i16, i16 } %6, ptr %0, align 2
; CHECK-LLVM: %7 = load %structtype, ptr %0, align 2
; CHECK-LLVM: %8 = extractvalue [[structtype]] %7, 0
; CHECK-LLVM: %9 = extractvalue [[structtype]] %7, 1
; CHECK-LLVM: %10 = icmp ne i16 %9, 0
; CHECK-LLVM: %11 = insertvalue [[structtype_0]] undef, i16 %8, 0
; CHECK-LLVM: %12 = insertvalue [[structtype_0]] %11, i1 %10, 1
; CHECK-LLVM: %13 = extractvalue [[structtype_0]] %12, 0
; CHECK-LLVM: %14 = extractvalue [[structtype_0]] %12, 1
; CHECK-LLVM: ret i1 %14
define spir_func i1 @test_uadd_with_overflow_i32(i32 %a, i32 %b) {
entry:
%res = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
Expand All @@ -109,16 +115,22 @@ entry:


; CHECK-LLVM: %0 = alloca [[structtype_1]], align 8
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryii(ptr sret([[structtype_1]]) %0, i32 %a, i32 %b)
; CHECK-LLVM: %1 = load [[structtype_1]], ptr %0, align 4
; CHECK-LLVM: %2 = extractvalue [[structtype_1]] %1, 0
; CHECK-LLVM: %3 = extractvalue [[structtype_1]] %1, 1
; CHECK-LLVM: %4 = icmp ne i32 %3, 0
; CHECK-LLVM: %5 = insertvalue [[structtype_2]] undef, i32 %2, 0
; CHECK-LLVM: %6 = insertvalue [[structtype_2]] %5, i1 %4, 1
; CHECK-LLVM: %7 = extractvalue [[structtype_2]] %6, 0
; CHECK-LLVM: %8 = extractvalue [[structtype_2]] %6, 1
; CHECK-LLVM: ret i1 %8
; CHECK-LLVM: %1 = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
; CHECK-LLVM: %2 = extractvalue { i32, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i32, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i32
; CHECK-LLVM: %5 = insertvalue { i32, i32 } undef, i32 %2, 0
; CHECK-LLVM: %6 = insertvalue { i32, i32 } %5, i32 %4, 1
; CHECK-LLVM: store { i32, i32 } %6, ptr %0, align 4
; CHECK-LLVM: %7 = load [[structtype_1]], ptr %0, align 4
; CHECK-LLVM: %8 = extractvalue [[structtype_1]] %7, 0
; CHECK-LLVM: %9 = extractvalue [[structtype_1]] %7, 1
; CHECK-LLVM: %10 = icmp ne i32 %9, 0
; CHECK-LLVM: %11 = insertvalue [[structtype_2]] undef, i32 %8, 0
; CHECK-LLVM: %12 = insertvalue [[structtype_2]] %11, i1 %10, 1
; CHECK-LLVM: %13 = extractvalue [[structtype_2]] %12, 0
; CHECK-LLVM: %14 = extractvalue [[structtype_2]] %12, 1
; CHECK-LLVM: ret i1 %14
define spir_func i1 @test_uadd_with_overflow_i64(i64 %a, i64 %b) {
entry:
%res = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
Expand All @@ -144,16 +156,22 @@ entry:
; CHECK-SPIRV: OpReturnValue [[var_65]]

; CHECK-LLVM: %0 = alloca [[structtype_3]], align 8
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryll(ptr sret([[structtype_3]]) %0, i64 %a, i64 %b)
; CHECK-LLVM: %1 = load [[structtype_3]], ptr %0, align 4
; CHECK-LLVM: %2 = extractvalue [[structtype_3]] %1, 0
; CHECK-LLVM: %3 = extractvalue [[structtype_3]] %1, 1
; CHECK-LLVM: %4 = icmp ne i64 %3, 0
; CHECK-LLVM: %5 = insertvalue [[structtype_4]] undef, i64 %2, 0
; CHECK-LLVM: %6 = insertvalue [[structtype_4]] %5, i1 %4, 1
; CHECK-LLVM: %7 = extractvalue [[structtype_4]] %6, 0
; CHECK-LLVM: %8 = extractvalue [[structtype_4]] %6, 1
; CHECK-LLVM: ret i1 %8
; CHECK-LLVM: %1 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
; CHECK-LLVM: %2 = extractvalue { i64, i1 } %1, 0
; CHECK-LLVM: %3 = extractvalue { i64, i1 } %1, 1
; CHECK-LLVM: %4 = zext i1 %3 to i64
; CHECK-LLVM: %5 = insertvalue { i64, i64 } undef, i64 %2, 0
; CHECK-LLVM: %6 = insertvalue { i64, i64 } %5, i64 %4, 1
; CHECK-LLVM: store { i64, i64 } %6, ptr %0, align 8
; CHECK-LLVM: %7 = load [[structtype_3]], ptr %0, align 4
; CHECK-LLVM: %8 = extractvalue [[structtype_3]] %7, 0
; CHECK-LLVM: %9 = extractvalue [[structtype_3]] %7, 1
; CHECK-LLVM: %10 = icmp ne i64 %9, 0
; CHECK-LLVM: %11 = insertvalue [[structtype_4]] undef, i64 %8, 0
; CHECK-LLVM: %12 = insertvalue [[structtype_4]] %11, i1 %10, 1
; CHECK-LLVM: %13 = extractvalue [[structtype_4]] %12, 0
; CHECK-LLVM: %14 = extractvalue [[structtype_4]] %12, 1
; CHECK-LLVM: ret i1 %14
define spir_func <4 x i1> @test_uadd_with_overflow_v4i32(<4 x i32> %a, <4 x i32> %b) {
entry:
%res = call {<4 x i32>, <4 x i1>} @llvm.uadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
Expand All @@ -179,16 +197,22 @@ entry:
; CHECK-SPIRV: OpReturnValue [[var_87]]

; CHECK-LLVM: %0 = alloca [[structtype_5]], align 16
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryDv4_iS_(ptr sret([[structtype_5]]) %0, <4 x i32> %a, <4 x i32> %b)
; CHECK-LLVM: %1 = load [[structtype_5]], ptr %0, align 16
; CHECK-LLVM: %2 = extractvalue [[structtype_5]] %1, 0
; CHECK-LLVM: %3 = extractvalue [[structtype_5]] %1, 1
; CHECK-LLVM: %4 = icmp ne <4 x i32> %3, zeroinitializer
; CHECK-LLVM: %5 = insertvalue [[structtype_6]] undef, <4 x i32> %2, 0
; CHECK-LLVM: %6 = insertvalue [[structtype_6]] %5, <4 x i1> %4, 1
; CHECK-LLVM: %7 = extractvalue [[structtype_6]] %6, 0
; CHECK-LLVM: %8 = extractvalue [[structtype_6]] %6, 1
; CHECK-LLVM: ret <4 x i1> %8
; CHECK-LLVM: %1 = call { <4 x i32>, <4 x i1> } @llvm.uadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
; CHECK-LLVM: %2 = extractvalue { <4 x i32>, <4 x i1> } %1, 0
; CHECK-LLVM: %3 = extractvalue { <4 x i32>, <4 x i1> } %1, 1
; CHECK-LLVM: %4 = zext <4 x i1> %3 to <4 x i32>
; CHECK-LLVM: %5 = insertvalue { <4 x i32>, <4 x i32> } undef, <4 x i32> %2, 0
; CHECK-LLVM: %6 = insertvalue { <4 x i32>, <4 x i32> } %5, <4 x i32> %4, 1
; CHECK-LLVM: store { <4 x i32>, <4 x i32> } %6, ptr %0, align 16
; CHECK-LLVM: %7 = load [[structtype_5]], ptr %0, align 16
; CHECK-LLVM: %8 = extractvalue [[structtype_5]] %7, 0
; CHECK-LLVM: %9 = extractvalue [[structtype_5]] %7, 1
; CHECK-LLVM: %10 = icmp ne <4 x i32> %9, zeroinitializer
; CHECK-LLVM: %11 = insertvalue [[structtype_6]] undef, <4 x i32> %8, 0
; CHECK-LLVM: %12 = insertvalue [[structtype_6]] %11, <4 x i1> %10, 1
; CHECK-LLVM: %13 = extractvalue [[structtype_6]] %12, 0
; CHECK-LLVM: %14 = extractvalue [[structtype_6]] %12, 1
; CHECK-LLVM: ret <4 x i1> %14
declare {i16, i1} @llvm.uadd.with.overflow.i16(i16 %a, i16 %b)
declare {i32, i1} @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
declare {i64, i1} @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
Expand Down
Loading

0 comments on commit 44bd69e

Please sign in to comment.