Skip to content

Commit 98729ef

Browse files
authored
Regularization of uadd/usub_with_overflow intrinsics (#2419)
The translation of uadd/usub with overflow were problematic. The returning type of these IR intrinsics are tuples with a second i1 type. These intrinsics were translated to OpIAddCarry and OpISubBorrow which, according to standard, should also return a two element tuple but in that case both types should be the same. IR i1 type is translated by default to BoolType which doesn't have the same properties as i1. There isn't also a possibility to exceptionally override the default behavior in current architecture. Finally the translation was implemented but without compliance with SPIR-V spec - the resulting type of two ops contained BoolType as second element. This commit fixes non compliant translation. Instrinsics uadd/usub_with_overflow are now translated to sequence of operations which repacks compliant return type into expected IR type with second element as BoolType. E.g for i32 uadd_with_overflow: %0 = alloca {i32, i32}, align 8 call spir_func void @_Z17__spirv_IAddCarryii(ptr sret({i32, i32}) %0, i32 %a, i32 %b) %1 = load {i32, i32}, ptr %0, align 4 %2 = extractvalue {i32, i32} %1, 0 %3 = extractvalue {i32, i32} %1, 1 %4 = icmp ne i32 %3, 0 %5 = insertvalue {i32, i1} undef, i32 %2, 0 %6 = insertvalue {i32, i1} %5, i1 %4, 1 All uses of original intrinsic value are replaced with the repacked result (%6 above) which fixes type mismatch.
1 parent e8e0666 commit 98729ef

File tree

3 files changed

+425
-54
lines changed

3 files changed

+425
-54
lines changed

lib/SPIRV/SPIRVRegularizeLLVM.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,70 @@ bool SPIRVRegularizeLLVMBase::runRegularizeLLVM(Module &Module) {
335335
return true;
336336
}
337337

338+
namespace {
339+
void regularizeWithOverflowInstrinsics(StringRef MangledName, CallInst *Call,
340+
Module *M,
341+
std::vector<Instruction *> &ToErase) {
342+
IRBuilder Builder(Call);
343+
Function *Builtin = Call->getModule()->getFunction(MangledName);
344+
AllocaInst *A;
345+
StructType *StructBuiltinTy;
346+
if (Builtin) {
347+
StructBuiltinTy = cast<StructType>(Builtin->getParamStructRetType(0));
348+
{
349+
IRBuilderBase::InsertPointGuard Guard(Builder);
350+
Builder.SetInsertPointPastAllocas(Call->getParent()->getParent());
351+
A = Builder.CreateAlloca(StructBuiltinTy);
352+
}
353+
CallInst *C = Builder.CreateCall(
354+
Builtin, {A, Call->getArgOperand(0), Call->getArgOperand(1)});
355+
auto SretAttr = Attribute::get(
356+
Builder.getContext(), Attribute::AttrKind::StructRet, StructBuiltinTy);
357+
C->addParamAttr(0, SretAttr);
358+
} else {
359+
StructBuiltinTy = StructType::create(
360+
Call->getContext(),
361+
{Call->getArgOperand(0)->getType(), Call->getArgOperand(1)->getType()});
362+
{
363+
IRBuilderBase::InsertPointGuard Guard(Builder);
364+
Builder.SetInsertPointPastAllocas(Call->getParent()->getParent());
365+
A = Builder.CreateAlloca(StructBuiltinTy);
366+
}
367+
FunctionType *FT =
368+
FunctionType::get(Builder.getVoidTy(),
369+
{A->getType(), Call->getArgOperand(0)->getType(),
370+
Call->getArgOperand(1)->getType()},
371+
false);
372+
Builtin =
373+
Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M);
374+
Builtin->setCallingConv(CallingConv::SPIR_FUNC);
375+
Builtin->addFnAttr(Attribute::NoUnwind);
376+
auto SretAttr = Attribute::get(
377+
Builder.getContext(), Attribute::AttrKind::StructRet, StructBuiltinTy);
378+
Builtin->addParamAttr(0, SretAttr);
379+
CallInst *C = Builder.CreateCall(
380+
Builtin, {A, Call->getArgOperand(0), Call->getArgOperand(1)});
381+
C->addParamAttr(0, SretAttr);
382+
}
383+
Type *RetTy = Call->getArgOperand(0)->getType();
384+
Constant *ConstZero = ConstantInt::get(RetTy, 0);
385+
Value *L = Builder.CreateLoad(StructBuiltinTy, A);
386+
Value *V0 = Builder.CreateExtractValue(L, {0});
387+
Value *V1 = Builder.CreateExtractValue(L, {1});
388+
Value *V2 = Builder.CreateICmpNE(V1, ConstZero);
389+
Type *StructI32I1Ty =
390+
StructType::create(Call->getContext(), {RetTy, V2->getType()});
391+
Value *Undef = UndefValue::get(StructI32I1Ty);
392+
Value *V3 = Builder.CreateInsertValue(Undef, V0, {0});
393+
Value *V4 = Builder.CreateInsertValue(V3, V2, {1});
394+
SmallVector<User *> Users(Call->users());
395+
for (User *U : Users) {
396+
U->replaceUsesOfWith(Call, V4);
397+
}
398+
ToErase.push_back(Call);
399+
}
400+
} // namespace
401+
338402
/// Remove entities not representable by SPIR-V
339403
bool SPIRVRegularizeLLVMBase::regularize() {
340404
eraseUselessFunctions(M);
@@ -365,6 +429,23 @@ bool SPIRVRegularizeLLVMBase::regularize() {
365429
lowerFunnelShift(II);
366430
else if (II->getIntrinsicID() == Intrinsic::umul_with_overflow)
367431
lowerUMulWithOverflow(II);
432+
else if (II->getIntrinsicID() == Intrinsic::uadd_with_overflow) {
433+
BuiltinFuncMangleInfo Info;
434+
std::string MangledName =
435+
mangleBuiltin("__spirv_IAddCarry",
436+
{Call->getArgOperand(0)->getType(),
437+
Call->getArgOperand(1)->getType()},
438+
&Info);
439+
regularizeWithOverflowInstrinsics(MangledName, Call, M, ToErase);
440+
} else if (II->getIntrinsicID() == Intrinsic::usub_with_overflow) {
441+
BuiltinFuncMangleInfo Info;
442+
std::string MangledName =
443+
mangleBuiltin("__spirv_ISubBorrow",
444+
{Call->getArgOperand(0)->getType(),
445+
Call->getArgOperand(1)->getType()},
446+
&Info);
447+
regularizeWithOverflowInstrinsics(MangledName, Call, M, ToErase);
448+
}
368449
}
369450
}
370451

