1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <string>
16 #include <vector>
17
18 #include "gmock/gmock.h"
19 #include "source/latest_version_opencl_std_header.h"
20 #include "source/util/string_utils.h"
21 #include "test/test_fixture.h"
22 #include "test/unit_spirv.h"
23
24 namespace spvtools {
25 namespace {
26
27 using spvtest::Concatenate;
28 using spvtest::MakeInstruction;
29 using utils::MakeVector;
30 using spvtest::TextToBinaryTest;
31 using testing::Eq;
32
33 struct InstructionCase {
34 uint32_t opcode;
35 std::string name;
36 std::string operands;
37 std::vector<uint32_t> expected_operands;
38 };
39
40 using ExtInstOpenCLStdRoundTripTest =
41 spvtest::TextToBinaryTestBase<::testing::TestWithParam<InstructionCase>>;
42
TEST_P(ExtInstOpenCLStdRoundTripTest,ParameterizedExtInst)43 TEST_P(ExtInstOpenCLStdRoundTripTest, ParameterizedExtInst) {
44 // This example should not validate.
45 const std::string input =
46 "%1 = OpExtInstImport \"OpenCL.std\"\n"
47 "%3 = OpExtInst %2 %1 " +
48 GetParam().name + " " + GetParam().operands + "\n";
49 // First make sure it assembles correctly.
50 EXPECT_THAT(CompiledInstructions(input),
51 Eq(Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
52 MakeVector("OpenCL.std")),
53 MakeInstruction(spv::Op::OpExtInst,
54 {2, 3, 1, GetParam().opcode},
55 GetParam().expected_operands)})))
56 << input;
57 // Now check the round trip through the disassembler.
58 EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input) << input;
59 }
60
61 #define CASE1(Enum, Name) \
62 { \
63 uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4", { 4 } \
64 }
65 #define CASE2(Enum, Name) \
66 { \
67 uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5", { 4, 5 } \
68 }
69 #define CASE3(Enum, Name) \
70 { \
71 uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6", { 4, 5, 6 } \
72 }
73 #define CASE4(Enum, Name) \
74 { \
75 uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6 %7", { \
76 4, 5, 6, 7 \
77 } \
78 }
79 #define CASE2Lit(Enum, Name, LiteralNumber) \
80 { \
81 uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 " #LiteralNumber, { \
82 4, 5, LiteralNumber \
83 } \
84 }
85 #define CASE3Round(Enum, Name, Mode) \
86 { \
87 uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6 " #Mode, { \
88 4, 5, 6, uint32_t(spv::FPRoundingMode::Mode) \
89 } \
90 }
91
92 // clang-format off
93 // OpenCL.std: 2.1 Math extended instructions
94 INSTANTIATE_TEST_SUITE_P(
95 OpenCLMath, ExtInstOpenCLStdRoundTripTest,
96 ::testing::ValuesIn(std::vector<InstructionCase>({
97 // We are only testing the correctness of encoding and decoding here.
98 // Semantic correctness should be the responsibility of validator.
99 CASE1(Acos, acos), // enum value 0
100 CASE1(Acosh, acosh),
101 CASE1(Acospi, acospi),
102 CASE1(Asin, asin),
103 CASE1(Asinh, asinh),
104 CASE1(Asinh, asinh),
105 CASE1(Asinpi, asinpi),
106 CASE1(Atan, atan),
107 CASE2(Atan2, atan2),
108 CASE1(Atanh, atanh),
109 CASE1(Atanpi, atanpi),
110 CASE2(Atan2pi, atan2pi),
111 CASE1(Cbrt, cbrt),
112 CASE1(Ceil, ceil),
113 CASE1(Ceil, ceil),
114 CASE2(Copysign, copysign),
115 CASE1(Cos, cos),
116 CASE1(Cosh, cosh),
117 CASE1(Cospi, cospi),
118 CASE1(Erfc, erfc),
119 CASE1(Erf, erf),
120 CASE1(Exp, exp),
121 CASE1(Exp2, exp2),
122 CASE1(Exp10, exp10),
123 CASE1(Expm1, expm1),
124 CASE1(Fabs, fabs),
125 CASE2(Fdim, fdim),
126 CASE1(Floor, floor),
127 CASE3(Fma, fma),
128 CASE2(Fmax, fmax),
129 CASE2(Fmin, fmin),
130 CASE2(Fmod, fmod),
131 CASE2(Fract, fract),
132 CASE2(Frexp, frexp),
133 CASE2(Hypot, hypot),
134 CASE1(Ilogb, ilogb),
135 CASE2(Ldexp, ldexp),
136 CASE1(Lgamma, lgamma),
137 CASE2(Lgamma_r, lgamma_r),
138 CASE1(Log, log),
139 CASE1(Log2, log2),
140 CASE1(Log10, log10),
141 CASE1(Log1p, log1p),
142 CASE3(Mad, mad),
143 CASE2(Maxmag, maxmag),
144 CASE2(Minmag, minmag),
145 CASE2(Modf, modf),
146 CASE1(Nan, nan),
147 CASE2(Nextafter, nextafter),
148 CASE2(Pow, pow),
149 CASE2(Pown, pown),
150 CASE2(Powr, powr),
151 CASE2(Remainder, remainder),
152 CASE3(Remquo, remquo),
153 CASE1(Rint, rint),
154 CASE2(Rootn, rootn),
155 CASE1(Round, round),
156 CASE1(Rsqrt, rsqrt),
157 CASE1(Sin, sin),
158 CASE2(Sincos, sincos),
159 CASE1(Sinh, sinh),
160 CASE1(Sinpi, sinpi),
161 CASE1(Sqrt, sqrt),
162 CASE1(Tan, tan),
163 CASE1(Tanh, tanh),
164 CASE1(Tanpi, tanpi),
165 CASE1(Tgamma, tgamma),
166 CASE1(Trunc, trunc),
167 CASE1(Half_cos, half_cos),
168 CASE2(Half_divide, half_divide),
169 CASE1(Half_exp, half_exp),
170 CASE1(Half_exp2, half_exp2),
171 CASE1(Half_exp10, half_exp10),
172 CASE1(Half_log, half_log),
173 CASE1(Half_log2, half_log2),
174 CASE1(Half_log10, half_log10),
175 CASE2(Half_powr, half_powr),
176 CASE1(Half_recip, half_recip),
177 CASE1(Half_rsqrt, half_rsqrt),
178 CASE1(Half_sin, half_sin),
179 CASE1(Half_sqrt, half_sqrt),
180 CASE1(Half_tan, half_tan),
181 CASE1(Native_cos, native_cos),
182 CASE2(Native_divide, native_divide),
183 CASE1(Native_exp, native_exp),
184 CASE1(Native_exp2, native_exp2),
185 CASE1(Native_exp10, native_exp10),
186 CASE1(Native_log, native_log),
187 CASE1(Native_log10, native_log10),
188 CASE2(Native_powr, native_powr),
189 CASE1(Native_recip, native_recip),
190 CASE1(Native_rsqrt, native_rsqrt),
191 CASE1(Native_sin, native_sin),
192 CASE1(Native_sqrt, native_sqrt),
193 CASE1(Native_tan, native_tan), // enum value 94
194 })));
195
196 // OpenCL.std: 2.1 Integer instructions
197 INSTANTIATE_TEST_SUITE_P(
198 OpenCLInteger, ExtInstOpenCLStdRoundTripTest,
199 ::testing::ValuesIn(std::vector<InstructionCase>({
200 CASE1(SAbs, s_abs), // enum value 141
201 CASE2(SAbs_diff, s_abs_diff),
202 CASE2(SAdd_sat, s_add_sat),
203 CASE2(UAdd_sat, u_add_sat),
204 CASE2(SHadd, s_hadd),
205 CASE2(UHadd, u_hadd),
206 CASE2(SRhadd, s_rhadd),
207 CASE2(SRhadd, s_rhadd),
208 CASE3(SClamp, s_clamp),
209 CASE3(UClamp, u_clamp),
210 CASE1(Clz, clz),
211 CASE1(Ctz, ctz),
212 CASE3(SMad_hi, s_mad_hi),
213 CASE3(UMad_sat, u_mad_sat),
214 CASE3(SMad_sat, s_mad_sat),
215 CASE2(SMax, s_max),
216 CASE2(UMax, u_max),
217 CASE2(SMin, s_min),
218 CASE2(UMin, u_min),
219 CASE2(SMul_hi, s_mul_hi),
220 CASE2(Rotate, rotate),
221 CASE2(SSub_sat, s_sub_sat),
222 CASE2(USub_sat, u_sub_sat),
223 CASE2(U_Upsample, u_upsample),
224 CASE2(S_Upsample, s_upsample),
225 CASE1(Popcount, popcount),
226 CASE3(SMad24, s_mad24),
227 CASE3(UMad24, u_mad24),
228 CASE2(SMul24, s_mul24),
229 CASE2(UMul24, u_mul24), // enum value 170
230 CASE1(UAbs, u_abs), // enum value 201
231 CASE2(UAbs_diff, u_abs_diff),
232 CASE2(UMul_hi, u_mul_hi),
233 CASE3(UMad_hi, u_mad_hi), // enum value 204
234 })));
235
236 // OpenCL.std: 2.3 Common instructions
237 INSTANTIATE_TEST_SUITE_P(
238 OpenCLCommon, ExtInstOpenCLStdRoundTripTest,
239 ::testing::ValuesIn(std::vector<InstructionCase>({
240 CASE3(FClamp, fclamp), // enum value 95
241 CASE1(Degrees, degrees),
242 CASE2(FMax_common, fmax_common),
243 CASE2(FMin_common, fmin_common),
244 CASE3(Mix, mix),
245 CASE1(Radians, radians),
246 CASE2(Step, step),
247 CASE3(Smoothstep, smoothstep),
248 CASE1(Sign, sign), // enum value 103
249 })));
250
251 // OpenCL.std: 2.4 Geometric instructions
252 INSTANTIATE_TEST_SUITE_P(
253 OpenCLGeometric, ExtInstOpenCLStdRoundTripTest,
254 ::testing::ValuesIn(std::vector<InstructionCase>({
255 CASE2(Cross, cross), // enum value 104
256 CASE2(Distance, distance),
257 CASE1(Length, length),
258 CASE1(Normalize, normalize),
259 CASE2(Fast_distance, fast_distance),
260 CASE1(Fast_length, fast_length),
261 CASE1(Fast_normalize, fast_normalize), // enum value 110
262 })));
263
264 // OpenCL.std: 2.5 Relational instructions
265 INSTANTIATE_TEST_SUITE_P(
266 OpenCLRelational, ExtInstOpenCLStdRoundTripTest,
267 ::testing::ValuesIn(std::vector<InstructionCase>({
268 CASE3(Bitselect, bitselect), // enum value 186
269 CASE3(Select, select), // enum value 187
270 })));
271
272 // OpenCL.std: 2.6 Vector data load and store instructions
273 INSTANTIATE_TEST_SUITE_P(
274 OpenCLVectorLoadStore, ExtInstOpenCLStdRoundTripTest,
275 ::testing::ValuesIn(std::vector<InstructionCase>({
276 // The last argument to Vloadn must be one of 2, 3, 4, 8, 16.
277 CASE2Lit(Vloadn, vloadn, 2),
278 CASE2Lit(Vloadn, vloadn, 3),
279 CASE2Lit(Vloadn, vloadn, 4),
280 CASE2Lit(Vloadn, vloadn, 8),
281 CASE2Lit(Vloadn, vloadn, 16),
282 CASE3(Vstoren, vstoren),
283 CASE2(Vload_half, vload_half),
284 CASE2Lit(Vload_halfn, vload_halfn, 2),
285 CASE2Lit(Vload_halfn, vload_halfn, 3),
286 CASE2Lit(Vload_halfn, vload_halfn, 4),
287 CASE2Lit(Vload_halfn, vload_halfn, 8),
288 CASE2Lit(Vload_halfn, vload_halfn, 16),
289 CASE3(Vstore_half, vstore_half),
290 // Try all the rounding modes.
291 CASE3Round(Vstore_half_r, vstore_half_r, RTE),
292 CASE3Round(Vstore_half_r, vstore_half_r, RTZ),
293 CASE3Round(Vstore_half_r, vstore_half_r, RTP),
294 CASE3Round(Vstore_half_r, vstore_half_r, RTN),
295 CASE3(Vstore_halfn, vstore_halfn),
296 CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTE),
297 CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTZ),
298 CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTP),
299 CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTN),
300 CASE2Lit(Vloada_halfn, vloada_halfn, 2),
301 CASE2Lit(Vloada_halfn, vloada_halfn, 3),
302 CASE2Lit(Vloada_halfn, vloada_halfn, 4),
303 CASE2Lit(Vloada_halfn, vloada_halfn, 8),
304 CASE2Lit(Vloada_halfn, vloada_halfn, 16),
305 CASE3(Vstorea_halfn, vstorea_halfn),
306 CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTE),
307 CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTZ),
308 CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTP),
309 CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTN),
310 })));
311
312 // OpenCL.std: 2.7 Miscellaneous vector instructions
313 INSTANTIATE_TEST_SUITE_P(
314 OpenCLMiscellaneousVector, ExtInstOpenCLStdRoundTripTest,
315 ::testing::ValuesIn(std::vector<InstructionCase>({
316 CASE2(Shuffle, shuffle),
317 CASE3(Shuffle2, shuffle2),
318 })));
319
320 // OpenCL.std: 2.8 Miscellaneous instructions
321
322 #define PREFIX uint32_t(OpenCLLIB::Entrypoints::Printf), "printf"
323 INSTANTIATE_TEST_SUITE_P(
324 OpenCLMiscPrintf, ExtInstOpenCLStdRoundTripTest,
325 ::testing::ValuesIn(std::vector<InstructionCase>({
326 // Printf is interesting because it takes a variable number of arguments.
327 // Start with zero optional arguments.
328 {PREFIX, "%4", {4}},
329 {PREFIX, "%4 %5", {4, 5}},
330 {PREFIX, "%4 %5 %6", {4, 5, 6}},
331 {PREFIX, "%4 %5 %6 %7", {4, 5, 6, 7}},
332 {PREFIX, "%4 %5 %6 %7 %8", {4, 5, 6, 7, 8}},
333 {PREFIX, "%4 %5 %6 %7 %8 %9", {4, 5, 6, 7, 8, 9}},
334 {PREFIX, "%4 %5 %6 %7 %8 %9 %10", {4, 5, 6, 7, 8, 9, 10}},
335 {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11", {4, 5, 6, 7, 8, 9, 10, 11}},
336 {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12",
337 {4, 5, 6, 7, 8, 9, 10, 11, 12}},
338 {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12 %13",
339 {4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
340 {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14",
341 {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}},
342 })));
343 #undef PREFIX
344
345 INSTANTIATE_TEST_SUITE_P(
346 OpenCLMiscPrefetch, ExtInstOpenCLStdRoundTripTest,
347 ::testing::ValuesIn(std::vector<InstructionCase>({
348 CASE2(Prefetch, prefetch),
349 })));
350
351 // OpenCL.std: 2.9.1 Image encoding
352 // No new instructions defined in this section.
353
354 // OpenCL.std: 2.9.2 Sampler encoding
355 // No new instructions defined in this section.
356
357 // OpenCL.std: 2.9.3 Image read
358 // No new instructions defined in this section.
359 // Use core instruction OpImageSampleExplicitLod instead.
360
361 // OpenCL.std: 2.9.4 Image write
362 // No new instructions defined in this section.
363
364 // clang-format on
365
366 #undef CASE1
367 #undef CASE2
368 #undef CASE3
369 #undef CASE4
370 #undef CASE2Lit
371 #undef CASE3Round
372
373 } // namespace
374 } // namespace spvtools
375