Skip to content

Commit 5440c10

Browse files
bwlodarczsys-ce-bb
authored andcommitted
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. Original commit: KhronosGroup/SPIRV-LLVM-Translator@98729ef13ca970b
1 parent ba57ab0 commit 5440c10

File tree

3 files changed

+425
-54
lines changed

3 files changed

+425
-54
lines changed

llvm-spirv/lib/SPIRV/SPIRVRegularizeLLVM.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,70 @@ static void simplifyBuiltinVarAccesses(GlobalValue *GV) {
391391
}
392392
}
393393

394+
namespace {
395+
void regularizeWithOverflowInstrinsics(StringRef MangledName, CallInst *Call,
396+
Module *M,
397+
std::vector<Instruction *> &ToErase) {
398+
IRBuilder Builder(Call);
399+
Function *Builtin = Call->getModule()->getFunction(MangledName);
400+
AllocaInst *A;
401+
StructType *StructBuiltinTy;
402+
if (Builtin) {
403+
StructBuiltinTy = cast<StructType>(Builtin->getParamStructRetType(0));
404+
{
405+
IRBuilderBase::InsertPointGuard Guard(Builder);
406+
Builder.SetInsertPointPastAllocas(Call->getParent()->getParent());
407+
A = Builder.CreateAlloca(StructBuiltinTy);
408+
}
409+
CallInst *C = Builder.CreateCall(
410+
Builtin, {A, Call->getArgOperand(0), Call->getArgOperand(1)});
411+
auto SretAttr = Attribute::get(
412+
Builder.getContext(), Attribute::AttrKind::StructRet, StructBuiltinTy);
413+
C->addParamAttr(0, SretAttr);
414+
} else {
415+
StructBuiltinTy = StructType::create(
416+
Call->getContext(),
417+
{Call->getArgOperand(0)->getType(), Call->getArgOperand(1)->getType()});
418+
{
419+
IRBuilderBase::InsertPointGuard Guard(Builder);
420+
Builder.SetInsertPointPastAllocas(Call->getParent()->getParent());
421+
A = Builder.CreateAlloca(StructBuiltinTy);
422+
}
423+
FunctionType *FT =
424+
FunctionType::get(Builder.getVoidTy(),
425+
{A->getType(), Call->getArgOperand(0)->getType(),
426+
Call->getArgOperand(1)->getType()},
427+
false);
428+
Builtin =
429+
Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M);
430+
Builtin->setCallingConv(CallingConv::SPIR_FUNC);
431+
Builtin->addFnAttr(Attribute::NoUnwind);
432+
auto SretAttr = Attribute::get(
433+
Builder.getContext(), Attribute::AttrKind::StructRet, StructBuiltinTy);
434+
Builtin->addParamAttr(0, SretAttr);
435+
CallInst *C = Builder.CreateCall(
436+
Builtin, {A, Call->getArgOperand(0), Call->getArgOperand(1)});
437+
C->addParamAttr(0, SretAttr);
438+
}
439+
Type *RetTy = Call->getArgOperand(0)->getType();
440+
Constant *ConstZero = ConstantInt::get(RetTy, 0);
441+
Value *L = Builder.CreateLoad(StructBuiltinTy, A);
442+
Value *V0 = Builder.CreateExtractValue(L, {0});
443+
Value *V1 = Builder.CreateExtractValue(L, {1});
444+
Value *V2 = Builder.CreateICmpNE(V1, ConstZero);
445+
Type *StructI32I1Ty =
446+
StructType::create(Call->getContext(), {RetTy, V2->getType()});
447+
Value *Undef = UndefValue::get(StructI32I1Ty);
448+
Value *V3 = Builder.CreateInsertValue(Undef, V0, {0});
449+
Value *V4 = Builder.CreateInsertValue(V3, V2, {1});
450+
SmallVector<User *> Users(Call->users());
451+
for (User *U : Users) {
452+
U->replaceUsesOfWith(Call, V4);
453+
}
454+
ToErase.push_back(Call);
455+
}
456+
} // namespace
457+
394458
/// Remove entities not representable by SPIR-V
395459
bool SPIRVRegularizeLLVMBase::regularize() {
396460
eraseUselessFunctions(M);
@@ -430,6 +494,23 @@ bool SPIRVRegularizeLLVMBase::regularize() {
430494
lowerFunnelShift(II);
431495
else if (II->getIntrinsicID() == Intrinsic::umul_with_overflow)
432496
lowerUMulWithOverflow(II);
497+
else if (II->getIntrinsicID() == Intrinsic::uadd_with_overflow) {
498+
BuiltinFuncMangleInfo Info;
499+
std::string MangledName =
500+
mangleBuiltin("__spirv_IAddCarry",
501+
{Call->getArgOperand(0)->getType(),
502+
Call->getArgOperand(1)->getType()},
503+
&Info);
504+
regularizeWithOverflowInstrinsics(MangledName, Call, M, ToErase);
505+
} else if (II->getIntrinsicID() == Intrinsic::usub_with_overflow) {
506+
BuiltinFuncMangleInfo Info;
507+
std::string MangledName =
508+
mangleBuiltin("__spirv_ISubBorrow",
509+
{Call->getArgOperand(0)->getType(),
510+
Call->getArgOperand(1)->getType()},
511+
&Info);
512+
regularizeWithOverflowInstrinsics(MangledName, Call, M, ToErase);
513+
}
433514
}
434515
}
435516

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)