Skip to content

Commit c75fab2

Browse files
authored
Support SMulExtended and UMulExtended SPIR-V instructions (#2608)
They can be used as SPIR-V friendly calls as there is no obvious mapping to any existing LLVM instruction. The tests are basically copying the ones added in #2392 This change will address the second part of #2302 issue
1 parent 305f488 commit c75fab2

File tree

7 files changed

+343
-13
lines changed

7 files changed

+343
-13
lines changed

lib/SPIRV/SPIRVReader.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2557,6 +2557,14 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
25572557
auto *BC = static_cast<SPIRVBinary *>(BV);
25582558
return mapValue(BV, transBuiltinFromInst("__spirv_ISubBorrow", BC, BB));
25592559
}
2560+
case OpSMulExtended: {
2561+
auto *BC = static_cast<SPIRVBinary *>(BV);
2562+
return mapValue(BV, transBuiltinFromInst("__spirv_SMulExtended", BC, BB));
2563+
}
2564+
case OpUMulExtended: {
2565+
auto *BC = static_cast<SPIRVBinary *>(BV);
2566+
return mapValue(BV, transBuiltinFromInst("__spirv_UMulExtended", BC, BB));
2567+
}
25602568
case OpGetKernelWorkGroupSize:
25612569
case OpGetKernelPreferredWorkGroupSizeMultiple:
25622570
return mapValue(

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6509,18 +6509,13 @@ LLVMToSPIRVBase::transBuiltinToInstWithoutDecoration(Op OC, CallInst *CI,
65096509
return BM->addCompositeConstructInst(transType(CI->getType()), Operands,
65106510
BB);
65116511
}
6512-
case OpIAddCarry: {
6512+
case OpIAddCarry:
6513+
case OpISubBorrow:
6514+
case OpUMulExtended:
6515+
case OpSMulExtended: {
65136516
Function *F = CI->getCalledFunction();
65146517
StructType *St = cast<StructType>(F->getParamStructRetType(0));
6515-
SPIRVValue *V = BM->addBinaryInst(OpIAddCarry, transType(St),
6516-
transValue(CI->getArgOperand(1), BB),
6517-
transValue(CI->getArgOperand(2), BB), BB);
6518-
return BM->addStoreInst(transValue(CI->getArgOperand(0), BB), V, {}, BB);
6519-
}
6520-
case OpISubBorrow: {
6521-
Function *F = CI->getCalledFunction();
6522-
StructType *St = cast<StructType>(F->getParamStructRetType(0));
6523-
SPIRVValue *V = BM->addBinaryInst(OpISubBorrow, transType(St),
6518+
SPIRVValue *V = BM->addBinaryInst(OC, transType(St),
65246519
transValue(CI->getArgOperand(1), BB),
65256520
transValue(CI->getArgOperand(2), BB), BB);
65266521
return BM->addStoreInst(transValue(CI->getArgOperand(0), BB), V, {}, BB);

lib/SPIRV/libSPIRV/SPIRVEntry.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,8 +1056,6 @@ _SPIRV_OP(ImageDrefGather)
10561056
_SPIRV_OP(QuantizeToF16)
10571057
_SPIRV_OP(ArrayLength)
10581058
_SPIRV_OP(OuterProduct)
1059-
_SPIRV_OP(SMulExtended)
1060-
_SPIRV_OP(UMulExtended)
10611059
_SPIRV_OP(DPdx)
10621060
_SPIRV_OP(DPdy)
10631061
_SPIRV_OP(Fwidth)

lib/SPIRV/libSPIRV/SPIRVInstruction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,8 @@ _SPIRV_OP(ISubBorrow)
711711
_SPIRV_OP(FSub)
712712
_SPIRV_OP(IMul)
713713
_SPIRV_OP(FMul)
714+
_SPIRV_OP(SMulExtended)
715+
_SPIRV_OP(UMulExtended)
714716
_SPIRV_OP(UDiv)
715717
_SPIRV_OP(SDiv)
716718
_SPIRV_OP(FDiv)

lib/SPIRV/libSPIRV/SPIRVOpCode.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ inline bool isAtomicOpCode(Op OpCode) {
7171
}
7272
inline bool isBinaryOpCode(Op OpCode) {
7373
return ((unsigned)OpCode >= OpIAdd && (unsigned)OpCode <= OpFMod) ||
74-
OpCode == OpDot || OpCode == OpIAddCarry || OpCode == OpISubBorrow;
74+
OpCode == OpDot || OpCode == OpIAddCarry || OpCode == OpISubBorrow ||
75+
OpCode == OpUMulExtended || OpCode == OpSMulExtended;
7576
}
7677

7778
inline bool isBinaryPtrOpCode(Op OpCode) {

test/smulextended_builtin.ll

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
; REQUIRES: spirv-dis
2+
; RUN: llvm-as %s -o %t.bc
3+
; RUN: llvm-spirv %t.bc -o %t.spv
4+
; RUN: spirv-dis --raw-id %t.spv -o %t.spvasm
5+
; RUN: FileCheck < %t.spvasm --check-prefix CHECK-SPIRV %s
6+
; RUN: spirv-val %t.spv
7+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
8+
; RUN: llvm-dis %t.rev.bc -o - | FileCheck --check-prefix CHECK-LLVM %s
9+
10+
target triple = "spir64-unknown-unknown"
11+
12+
%i8struct = type {i8, i8}
13+
%i16struct = type {i16, i16}
14+
%i32struct = type {i32, i32}
15+
%i64struct = type {i64, i64}
16+
%vecstruct = type {<4 x i32>, <4 x i32>}
17+
%struct.anon = type { i32, i32 }
18+
19+
; CHECK-SPIRV-DAG: [[uchar:%[a-z0-9_]+]] = OpTypeInt 8
20+
; CHECK-SPIRV-DAG: [[ushort:%[a-z0-9_]+]] = OpTypeInt 16
21+
; CHECK-SPIRV-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32
22+
; CHECK-SPIRV-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64
23+
; CHECK-SPIRV-DAG: [[void:%[a-z0-9_]+]] = OpTypeVoid
24+
; CHECK-SPIRV-DAG: [[i8struct:%[a-z0-9_]+]] = OpTypeStruct [[uchar]] [[uchar]]
25+
; CHECK-SPIRV-DAG: [[_ptr_Function_i8struct:%[a-z0-9_]+]] = OpTypePointer Function [[i8struct]]
26+
; CHECK-SPIRV-DAG: [[i16struct:%[a-z0-9_]+]] = OpTypeStruct [[ushort]] [[ushort]]
27+
; CHECK-SPIRV-DAG: [[_ptr_Function_i16struct:%[a-z0-9_]+]] = OpTypePointer Function [[i16struct]]
28+
; CHECK-SPIRV-DAG: [[i32struct:%[a-z0-9_]+]] = OpTypeStruct [[uint]] [[uint]]
29+
; CHECK-SPIRV-DAG: [[_ptr_Function_i32struct:%[a-z0-9_]+]] = OpTypePointer Function [[i32struct]]
30+
; CHECK-SPIRV-DAG: [[i64struct:%[a-z0-9_]+]] = OpTypeStruct [[ulong]] [[ulong]]
31+
; CHECK-SPIRV-DAG: [[_ptr_Function_i64struct:%[a-z0-9_]+]] = OpTypePointer Function [[i64struct]]
32+
; CHECK-SPIRV-DAG: [[v4uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 4
33+
; CHECK-SPIRV-DAG: [[vecstruct:%[a-z0-9_]+]] = OpTypeStruct [[v4uint]] [[v4uint]]
34+
; CHECK-SPIRV-DAG: [[_ptr_Function_vecstruct:%[a-z0-9_]+]] = OpTypePointer Function [[vecstruct]]
35+
; CHECK-SPIRV-DAG: [[struct_anon:%[a-z0-9_.]+]] = OpTypeStruct [[uint]] [[uint]]
36+
; CHECK-SPIRV-DAG: [[_ptr_Function_struct_anon:%[a-z0-9_]+]] = OpTypePointer Function [[struct_anon]]
37+
; CHECK-SPIRV-DAG: [[_ptr_Generic_struct_anon:%[a-z0-9_]+]] = OpTypePointer Generic [[struct_anon]]
38+
39+
; CHECK-LLVM-DAG: [[i8struct:%[a-z0-9_.]+]] = type { i8, i8 }
40+
; CHECK-LLVM-DAG: [[i16struct:%[a-z0-9_.]+]] = type { i16, i16 }
41+
; CHECK-LLVM-DAG: [[i32struct:%[a-z0-9_.]+]] = type { i32, i32 }
42+
; CHECK-LLVM-DAG: [[i64struct:%[a-z0-9_.]+]] = type { i64, i64 }
43+
; CHECK-LLVM-DAG: [[vecstruct:%[a-z0-9_.]+]] = type { <4 x i32>, <4 x i32> }
44+
; CHECK-LLVM-DAG: [[struct_anon:%[a-z0-9_.]+]] = type { i32, i32 }
45+
46+
define spir_func void @test_builtin_smulextcc(i8 %a, i8 %b) {
47+
entry:
48+
%0 = alloca %i8struct
49+
call void @_Z20__spirv_SMulExtendedcc(ptr sret (%i8struct) %0, i8 %a, i8 %b)
50+
ret void
51+
}
52+
; CHECK-SPIRV: [[a:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
53+
; CHECK-SPIRV: [[b:%[a-z0-9_]+]] = OpFunctionParameter [[uchar]]
54+
; CHECK-SPIRV: [[entry:%[a-z0-9_]+]] = OpLabel
55+
; CHECK-SPIRV: [[var_11:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i8struct]] Function
56+
; CHECK-SPIRV: [[var_12:%[a-z0-9_]+]] = OpSMulExtended [[i8struct]] [[a]] [[b]]
57+
; CHECK-SPIRV: OpStore [[var_11]] [[var_12]]
58+
; CHECK-SPIRV: OpReturn
59+
; CHECK-SPIRV: OpFunctionEnd
60+
61+
; CHECK-LLVM: %0 = alloca [[i8struct]], align 8
62+
; CHECK-LLVM: call spir_func void @_Z20__spirv_SMulExtendedcc(ptr sret([[i8struct]]) %0, i8 %a, i8 %b)
63+
; CHECK-LLVM: ret void
64+
define spir_func void @test_builtin_smulextss(i16 %a, i16 %b) {
65+
entry:
66+
%0 = alloca %i16struct
67+
call void @_Z20__spirv_SMulExtendedss(ptr sret (%i16struct) %0, i16 %a, i16 %b)
68+
ret void
69+
}
70+
; CHECK-SPIRV: [[a_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
71+
; CHECK-SPIRV: [[b_0:%[a-z0-9_]+]] = OpFunctionParameter [[ushort]]
72+
; CHECK-SPIRV: [[entry_0:%[a-z0-9_]+]] = OpLabel
73+
; CHECK-SPIRV: [[var_21:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i16struct]] Function
74+
; CHECK-SPIRV: [[var_22:%[a-z0-9_]+]] = OpSMulExtended [[i16struct]] [[a_0]] [[b_0]]
75+
; CHECK-SPIRV: OpStore [[var_21]] [[var_22]]
76+
; CHECK-SPIRV: OpReturn
77+
; CHECK-SPIRV: OpFunctionEnd
78+
79+
; CHECK-LLVM: %0 = alloca [[i16struct]], align 8
80+
; CHECK-LLVM: call spir_func void @_Z20__spirv_SMulExtendedss(ptr sret([[i16struct]]) %0, i16 %a, i16 %b)
81+
; CHECK-LLVM: ret void
82+
define spir_func void @test_builtin_smulextii(i32 %a, i32 %b) {
83+
entry:
84+
%0 = alloca %i32struct
85+
call void @_Z20__spirv_SMulExtendedii(ptr sret (%i32struct) %0, i32 %a, i32 %b)
86+
ret void
87+
}
88+
; CHECK-SPIRV: [[a_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
89+
; CHECK-SPIRV: [[b_1:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
90+
; CHECK-SPIRV: [[entry_1:%[a-z0-9_]+]] = OpLabel
91+
; CHECK-SPIRV: [[var_31:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i32struct]] Function
92+
; CHECK-SPIRV: [[var_32:%[a-z0-9_]+]] = OpSMulExtended [[i32struct]] [[a_1]] [[b_1]]
93+
; CHECK-SPIRV: OpStore [[var_31]] [[var_32]]
94+
; CHECK-SPIRV: OpReturn
95+
; CHECK-SPIRV: OpFunctionEnd
96+
97+
; CHECK-LLVM: %0 = alloca [[i32struct]], align 8
98+
; CHECK-LLVM: call spir_func void @_Z20__spirv_SMulExtendedii(ptr sret([[i32struct]]) %0, i32 %a, i32 %b)
99+
; CHECK-LLVM: ret void
100+
define spir_func void @test_builtin_smulextll(i64 %a, i64 %b) {
101+
entry:
102+
%0 = alloca %i64struct
103+
call void @_Z20__spirv_SMulExtendedll(ptr sret (%i64struct) %0, i64 %a, i64 %b)
104+
ret void
105+
}
106+
; CHECK-SPIRV: [[a_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
107+
; CHECK-SPIRV: [[b_2:%[a-z0-9_]+]] = OpFunctionParameter [[ulong]]
108+
; CHECK-SPIRV: [[entry_2:%[a-z0-9_]+]] = OpLabel
109+
; CHECK-SPIRV: [[var_41:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_i64struct]] Function
110+
; CHECK-SPIRV: [[var_42:%[a-z0-9_]+]] = OpSMulExtended [[i64struct]] [[a_2]] [[b_2]]
111+
; CHECK-SPIRV: OpStore [[var_41]] [[var_42]]
112+
; CHECK-SPIRV: OpReturn
113+
; CHECK-SPIRV: OpFunctionEnd
114+
115+
; CHECK-LLVM: %0 = alloca [[i64struct]]
116+
; CHECK-LLVM: call spir_func void @_Z20__spirv_SMulExtendedll(ptr sret([[i64struct]]) %0, i64 %a, i64 %b)
117+
; CHECK-LLVM: ret void
118+
define spir_func void @test_builtin_smulextDv4_xS_(<4 x i32> %a, <4 x i32> %b) {
119+
entry:
120+
%0 = alloca %vecstruct
121+
call void @_Z20__spirv_SMulExtendedDv4_iS_(ptr sret (%vecstruct) %0, <4 x i32> %a, <4 x i32> %b)
122+
ret void
123+
}
124+
; CHECK-SPIRV: [[a_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
125+
; CHECK-SPIRV: [[b_3:%[a-z0-9_]+]] = OpFunctionParameter [[v4uint]]
126+
; CHECK-SPIRV: [[entry_3:%[a-z0-9_]+]] = OpLabel
127+
; CHECK-SPIRV: [[var_51:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_vecstruct]] Function
128+
; CHECK-SPIRV: [[var_52:%[a-z0-9_]+]] = OpSMulExtended [[vecstruct]] [[a_3]] [[b_3]]
129+
; CHECK-SPIRV: OpStore [[var_51]] [[var_52]]
130+
; CHECK-SPIRV: OpReturn
131+
; CHECK-SPIRV: OpFunctionEnd
132+
133+
; CHECK-LLVM: %0 = alloca [[vecstruct]]
134+
; CHECK-LLVM: call spir_func void @_Z20__spirv_SMulExtendedDv4_iS_(ptr sret([[vecstruct]]) %0, <4 x i32> %a, <4 x i32> %b)
135+
; CHECK-LLVM: ret void
136+
137+
138+
define spir_func void @test_builtin_smulext_anon(i32 %a, i32 %b) {
139+
entry:
140+
%0 = alloca %struct.anon
141+
%1 = addrspacecast ptr %0 to ptr addrspace(4)
142+
call spir_func void @_Z20__spirv_SMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4 %1, i32 %a, i32 %b)
143+
ret void
144+
}
145+
; CHECK-SPIRV: [[a_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
146+
; CHECK-SPIRV: [[b_4:%[a-z0-9_]+]] = OpFunctionParameter [[uint]]
147+
; CHECK-SPIRV: [[entry_4:%[a-z0-9_]+]] = OpLabel
148+
; CHECK-SPIRV: [[var_59:%[a-z0-9_]+]] = OpVariable [[_ptr_Function_struct_anon]] Function
149+
; CHECK-SPIRV: [[var_61:%[a-z0-9_]+]] = OpPtrCastToGeneric [[_ptr_Generic_struct_anon]] [[var_59]]
150+
; CHECK-SPIRV: [[var_62:%[a-z0-9_]+]] = OpSMulExtended [[struct_anon]] [[a_4]] [[b_4]]
151+
; CHECK-SPIRV: OpStore [[var_61]] [[var_62]]
152+
153+
; CHECK-LLVM: %0 = alloca [[struct_anon]], align 8
154+
; CHECK-LLVM: %1 = addrspacecast ptr %0 to ptr addrspace(4)
155+
; CHECK-LLVM: call spir_func void @_Z20__spirv_SMulExtendedii.1(ptr addrspace(4) sret([[struct_anon]]) %1, i32 %a, i32 %b)
156+
; CHECK-LLVM: ret void
157+
158+
declare void @_Z20__spirv_SMulExtendedIiiE4anonIT_T0_ES1_S2_(ptr addrspace(4) sret(%struct.anon) align 4, i32, i32)
159+
declare void @_Z20__spirv_SMulExtendedcc(ptr sret(%i8struct), i8, i8)
160+
declare void @_Z20__spirv_SMulExtendedss(ptr sret(%i16struct), i16, i16)
161+
declare void @_Z20__spirv_SMulExtendedii(ptr sret(%i32struct), i32, i32)
162+
declare void @_Z20__spirv_SMulExtendedll(ptr sret(%i64struct), i64, i64)
163+
declare void @_Z20__spirv_SMulExtendedDv4_iS_(ptr sret (%vecstruct), <4 x i32>, <4 x i32>)

0 commit comments

Comments
 (0)