Lines changed: 172 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,196 @@
1+
; REQUIRES: spirv-dis
12
; RUN: llvm-as %s -o %t.bc
2-
; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck --check-prefix CHECK-SPIRV %s
33
; 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
4+
; RUN: spirv-dis --raw-id %t.spv | FileCheck --check-prefix CHECK-SPIRV %s
5+
; RUN: spirv-val %t.spv
6+
; RUN: llvm-spirv -r -o %t.rev.bc %t.spv
7+
; RUN: llvm-dis -o - %t.rev.bc | FileCheck --check-prefix CHECK-LLVM %s
68

79
target triple = "spir64-unknown-unknown"
810

9-
; CHECK-SPIRV: TypeInt [[#I16TYPE:]] 16
10-
; CHECK-SPIRV: TypeInt [[#I32TYPE:]] 32
11-
; CHECK-SPIRV: TypeInt [[#I64TYPE:]] 64
12-
; CHECK-SPIRV: TypeBool [[#BTYPE:]]
13-
; CHECK-SPIRV: TypeStruct [[#S0TYPE:]] [[#I16TYPE]] [[#BTYPE]]
14-
; CHECK-SPIRV: TypeStruct [[#S1TYPE:]] [[#I32TYPE]] [[#BTYPE]]
15-
; CHECK-SPIRV: TypeStruct [[#S2TYPE:]] [[#I64TYPE]] [[#BTYPE]]
16-
; CHECK-SPIRV: TypeVector [[#V4XI32TYPE:]] [[#I32TYPE]] 4
17-
; CHECK-SPIRV: TypeVector [[#V4XBTYPE:]] [[#BTYPE]] 4
18-
; CHECK-SPIRV: TypeStruct [[#S3TYPE:]] [[#V4XI32TYPE]] [[#V4XBTYPE]]
19-
; CHECK-SPIRV: IAddCarry [[#S0TYPE]]
20-
; CHECK-SPIRV: IAddCarry [[#S1TYPE]]
21-
; CHECK-SPIRV: IAddCarry [[#S2TYPE]]
22-
; CHECK-SPIRV: IAddCarry [[#S3TYPE]]
23-
24-
define spir_func void @test_uadd_with_overflow_i16(i16 %a, i16 %b) {
11+
; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_.]+]] = OpTypeInt 16 0
12+
; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_.]+]] = OpTypeInt 32 0
13+
; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_.]+]] = OpTypeInt 64 0
14+
; CHECK-SPIRV-DAG: [[ushort_0:%[a-z0-9_.]+]] = OpConstant [[ushort]] 0
15+
; CHECK-SPIRV-DAG: [[uint_0:%[a-z0-9_.]+]] = OpConstant [[uint]] 0
16+
; CHECK-SPIRV-DAG: [[ulong_0:%[a-z0-9_.]+]] = OpConstant [[ulong]] 0
17+
; CHECK-SPIRV-DAG: [[bool:%[a-z0-9_.]+]] = OpTypeBool
18+
; CHECK-SPIRV-DAG: [[var_4:%[a-z0-9_.]+]] = OpTypeFunction [[bool]] [[ushort]] [[ushort]]
19+
; CHECK-SPIRV-DAG: [[_struct_9:%[a-z0-9_.]+]] = OpTypeStruct [[ushort]] [[ushort]]
20+
; CHECK-SPIRV-DAG: [[_ptr_Function__struct_9:%[a-z0-9_.]+]] = OpTypePointer Function [[_struct_9]]
21+
; CHECK-SPIRV-DAG: [[_struct_18:%[a-z0-9_.]+]] = OpTypeStruct [[ushort]] [[bool]]
22+
; CHECK-SPIRV-DAG: [[var_25:%[a-z0-9_.]+]] = OpTypeFunction [[bool]] [[uint]] [[uint]]
23+
; CHECK-SPIRV-DAG: [[_struct_30:%[a-z0-9_.]+]] = OpTypeStruct [[uint]] [[uint]]
24+
; CHECK-SPIRV-DAG: [[_ptr_Function__struct_30:%[a-z0-9_.]+]] = OpTypePointer Function [[_struct_30]]
25+
; CHECK-SPIRV-DAG: [[_struct_39:%[a-z0-9_.]+]] = OpTypeStruct [[uint]] [[bool]]
26+
; CHECK-SPIRV-DAG: [[var_46:%[a-z0-9_.]+]] = OpTypeFunction [[bool]] [[ulong]] [[ulong]]
27+
; CHECK-SPIRV-DAG: [[_struct_51:%[a-z0-9_.]+]] = OpTypeStruct [[ulong]] [[ulong]]
28+
; CHECK-SPIRV-DAG: [[_ptr_Function__struct_51:%[a-z0-9_.]+]] = OpTypePointer Function [[_struct_51]]
29+
; CHECK-SPIRV-DAG: [[_struct_60:%[a-z0-9_.]+]] = OpTypeStruct [[ulong]] [[bool]]
30+
; CHECK-SPIRV-DAG: [[v4bool:%[a-z0-9_.]+]] = OpTypeVector [[bool]] 4
31+
; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_.]+]] = OpTypeVector [[uint]] 4
32+
; CHECK-SPIRV-DAG: [[var_68:%[a-z0-9_.]+]] = OpTypeFunction [[v4bool]] [[v4uint]] [[v4uint]]
33+
; CHECK-SPIRV-DAG: [[_struct_73:%[a-z0-9_.]+]] = OpTypeStruct [[v4uint]] [[v4uint]]
34+
; CHECK-SPIRV-DAG: [[_ptr_Function__struct_73:%[a-z0-9_.]+]] = OpTypePointer Function [[_struct_73]]
35+
; CHECK-SPIRV-DAG: [[_struct_82:%[a-z0-9_.]+]] = OpTypeStruct [[v4uint]] [[v4bool]]
36+
; CHECK-SPIRV-DAG: [[var_19:%[a-z0-9_.]+]] = OpUndef [[_struct_18]]
37+
; CHECK-SPIRV-DAG: [[var_40:%[a-z0-9_.]+]] = OpUndef [[_struct_39]]
38+
; CHECK-SPIRV-DAG: [[var_61:%[a-z0-9_.]+]] = OpUndef [[_struct_60]]
39+
; CHECK-SPIRV-DAG: [[var_80:%[a-z0-9_.]+]] = OpConstantNull [[v4uint]]
40+
; CHECK-SPIRV-DAG: [[var_83:%[a-z0-9_.]+]] = OpUndef [[_struct_82]]
41+
42+
; CHECK-LLVM-DAG: [[structtype:%[a-z0-9._]+]] = type { i16, i16 }
43+
; CHECK-LLVM-DAG: [[structtype_0:%[a-z0-9._]+]] = type { i16, i1 }
44+
; CHECK-LLVM-DAG: [[structtype_1:%[a-z0-9._]+]] = type { i32, i32 }
45+
; CHECK-LLVM-DAG: [[structtype_2:%[a-z0-9._]+]] = type { i32, i1 }
46+
; CHECK-LLVM-DAG: [[structtype_3:%[a-z0-9._]+]] = type { i64, i64 }
47+
; CHECK-LLVM-DAG: [[structtype_4:%[a-z0-9._]+]] = type { i64, i1 }
48+
; CHECK-LLVM-DAG: [[structtype_5:%[a-z0-9._]+]] = type { <4 x i32>, <4 x i32> }
49+
; CHECK-LLVM-DAG: [[structtype_6:%[a-z0-9._]+]] = type { <4 x i32>, <4 x i1> }
50+
51+
define spir_func i1 @test_uadd_with_overflow_i16(i16 %a, i16 %b) {
2552
entry:
2653
%res = call {i16, i1} @llvm.uadd.with.overflow.i16(i16 %a, i16 %b)
27-
ret void
54+
%0 = extractvalue {i16, i1} %res, 0
55+
%1 = extractvalue {i16, i1} %res, 1
56+
ret i1 %1
2857
}
2958

30-
define spir_func void @test_uadd_with_overflow_i32(i32 %a, i32 %b) {
59+
; CHECK-SPIRV: [[a:%[a-z0-9_.]+]] = OpFunctionParameter [[ushort]]
60+
; CHECK-SPIRV: [[b:%[a-z0-9_.]+]] = OpFunctionParameter [[ushort]]
61+
; CHECK-SPIRV: [[entry:%[a-z0-9_.]+]] = OpLabel
62+
; CHECK-SPIRV: [[var_11:%[a-z0-9_.]+]] = OpVariable [[_ptr_Function__struct_9]] Function
63+
; CHECK-SPIRV: [[var_12:%[a-z0-9_.]+]] = OpIAddCarry [[_struct_9]] [[a]] [[b]]
64+
; CHECK-SPIRV: OpStore [[var_11]] [[var_12]]
65+
; CHECK-SPIRV: [[var_13:%[a-z0-9_.]+]] = OpLoad [[_struct_9]] [[var_11]] Aligned 2
66+
; CHECK-SPIRV: [[var_14:%[a-z0-9_.]+]] = OpCompositeExtract [[ushort]] [[var_13]] 0
67+
; CHECK-SPIRV: [[var_15:%[a-z0-9_.]+]] = OpCompositeExtract [[ushort]] [[var_13]] 1
68+
; CHECK-SPIRV: [[var_17:%[a-z0-9_.]+]] = OpINotEqual [[bool]] [[var_15]] [[ushort_0]]
69+
; CHECK-SPIRV: [[var_20:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_18]] [[var_14]] [[var_19]] 0
70+
; CHECK-SPIRV: [[var_21:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_18]] [[var_17]] [[var_20]] 1
71+
; CHECK-SPIRV: [[var_22:%[a-z0-9_.]+]] = OpCompositeExtract [[ushort]] [[var_21]] 0
72+
; CHECK-SPIRV: [[var_23:%[a-z0-9_.]+]] = OpCompositeExtract [[bool]] [[var_21]] 1
73+
; CHECK-SPIRV: OpReturnValue [[var_23]]
74+
75+
; CHECK-LLVM: %0 = alloca [[structtype]], align 8
76+
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryss(ptr sret([[structtype]]) %0, i16 %a, i16 %b)
77+
; CHECK-LLVM: %1 = load [[structtype]], ptr %0, align 2
78+
; CHECK-LLVM: %2 = extractvalue [[structtype]] %1, 0
79+
; CHECK-LLVM: %3 = extractvalue [[structtype]] %1, 1
80+
; CHECK-LLVM: %4 = icmp ne i16 %3, 0
81+
; CHECK-LLVM: %5 = insertvalue [[structtype_0]] undef, i16 %2, 0
82+
; CHECK-LLVM: %6 = insertvalue [[structtype_0]] %5, i1 %4, 1
83+
; CHECK-LLVM: %7 = extractvalue [[structtype_0]] %6, 0
84+
; CHECK-LLVM: %8 = extractvalue [[structtype_0]] %6, 1
85+
; CHECK-LLVM: ret i1 %8
86+
define spir_func i1 @test_uadd_with_overflow_i32(i32 %a, i32 %b) {
3187
entry:
3288
%res = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
33-
ret void
89+
%0 = extractvalue {i32, i1} %res, 0
90+
%1 = extractvalue {i32, i1} %res, 1
91+
ret i1 %1
3492
}
3593

36-
define spir_func void @test_uadd_with_overflow_i64(i64 %a, i64 %b) {
94+
; CHECK-SPIRV: [[a_0:%[a-z0-9_.]+]] = OpFunctionParameter [[uint]]
95+
; CHECK-SPIRV: [[b_0:%[a-z0-9_.]+]] = OpFunctionParameter [[uint]]
96+
; CHECK-SPIRV: [[entry_0:%[a-z0-9_.]+]] = OpLabel
97+
; CHECK-SPIRV: [[var_32:%[a-z0-9_.]+]] = OpVariable [[_ptr_Function__struct_30]] Function
98+
; CHECK-SPIRV: [[var_33:%[a-z0-9_.]+]] = OpIAddCarry [[_struct_30]] [[a_0]] [[b_0]]
99+
; CHECK-SPIRV: OpStore [[var_32]] [[var_33]]
100+
; CHECK-SPIRV: [[var_34:%[a-z0-9_.]+]] = OpLoad [[_struct_30]] [[var_32]] Aligned 4
101+
; CHECK-SPIRV: [[var_35:%[a-z0-9_.]+]] = OpCompositeExtract [[uint]] [[var_34]] 0
102+
; CHECK-SPIRV: [[var_36:%[a-z0-9_.]+]] = OpCompositeExtract [[uint]] [[var_34]] 1
103+
; CHECK-SPIRV: [[var_38:%[a-z0-9_.]+]] = OpINotEqual [[bool]] [[var_36]] [[uint_0]]
104+
; CHECK-SPIRV: [[var_41:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_39]] [[var_35]] [[var_40]] 0
105+
; CHECK-SPIRV: [[var_42:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_39]] [[var_38]] [[var_41]] 1
106+
; CHECK-SPIRV: [[var_43:%[a-z0-9_.]+]] = OpCompositeExtract [[uint]] [[var_42]] 0
107+
; CHECK-SPIRV: [[var_44:%[a-z0-9_.]+]] = OpCompositeExtract [[bool]] [[var_42]] 1
108+
; CHECK-SPIRV: OpReturnValue [[var_44]]
109+
110+
111+
; CHECK-LLVM: %0 = alloca [[structtype_1]], align 8
112+
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryii(ptr sret([[structtype_1]]) %0, i32 %a, i32 %b)
113+
; CHECK-LLVM: %1 = load [[structtype_1]], ptr %0, align 4
114+
; CHECK-LLVM: %2 = extractvalue [[structtype_1]] %1, 0
115+
; CHECK-LLVM: %3 = extractvalue [[structtype_1]] %1, 1
116+
; CHECK-LLVM: %4 = icmp ne i32 %3, 0
117+
; CHECK-LLVM: %5 = insertvalue [[structtype_2]] undef, i32 %2, 0
118+
; CHECK-LLVM: %6 = insertvalue [[structtype_2]] %5, i1 %4, 1
119+
; CHECK-LLVM: %7 = extractvalue [[structtype_2]] %6, 0
120+
; CHECK-LLVM: %8 = extractvalue [[structtype_2]] %6, 1
121+
; CHECK-LLVM: ret i1 %8
122+
define spir_func i1 @test_uadd_with_overflow_i64(i64 %a, i64 %b) {
37123
entry:
38124
%res = call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
39-
ret void
125+
%0 = extractvalue {i64, i1} %res, 0
126+
%1 = extractvalue {i64, i1} %res, 1
127+
ret i1 %1
40128
}
41129

42-
define spir_func void @test_uadd_with_overflow_v4i32(<4 x i32> %a, <4 x i32> %b) {
130+
; CHECK-SPIRV: [[a_1:%[a-z0-9_.]+]] = OpFunctionParameter [[ulong]]
131+
; CHECK-SPIRV: [[b_1:%[a-z0-9_.]+]] = OpFunctionParameter [[ulong]]
132+
; CHECK-SPIRV: [[entry_1:%[a-z0-9_.]+]] = OpLabel
133+
; CHECK-SPIRV: [[var_53:%[a-z0-9_.]+]] = OpVariable [[_ptr_Function__struct_51]] Function
134+
; CHECK-SPIRV: [[var_54:%[a-z0-9_.]+]] = OpIAddCarry [[_struct_51]] [[a_1]] [[b_1]]
135+
; CHECK-SPIRV: OpStore [[var_53]] [[var_54]]
136+
; CHECK-SPIRV: [[var_55:%[a-z0-9_.]+]] = OpLoad [[_struct_51]] [[var_53]] Aligned 4
137+
; CHECK-SPIRV: [[var_56:%[a-z0-9_.]+]] = OpCompositeExtract [[ulong]] [[var_55]] 0
138+
; CHECK-SPIRV: [[var_57:%[a-z0-9_.]+]] = OpCompositeExtract [[ulong]] [[var_55]] 1
139+
; CHECK-SPIRV: [[var_59:%[a-z0-9_.]+]] = OpINotEqual [[bool]] [[var_57]] [[ulong_0]]
140+
; CHECK-SPIRV: [[var_62:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_60]] [[var_56]] [[var_61]] 0
141+
; CHECK-SPIRV: [[var_63:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_60]] [[var_59]] [[var_62]] 1
142+
; CHECK-SPIRV: [[var_64:%[a-z0-9_.]+]] = OpCompositeExtract [[ulong]] [[var_63]] 0
143+
; CHECK-SPIRV: [[var_65:%[a-z0-9_.]+]] = OpCompositeExtract [[bool]] [[var_63]] 1
144+
; CHECK-SPIRV: OpReturnValue [[var_65]]
145+
146+
; CHECK-LLVM: %0 = alloca [[structtype_3]], align 8
147+
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryll(ptr sret([[structtype_3]]) %0, i64 %a, i64 %b)
148+
; CHECK-LLVM: %1 = load [[structtype_3]], ptr %0, align 4
149+
; CHECK-LLVM: %2 = extractvalue [[structtype_3]] %1, 0
150+
; CHECK-LLVM: %3 = extractvalue [[structtype_3]] %1, 1
151+
; CHECK-LLVM: %4 = icmp ne i64 %3, 0
152+
; CHECK-LLVM: %5 = insertvalue [[structtype_4]] undef, i64 %2, 0
153+
; CHECK-LLVM: %6 = insertvalue [[structtype_4]] %5, i1 %4, 1
154+
; CHECK-LLVM: %7 = extractvalue [[structtype_4]] %6, 0
155+
; CHECK-LLVM: %8 = extractvalue [[structtype_4]] %6, 1
156+
; CHECK-LLVM: ret i1 %8
157+
define spir_func <4 x i1> @test_uadd_with_overflow_v4i32(<4 x i32> %a, <4 x i32> %b) {
43158
entry:
44-
%res = call {<4 x i32>, <4 x i1>} @llvm.uadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
45-
ret void
159+
%res = call {<4 x i32>, <4 x i1>} @llvm.uadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
160+
%0 = extractvalue {<4 x i32>, <4 x i1>} %res, 0
161+
%1 = extractvalue {<4 x i32>, <4 x i1>} %res, 1
162+
ret <4 x i1> %1
46163
}
47164

165+
; CHECK-SPIRV: [[a_2:%[a-z0-9_.]+]] = OpFunctionParameter [[v4uint]]
166+
; CHECK-SPIRV: [[b_2:%[a-z0-9_.]+]] = OpFunctionParameter [[v4uint]]
167+
; CHECK-SPIRV: [[entry_2:%[a-z0-9_.]+]] = OpLabel
168+
; CHECK-SPIRV: [[var_75:%[a-z0-9_.]+]] = OpVariable [[_ptr_Function__struct_73]] Function
169+
; CHECK-SPIRV: [[var_76:%[a-z0-9_.]+]] = OpIAddCarry [[_struct_73]] [[a_2]] [[b_2]]
170+
; CHECK-SPIRV: OpStore [[var_75]] [[var_76]]
171+
; CHECK-SPIRV: [[var_77:%[a-z0-9_.]+]] = OpLoad [[_struct_73]] [[var_75]] Aligned 16
172+
; CHECK-SPIRV: [[var_78:%[a-z0-9_.]+]] = OpCompositeExtract [[v4uint]] [[var_77]] 0
173+
; CHECK-SPIRV: [[var_79:%[a-z0-9_.]+]] = OpCompositeExtract [[v4uint]] [[var_77]] 1
174+
; CHECK-SPIRV: [[var_81:%[a-z0-9_.]+]] = OpINotEqual [[v4bool]] [[var_79]] [[var_80]]
175+
; CHECK-SPIRV: [[var_84:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_82]] [[var_78]] [[var_83]] 0
176+
; CHECK-SPIRV: [[var_85:%[a-z0-9_.]+]] = OpCompositeInsert [[_struct_82]] [[var_81]] [[var_84]] 1
177+
; CHECK-SPIRV: [[var_86:%[a-z0-9_.]+]] = OpCompositeExtract [[v4uint]] [[var_85]] 0
178+
; CHECK-SPIRV: [[var_87:%[a-z0-9_.]+]] = OpCompositeExtract [[v4bool]] [[var_85]] 1
179+
; CHECK-SPIRV: OpReturnValue [[var_87]]
180+
181+
; CHECK-LLVM: %0 = alloca [[structtype_5]], align 16
182+
; CHECK-LLVM: call spir_func void @_Z17__spirv_IAddCarryDv4_iS_(ptr sret([[structtype_5]]) %0, <4 x i32> %a, <4 x i32> %b)
183+
; CHECK-LLVM: %1 = load [[structtype_5]], ptr %0, align 16
184+
; CHECK-LLVM: %2 = extractvalue [[structtype_5]] %1, 0
185+
; CHECK-LLVM: %3 = extractvalue [[structtype_5]] %1, 1
186+
; CHECK-LLVM: %4 = icmp ne <4 x i32> %3, zeroinitializer
187+
; CHECK-LLVM: %5 = insertvalue [[structtype_6]] undef, <4 x i32> %2, 0
188+
; CHECK-LLVM: %6 = insertvalue [[structtype_6]] %5, <4 x i1> %4, 1
189+
; CHECK-LLVM: %7 = extractvalue [[structtype_6]] %6, 0
190+
; CHECK-LLVM: %8 = extractvalue [[structtype_6]] %6, 1
191+
; CHECK-LLVM: ret <4 x i1> %8
48192
declare {i16, i1} @llvm.uadd.with.overflow.i16(i16 %a, i16 %b)
49193
declare {i32, i1} @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
50194
declare {i64, i1} @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
51195
declare {<4 x i32>, <4 x i1>} @llvm.uadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
196+
declare void @_Z17__spirv_IAddCarryii(ptr sret({i32, i32}), i32, i32)

0 commit comments

Comments
 (0)