| // Copyright (c) 2015-2016 The Khronos Group Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <string> |
| #include <vector> |
| |
| #include "gmock/gmock.h" |
| #include "source/latest_version_opencl_std_header.h" |
| #include "source/util/string_utils.h" |
| #include "test/test_fixture.h" |
| #include "test/unit_spirv.h" |
| |
| namespace spvtools { |
| namespace { |
| |
| using spvtest::Concatenate; |
| using spvtest::MakeInstruction; |
| using utils::MakeVector; |
| using spvtest::TextToBinaryTest; |
| using testing::Eq; |
| |
| struct InstructionCase { |
| uint32_t opcode; |
| std::string name; |
| std::string operands; |
| std::vector<uint32_t> expected_operands; |
| }; |
| |
| using ExtInstOpenCLStdRoundTripTest = |
| spvtest::TextToBinaryTestBase<::testing::TestWithParam<InstructionCase>>; |
| |
| TEST_P(ExtInstOpenCLStdRoundTripTest, ParameterizedExtInst) { |
| // This example should not validate. |
| const std::string input = |
| "%1 = OpExtInstImport \"OpenCL.std\"\n" |
| "%3 = OpExtInst %2 %1 " + |
| GetParam().name + " " + GetParam().operands + "\n"; |
| // First make sure it assembles correctly. |
| EXPECT_THAT(CompiledInstructions(input), |
| Eq(Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1}, |
| MakeVector("OpenCL.std")), |
| MakeInstruction(spv::Op::OpExtInst, |
| {2, 3, 1, GetParam().opcode}, |
| GetParam().expected_operands)}))) |
| << input; |
| // Now check the round trip through the disassembler. |
| EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input) << input; |
| } |
| |
| #define CASE1(Enum, Name) \ |
| { \ |
| uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4", { 4 } \ |
| } |
| #define CASE2(Enum, Name) \ |
| { \ |
| uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5", { 4, 5 } \ |
| } |
| #define CASE3(Enum, Name) \ |
| { \ |
| uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6", { 4, 5, 6 } \ |
| } |
| #define CASE4(Enum, Name) \ |
| { \ |
| uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6 %7", { \ |
| 4, 5, 6, 7 \ |
| } \ |
| } |
| #define CASE2Lit(Enum, Name, LiteralNumber) \ |
| { \ |
| uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 " #LiteralNumber, { \ |
| 4, 5, LiteralNumber \ |
| } \ |
| } |
| #define CASE3Round(Enum, Name, Mode) \ |
| { \ |
| uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6 " #Mode, { \ |
| 4, 5, 6, uint32_t(spv::FPRoundingMode::Mode) \ |
| } \ |
| } |
| |
| // clang-format off |
| // OpenCL.std: 2.1 Math extended instructions |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLMath, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| // We are only testing the correctness of encoding and decoding here. |
| // Semantic correctness should be the responsibility of validator. |
| CASE1(Acos, acos), // enum value 0 |
| CASE1(Acosh, acosh), |
| CASE1(Acospi, acospi), |
| CASE1(Asin, asin), |
| CASE1(Asinh, asinh), |
| CASE1(Asinh, asinh), |
| CASE1(Asinpi, asinpi), |
| CASE1(Atan, atan), |
| CASE2(Atan2, atan2), |
| CASE1(Atanh, atanh), |
| CASE1(Atanpi, atanpi), |
| CASE2(Atan2pi, atan2pi), |
| CASE1(Cbrt, cbrt), |
| CASE1(Ceil, ceil), |
| CASE1(Ceil, ceil), |
| CASE2(Copysign, copysign), |
| CASE1(Cos, cos), |
| CASE1(Cosh, cosh), |
| CASE1(Cospi, cospi), |
| CASE1(Erfc, erfc), |
| CASE1(Erf, erf), |
| CASE1(Exp, exp), |
| CASE1(Exp2, exp2), |
| CASE1(Exp10, exp10), |
| CASE1(Expm1, expm1), |
| CASE1(Fabs, fabs), |
| CASE2(Fdim, fdim), |
| CASE1(Floor, floor), |
| CASE3(Fma, fma), |
| CASE2(Fmax, fmax), |
| CASE2(Fmin, fmin), |
| CASE2(Fmod, fmod), |
| CASE2(Fract, fract), |
| CASE2(Frexp, frexp), |
| CASE2(Hypot, hypot), |
| CASE1(Ilogb, ilogb), |
| CASE2(Ldexp, ldexp), |
| CASE1(Lgamma, lgamma), |
| CASE2(Lgamma_r, lgamma_r), |
| CASE1(Log, log), |
| CASE1(Log2, log2), |
| CASE1(Log10, log10), |
| CASE1(Log1p, log1p), |
| CASE3(Mad, mad), |
| CASE2(Maxmag, maxmag), |
| CASE2(Minmag, minmag), |
| CASE2(Modf, modf), |
| CASE1(Nan, nan), |
| CASE2(Nextafter, nextafter), |
| CASE2(Pow, pow), |
| CASE2(Pown, pown), |
| CASE2(Powr, powr), |
| CASE2(Remainder, remainder), |
| CASE3(Remquo, remquo), |
| CASE1(Rint, rint), |
| CASE2(Rootn, rootn), |
| CASE1(Round, round), |
| CASE1(Rsqrt, rsqrt), |
| CASE1(Sin, sin), |
| CASE2(Sincos, sincos), |
| CASE1(Sinh, sinh), |
| CASE1(Sinpi, sinpi), |
| CASE1(Sqrt, sqrt), |
| CASE1(Tan, tan), |
| CASE1(Tanh, tanh), |
| CASE1(Tanpi, tanpi), |
| CASE1(Tgamma, tgamma), |
| CASE1(Trunc, trunc), |
| CASE1(Half_cos, half_cos), |
| CASE2(Half_divide, half_divide), |
| CASE1(Half_exp, half_exp), |
| CASE1(Half_exp2, half_exp2), |
| CASE1(Half_exp10, half_exp10), |
| CASE1(Half_log, half_log), |
| CASE1(Half_log2, half_log2), |
| CASE1(Half_log10, half_log10), |
| CASE2(Half_powr, half_powr), |
| CASE1(Half_recip, half_recip), |
| CASE1(Half_rsqrt, half_rsqrt), |
| CASE1(Half_sin, half_sin), |
| CASE1(Half_sqrt, half_sqrt), |
| CASE1(Half_tan, half_tan), |
| CASE1(Native_cos, native_cos), |
| CASE2(Native_divide, native_divide), |
| CASE1(Native_exp, native_exp), |
| CASE1(Native_exp2, native_exp2), |
| CASE1(Native_exp10, native_exp10), |
| CASE1(Native_log, native_log), |
| CASE1(Native_log10, native_log10), |
| CASE2(Native_powr, native_powr), |
| CASE1(Native_recip, native_recip), |
| CASE1(Native_rsqrt, native_rsqrt), |
| CASE1(Native_sin, native_sin), |
| CASE1(Native_sqrt, native_sqrt), |
| CASE1(Native_tan, native_tan), // enum value 94 |
| }))); |
| |
| // OpenCL.std: 2.1 Integer instructions |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLInteger, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| CASE1(SAbs, s_abs), // enum value 141 |
| CASE2(SAbs_diff, s_abs_diff), |
| CASE2(SAdd_sat, s_add_sat), |
| CASE2(UAdd_sat, u_add_sat), |
| CASE2(SHadd, s_hadd), |
| CASE2(UHadd, u_hadd), |
| CASE2(SRhadd, s_rhadd), |
| CASE2(SRhadd, s_rhadd), |
| CASE3(SClamp, s_clamp), |
| CASE3(UClamp, u_clamp), |
| CASE1(Clz, clz), |
| CASE1(Ctz, ctz), |
| CASE3(SMad_hi, s_mad_hi), |
| CASE3(UMad_sat, u_mad_sat), |
| CASE3(SMad_sat, s_mad_sat), |
| CASE2(SMax, s_max), |
| CASE2(UMax, u_max), |
| CASE2(SMin, s_min), |
| CASE2(UMin, u_min), |
| CASE2(SMul_hi, s_mul_hi), |
| CASE2(Rotate, rotate), |
| CASE2(SSub_sat, s_sub_sat), |
| CASE2(USub_sat, u_sub_sat), |
| CASE2(U_Upsample, u_upsample), |
| CASE2(S_Upsample, s_upsample), |
| CASE1(Popcount, popcount), |
| CASE3(SMad24, s_mad24), |
| CASE3(UMad24, u_mad24), |
| CASE2(SMul24, s_mul24), |
| CASE2(UMul24, u_mul24), // enum value 170 |
| CASE1(UAbs, u_abs), // enum value 201 |
| CASE2(UAbs_diff, u_abs_diff), |
| CASE2(UMul_hi, u_mul_hi), |
| CASE3(UMad_hi, u_mad_hi), // enum value 204 |
| }))); |
| |
| // OpenCL.std: 2.3 Common instructions |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLCommon, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| CASE3(FClamp, fclamp), // enum value 95 |
| CASE1(Degrees, degrees), |
| CASE2(FMax_common, fmax_common), |
| CASE2(FMin_common, fmin_common), |
| CASE3(Mix, mix), |
| CASE1(Radians, radians), |
| CASE2(Step, step), |
| CASE3(Smoothstep, smoothstep), |
| CASE1(Sign, sign), // enum value 103 |
| }))); |
| |
| // OpenCL.std: 2.4 Geometric instructions |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLGeometric, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| CASE2(Cross, cross), // enum value 104 |
| CASE2(Distance, distance), |
| CASE1(Length, length), |
| CASE1(Normalize, normalize), |
| CASE2(Fast_distance, fast_distance), |
| CASE1(Fast_length, fast_length), |
| CASE1(Fast_normalize, fast_normalize), // enum value 110 |
| }))); |
| |
| // OpenCL.std: 2.5 Relational instructions |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLRelational, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| CASE3(Bitselect, bitselect), // enum value 186 |
| CASE3(Select, select), // enum value 187 |
| }))); |
| |
| // OpenCL.std: 2.6 Vector data load and store instructions |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLVectorLoadStore, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| // The last argument to Vloadn must be one of 2, 3, 4, 8, 16. |
| CASE2Lit(Vloadn, vloadn, 2), |
| CASE2Lit(Vloadn, vloadn, 3), |
| CASE2Lit(Vloadn, vloadn, 4), |
| CASE2Lit(Vloadn, vloadn, 8), |
| CASE2Lit(Vloadn, vloadn, 16), |
| CASE3(Vstoren, vstoren), |
| CASE2(Vload_half, vload_half), |
| CASE2Lit(Vload_halfn, vload_halfn, 2), |
| CASE2Lit(Vload_halfn, vload_halfn, 3), |
| CASE2Lit(Vload_halfn, vload_halfn, 4), |
| CASE2Lit(Vload_halfn, vload_halfn, 8), |
| CASE2Lit(Vload_halfn, vload_halfn, 16), |
| CASE3(Vstore_half, vstore_half), |
| // Try all the rounding modes. |
| CASE3Round(Vstore_half_r, vstore_half_r, RTE), |
| CASE3Round(Vstore_half_r, vstore_half_r, RTZ), |
| CASE3Round(Vstore_half_r, vstore_half_r, RTP), |
| CASE3Round(Vstore_half_r, vstore_half_r, RTN), |
| CASE3(Vstore_halfn, vstore_halfn), |
| CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTE), |
| CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTZ), |
| CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTP), |
| CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTN), |
| CASE2Lit(Vloada_halfn, vloada_halfn, 2), |
| CASE2Lit(Vloada_halfn, vloada_halfn, 3), |
| CASE2Lit(Vloada_halfn, vloada_halfn, 4), |
| CASE2Lit(Vloada_halfn, vloada_halfn, 8), |
| CASE2Lit(Vloada_halfn, vloada_halfn, 16), |
| CASE3(Vstorea_halfn, vstorea_halfn), |
| CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTE), |
| CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTZ), |
| CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTP), |
| CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTN), |
| }))); |
| |
| // OpenCL.std: 2.7 Miscellaneous vector instructions |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLMiscellaneousVector, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| CASE2(Shuffle, shuffle), |
| CASE3(Shuffle2, shuffle2), |
| }))); |
| |
| // OpenCL.std: 2.8 Miscellaneous instructions |
| |
| #define PREFIX uint32_t(OpenCLLIB::Entrypoints::Printf), "printf" |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLMiscPrintf, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| // Printf is interesting because it takes a variable number of arguments. |
| // Start with zero optional arguments. |
| {PREFIX, "%4", {4}}, |
| {PREFIX, "%4 %5", {4, 5}}, |
| {PREFIX, "%4 %5 %6", {4, 5, 6}}, |
| {PREFIX, "%4 %5 %6 %7", {4, 5, 6, 7}}, |
| {PREFIX, "%4 %5 %6 %7 %8", {4, 5, 6, 7, 8}}, |
| {PREFIX, "%4 %5 %6 %7 %8 %9", {4, 5, 6, 7, 8, 9}}, |
| {PREFIX, "%4 %5 %6 %7 %8 %9 %10", {4, 5, 6, 7, 8, 9, 10}}, |
| {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11", {4, 5, 6, 7, 8, 9, 10, 11}}, |
| {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12", |
| {4, 5, 6, 7, 8, 9, 10, 11, 12}}, |
| {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12 %13", |
| {4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}, |
| {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14", |
| {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}}, |
| }))); |
| #undef PREFIX |
| |
| INSTANTIATE_TEST_SUITE_P( |
| OpenCLMiscPrefetch, ExtInstOpenCLStdRoundTripTest, |
| ::testing::ValuesIn(std::vector<InstructionCase>({ |
| CASE2(Prefetch, prefetch), |
| }))); |
| |
| // OpenCL.std: 2.9.1 Image encoding |
| // No new instructions defined in this section. |
| |
| // OpenCL.std: 2.9.2 Sampler encoding |
| // No new instructions defined in this section. |
| |
| // OpenCL.std: 2.9.3 Image read |
| // No new instructions defined in this section. |
| // Use core instruction OpImageSampleExplicitLod instead. |
| |
| // OpenCL.std: 2.9.4 Image write |
| // No new instructions defined in this section. |
| |
| // clang-format on |
| |
| #undef CASE1 |
| #undef CASE2 |
| #undef CASE3 |
| #undef CASE4 |
| #undef CASE2Lit |
| #undef CASE3Round |
| |
| } // namespace |
| } // namespace spvtools |