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 <sstream> 16 #include <string> 17 #include <tuple> 18 #include <vector> 19 20 #include "gmock/gmock.h" 21 #include "source/spirv_constant.h" 22 #include "test/test_fixture.h" 23 #include "test/unit_spirv.h" 24 25 namespace spvtools { 26 namespace { 27 28 using spvtest::AutoText; 29 using spvtest::ScopedContext; 30 using spvtest::TextToBinaryTest; 31 using ::testing::Combine; 32 using ::testing::Eq; 33 using ::testing::HasSubstr; 34 35 class BinaryToText : public ::testing::Test { 36 public: 37 BinaryToText() : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)) {} 38 ~BinaryToText() { spvContextDestroy(context); } 39 40 virtual void SetUp() { 41 const char* textStr = R"( 42 OpSource OpenCL_C 12 43 OpMemoryModel Physical64 OpenCL 44 OpSourceExtension "PlaceholderExtensionName" 45 OpEntryPoint Kernel %1 "foo" 46 OpExecutionMode %1 LocalSizeHint 1 1 1 47 %2 = OpTypeVoid 48 %3 = OpTypeBool 49 %4 = OpTypeInt 8 0 50 %5 = OpTypeInt 8 1 51 %6 = OpTypeInt 16 0 52 %7 = OpTypeInt 16 1 53 %8 = OpTypeInt 32 0 54 %9 = OpTypeInt 32 1 55 %10 = OpTypeInt 64 0 56 %11 = OpTypeInt 64 1 57 %12 = OpTypeFloat 16 58 %13 = OpTypeFloat 32 59 %14 = OpTypeFloat 64 60 %15 = OpTypeVector %4 2 61 )"; 62 spv_text_t text = {textStr, strlen(textStr)}; 63 spv_diagnostic diagnostic = nullptr; 64 spv_result_t error = 65 spvTextToBinary(context, text.str, text.length, &binary, &diagnostic); 66 if (error) { 67 spvDiagnosticPrint(diagnostic); 68 spvDiagnosticDestroy(diagnostic); 69 ASSERT_EQ(SPV_SUCCESS, error); 70 } 71 } 72 73 virtual void TearDown() { spvBinaryDestroy(binary); } 74 75 // Compiles the given assembly text, and saves it into 'binary'. 76 void CompileSuccessfully(std::string text) { 77 spv_diagnostic diagnostic = nullptr; 78 EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(), 79 &binary, &diagnostic)); 80 } 81 82 spv_context context; 83 spv_binary binary; 84 }; 85 86 TEST_F(BinaryToText, Default) { 87 spv_text text = nullptr; 88 spv_diagnostic diagnostic = nullptr; 89 ASSERT_EQ( 90 SPV_SUCCESS, 91 spvBinaryToText(context, binary->code, binary->wordCount, 92 SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic)); 93 printf("%s", text->str); 94 spvTextDestroy(text); 95 } 96 97 TEST_F(BinaryToText, MissingModule) { 98 spv_text text; 99 spv_diagnostic diagnostic = nullptr; 100 EXPECT_EQ( 101 SPV_ERROR_INVALID_BINARY, 102 spvBinaryToText(context, nullptr, 42, SPV_BINARY_TO_TEXT_OPTION_NONE, 103 &text, &diagnostic)); 104 EXPECT_THAT(diagnostic->error, Eq(std::string("Missing module."))); 105 if (diagnostic) { 106 spvDiagnosticPrint(diagnostic); 107 spvDiagnosticDestroy(diagnostic); 108 } 109 } 110 111 TEST_F(BinaryToText, TruncatedModule) { 112 // Make a valid module with zero instructions. 113 CompileSuccessfully(""); 114 EXPECT_EQ(SPV_INDEX_INSTRUCTION, binary->wordCount); 115 116 for (size_t length = 0; length < SPV_INDEX_INSTRUCTION; length++) { 117 spv_text text = nullptr; 118 spv_diagnostic diagnostic = nullptr; 119 EXPECT_EQ( 120 SPV_ERROR_INVALID_BINARY, 121 spvBinaryToText(context, binary->code, length, 122 SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic)); 123 ASSERT_NE(nullptr, diagnostic); 124 std::stringstream expected; 125 expected << "Module has incomplete header: only " << length 126 << " words instead of " << SPV_INDEX_INSTRUCTION; 127 EXPECT_THAT(diagnostic->error, Eq(expected.str())); 128 spvDiagnosticDestroy(diagnostic); 129 } 130 } 131 132 TEST_F(BinaryToText, InvalidMagicNumber) { 133 CompileSuccessfully(""); 134 std::vector<uint32_t> damaged_binary(binary->code, 135 binary->code + binary->wordCount); 136 damaged_binary[SPV_INDEX_MAGIC_NUMBER] ^= 123; 137 138 spv_diagnostic diagnostic = nullptr; 139 spv_text text; 140 EXPECT_EQ( 141 SPV_ERROR_INVALID_BINARY, 142 spvBinaryToText(context, damaged_binary.data(), damaged_binary.size(), 143 SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic)); 144 ASSERT_NE(nullptr, diagnostic); 145 std::stringstream expected; 146 expected << "Invalid SPIR-V magic number '" << std::hex 147 << damaged_binary[SPV_INDEX_MAGIC_NUMBER] << "'."; 148 EXPECT_THAT(diagnostic->error, Eq(expected.str())); 149 spvDiagnosticDestroy(diagnostic); 150 } 151 152 struct FailedDecodeCase { 153 std::string source_text; 154 std::vector<uint32_t> appended_instruction; 155 std::string expected_error_message; 156 }; 157 158 using BinaryToTextFail = 159 spvtest::TextToBinaryTestBase<::testing::TestWithParam<FailedDecodeCase>>; 160 161 TEST_P(BinaryToTextFail, EncodeSuccessfullyDecodeFailed) { 162 EXPECT_THAT(EncodeSuccessfullyDecodeFailed(GetParam().source_text, 163 GetParam().appended_instruction), 164 Eq(GetParam().expected_error_message)); 165 } 166 167 INSTANTIATE_TEST_CASE_P( 168 InvalidIds, BinaryToTextFail, 169 ::testing::ValuesIn(std::vector<FailedDecodeCase>{ 170 {"", spvtest::MakeInstruction(SpvOpTypeVoid, {0}), 171 "Error: Result Id is 0"}, 172 {"", spvtest::MakeInstruction(SpvOpConstant, {0, 1, 42}), 173 "Error: Type Id is 0"}, 174 {"%1 = OpTypeVoid", spvtest::MakeInstruction(SpvOpTypeVoid, {1}), 175 "Id 1 is defined more than once"}, 176 {"%1 = OpTypeVoid\n" 177 "%2 = OpNot %1 %foo", 178 spvtest::MakeInstruction(SpvOpNot, {1, 2, 3}), 179 "Id 2 is defined more than once"}, 180 {"%1 = OpTypeVoid\n" 181 "%2 = OpNot %1 %foo", 182 spvtest::MakeInstruction(SpvOpNot, {1, 1, 3}), 183 "Id 1 is defined more than once"}, 184 // The following are the two failure cases for 185 // Parser::setNumericTypeInfoForType. 186 {"", spvtest::MakeInstruction(SpvOpConstant, {500, 1, 42}), 187 "Type Id 500 is not a type"}, 188 {"%1 = OpTypeInt 32 0\n" 189 "%2 = OpTypeVector %1 4", 190 spvtest::MakeInstruction(SpvOpConstant, {2, 3, 999}), 191 "Type Id 2 is not a scalar numeric type"}, 192 }), ); 193 194 INSTANTIATE_TEST_CASE_P( 195 InvalidIdsCheckedDuringLiteralCaseParsing, BinaryToTextFail, 196 ::testing::ValuesIn(std::vector<FailedDecodeCase>{ 197 {"", spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}), 198 "Invalid OpSwitch: selector id 1 has no type"}, 199 {"%1 = OpTypeVoid\n", 200 spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}), 201 "Invalid OpSwitch: selector id 1 is a type, not a value"}, 202 {"%1 = OpConstantTrue !500", 203 spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}), 204 "Type Id 500 is not a type"}, 205 {"%1 = OpTypeFloat 32\n%2 = OpConstant %1 1.5", 206 spvtest::MakeInstruction(SpvOpSwitch, {2, 3, 4, 5}), 207 "Invalid OpSwitch: selector id 2 is not a scalar integer"}, 208 }), ); 209 210 TEST_F(TextToBinaryTest, OneInstruction) { 211 const std::string input = "OpSource OpenCL_C 12\n"; 212 EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input)); 213 } 214 215 // Exercise the case where an operand itself has operands. 216 // This could detect problems in updating the expected-set-of-operands 217 // list. 218 TEST_F(TextToBinaryTest, OperandWithOperands) { 219 const std::string input = R"(OpEntryPoint Kernel %1 "foo" 220 OpExecutionMode %1 LocalSizeHint 100 200 300 221 %2 = OpTypeVoid 222 %3 = OpTypeFunction %2 223 %1 = OpFunction %1 None %3 224 )"; 225 EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input)); 226 } 227 228 using RoundTripInstructionsTest = spvtest::TextToBinaryTestBase< 229 ::testing::TestWithParam<std::tuple<spv_target_env, std::string>>>; 230 231 TEST_P(RoundTripInstructionsTest, Sample) { 232 EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<1>(GetParam()), 233 SPV_BINARY_TO_TEXT_OPTION_NONE, 234 std::get<0>(GetParam())), 235 Eq(std::get<1>(GetParam()))); 236 } 237 238 // clang-format off 239 INSTANTIATE_TEST_CASE_P( 240 NumericLiterals, RoundTripInstructionsTest, 241 // This test is independent of environment, so just test the one. 242 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, 243 SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), 244 ::testing::ValuesIn(std::vector<std::string>{ 245 "%1 = OpTypeInt 12 0\n%2 = OpConstant %1 1867\n", 246 "%1 = OpTypeInt 12 1\n%2 = OpConstant %1 1867\n", 247 "%1 = OpTypeInt 12 1\n%2 = OpConstant %1 -1867\n", 248 "%1 = OpTypeInt 32 0\n%2 = OpConstant %1 1867\n", 249 "%1 = OpTypeInt 32 1\n%2 = OpConstant %1 1867\n", 250 "%1 = OpTypeInt 32 1\n%2 = OpConstant %1 -1867\n", 251 "%1 = OpTypeInt 64 0\n%2 = OpConstant %1 18446744073709551615\n", 252 "%1 = OpTypeInt 64 1\n%2 = OpConstant %1 9223372036854775807\n", 253 "%1 = OpTypeInt 64 1\n%2 = OpConstant %1 -9223372036854775808\n", 254 // 16-bit floats print as hex floats. 255 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ff4p+16\n", 256 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.d2cp-10\n", 257 // 32-bit floats 258 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -3.125\n", 259 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128\n", // NaN 260 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128\n", // NaN 261 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128\n", // Inf 262 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -Inf 263 // 64-bit floats 264 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -3.125\n", 265 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.ffffffffffffap-1023\n", // small normal 266 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.ffffffffffffap-1023\n", 267 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024\n", // NaN 268 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0002p+1024\n", // NaN 269 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", // Inf 270 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", // -Inf 271 })), ); 272 // clang-format on 273 274 INSTANTIATE_TEST_CASE_P( 275 MemoryAccessMasks, RoundTripInstructionsTest, 276 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, 277 SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), 278 ::testing::ValuesIn(std::vector<std::string>{ 279 "OpStore %1 %2\n", // 3 words long. 280 "OpStore %1 %2 None\n", // 4 words long, explicit final 0. 281 "OpStore %1 %2 Volatile\n", 282 "OpStore %1 %2 Aligned 8\n", 283 "OpStore %1 %2 Nontemporal\n", 284 // Combinations show the names from LSB to MSB 285 "OpStore %1 %2 Volatile|Aligned 16\n", 286 "OpStore %1 %2 Volatile|Nontemporal\n", 287 "OpStore %1 %2 Volatile|Aligned|Nontemporal 32\n", 288 })), ); 289 290 INSTANTIATE_TEST_CASE_P( 291 FPFastMathModeMasks, RoundTripInstructionsTest, 292 Combine( 293 ::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, 294 SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), 295 ::testing::ValuesIn(std::vector<std::string>{ 296 "OpDecorate %1 FPFastMathMode None\n", 297 "OpDecorate %1 FPFastMathMode NotNaN\n", 298 "OpDecorate %1 FPFastMathMode NotInf\n", 299 "OpDecorate %1 FPFastMathMode NSZ\n", 300 "OpDecorate %1 FPFastMathMode AllowRecip\n", 301 "OpDecorate %1 FPFastMathMode Fast\n", 302 // Combinations show the names from LSB to MSB 303 "OpDecorate %1 FPFastMathMode NotNaN|NotInf\n", 304 "OpDecorate %1 FPFastMathMode NSZ|AllowRecip\n", 305 "OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast\n", 306 })), ); 307 308 INSTANTIATE_TEST_CASE_P( 309 LoopControlMasks, RoundTripInstructionsTest, 310 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, 311 SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2), 312 ::testing::ValuesIn(std::vector<std::string>{ 313 "OpLoopMerge %1 %2 None\n", 314 "OpLoopMerge %1 %2 Unroll\n", 315 "OpLoopMerge %1 %2 DontUnroll\n", 316 "OpLoopMerge %1 %2 Unroll|DontUnroll\n", 317 })), ); 318 319 INSTANTIATE_TEST_CASE_P(LoopControlMasksV11, RoundTripInstructionsTest, 320 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_1, 321 SPV_ENV_UNIVERSAL_1_2, 322 SPV_ENV_UNIVERSAL_1_3), 323 ::testing::ValuesIn(std::vector<std::string>{ 324 "OpLoopMerge %1 %2 DependencyInfinite\n", 325 "OpLoopMerge %1 %2 DependencyLength 8\n", 326 })), ); 327 328 INSTANTIATE_TEST_CASE_P( 329 SelectionControlMasks, RoundTripInstructionsTest, 330 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, 331 SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2), 332 ::testing::ValuesIn(std::vector<std::string>{ 333 "OpSelectionMerge %1 None\n", 334 "OpSelectionMerge %1 Flatten\n", 335 "OpSelectionMerge %1 DontFlatten\n", 336 "OpSelectionMerge %1 Flatten|DontFlatten\n", 337 })), ); 338 339 INSTANTIATE_TEST_CASE_P( 340 FunctionControlMasks, RoundTripInstructionsTest, 341 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, 342 SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), 343 ::testing::ValuesIn(std::vector<std::string>{ 344 "%2 = OpFunction %1 None %3\n", 345 "%2 = OpFunction %1 Inline %3\n", 346 "%2 = OpFunction %1 DontInline %3\n", 347 "%2 = OpFunction %1 Pure %3\n", 348 "%2 = OpFunction %1 Const %3\n", 349 "%2 = OpFunction %1 Inline|Pure|Const %3\n", 350 "%2 = OpFunction %1 DontInline|Const %3\n", 351 })), ); 352 353 INSTANTIATE_TEST_CASE_P( 354 ImageMasks, RoundTripInstructionsTest, 355 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, 356 SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), 357 ::testing::ValuesIn(std::vector<std::string>{ 358 "%2 = OpImageFetch %1 %3 %4\n", 359 "%2 = OpImageFetch %1 %3 %4 None\n", 360 "%2 = OpImageFetch %1 %3 %4 Bias %5\n", 361 "%2 = OpImageFetch %1 %3 %4 Lod %5\n", 362 "%2 = OpImageFetch %1 %3 %4 Grad %5 %6\n", 363 "%2 = OpImageFetch %1 %3 %4 ConstOffset %5\n", 364 "%2 = OpImageFetch %1 %3 %4 Offset %5\n", 365 "%2 = OpImageFetch %1 %3 %4 ConstOffsets %5\n", 366 "%2 = OpImageFetch %1 %3 %4 Sample %5\n", 367 "%2 = OpImageFetch %1 %3 %4 MinLod %5\n", 368 "%2 = OpImageFetch %1 %3 %4 Bias|Lod|Grad %5 %6 %7 %8\n", 369 "%2 = OpImageFetch %1 %3 %4 ConstOffset|Offset|ConstOffsets" 370 " %5 %6 %7\n", 371 "%2 = OpImageFetch %1 %3 %4 Sample|MinLod %5 %6\n", 372 "%2 = OpImageFetch %1 %3 %4" 373 " Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod" 374 " %5 %6 %7 %8 %9 %10 %11 %12 %13\n"})), ); 375 376 INSTANTIATE_TEST_CASE_P( 377 NewInstructionsInSPIRV1_2, RoundTripInstructionsTest, 378 Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), 379 ::testing::ValuesIn(std::vector<std::string>{ 380 "OpExecutionModeId %1 SubgroupsPerWorkgroupId %2\n", 381 "OpExecutionModeId %1 LocalSizeId %2 %3 %4\n", 382 "OpExecutionModeId %1 LocalSizeHintId %2\n", 383 "OpDecorateId %1 AlignmentId %2\n", 384 "OpDecorateId %1 MaxByteOffsetId %2\n", 385 })), ); 386 387 using MaskSorting = TextToBinaryTest; 388 389 TEST_F(MaskSorting, MasksAreSortedFromLSBToMSB) { 390 EXPECT_THAT(EncodeAndDecodeSuccessfully( 391 "OpStore %1 %2 Nontemporal|Aligned|Volatile 32"), 392 Eq("OpStore %1 %2 Volatile|Aligned|Nontemporal 32\n")); 393 EXPECT_THAT( 394 EncodeAndDecodeSuccessfully( 395 "OpDecorate %1 FPFastMathMode NotInf|Fast|AllowRecip|NotNaN|NSZ"), 396 Eq("OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast\n")); 397 EXPECT_THAT( 398 EncodeAndDecodeSuccessfully("OpLoopMerge %1 %2 DontUnroll|Unroll"), 399 Eq("OpLoopMerge %1 %2 Unroll|DontUnroll\n")); 400 EXPECT_THAT( 401 EncodeAndDecodeSuccessfully("OpSelectionMerge %1 DontFlatten|Flatten"), 402 Eq("OpSelectionMerge %1 Flatten|DontFlatten\n")); 403 EXPECT_THAT(EncodeAndDecodeSuccessfully( 404 "%2 = OpFunction %1 DontInline|Const|Pure|Inline %3"), 405 Eq("%2 = OpFunction %1 Inline|DontInline|Pure|Const %3\n")); 406 EXPECT_THAT(EncodeAndDecodeSuccessfully( 407 "%2 = OpImageFetch %1 %3 %4" 408 " MinLod|Sample|Offset|Lod|Grad|ConstOffsets|ConstOffset|Bias" 409 " %5 %6 %7 %8 %9 %10 %11 %12 %13\n"), 410 Eq("%2 = OpImageFetch %1 %3 %4" 411 " Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod" 412 " %5 %6 %7 %8 %9 %10 %11 %12 %13\n")); 413 } 414 415 using OperandTypeTest = TextToBinaryTest; 416 417 TEST_F(OperandTypeTest, OptionalTypedLiteralNumber) { 418 const std::string input = 419 "%1 = OpTypeInt 32 0\n" 420 "%2 = OpConstant %1 42\n" 421 "OpSwitch %2 %3 100 %4\n"; 422 EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input)); 423 } 424 425 using IndentTest = spvtest::TextToBinaryTest; 426 427 TEST_F(IndentTest, Sample) { 428 const std::string input = R"( 429 OpCapability Shader 430 OpMemoryModel Logical GLSL450 431 %1 = OpTypeInt 32 0 432 %2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10 ; force IDs into double digits 433 %11 = OpConstant %1 42 434 OpStore %2 %3 Aligned|Volatile 4 ; bogus, but not indented 435 )"; 436 const std::string expected = 437 R"( OpCapability Shader 438 OpMemoryModel Logical GLSL450 439 %1 = OpTypeInt 32 0 440 %2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10 441 %11 = OpConstant %1 42 442 OpStore %2 %3 Volatile|Aligned 4 443 )"; 444 EXPECT_THAT( 445 EncodeAndDecodeSuccessfully(input, SPV_BINARY_TO_TEXT_OPTION_INDENT), 446 expected); 447 } 448 449 using FriendlyNameDisassemblyTest = spvtest::TextToBinaryTest; 450 451 TEST_F(FriendlyNameDisassemblyTest, Sample) { 452 const std::string input = R"( 453 OpCapability Shader 454 OpMemoryModel Logical GLSL450 455 %1 = OpTypeInt 32 0 456 %2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10 ; force IDs into double digits 457 %11 = OpConstant %1 42 458 )"; 459 const std::string expected = 460 R"(OpCapability Shader 461 OpMemoryModel Logical GLSL450 462 %uint = OpTypeInt 32 0 463 %_struct_2 = OpTypeStruct %uint %3 %4 %5 %6 %7 %8 %9 %10 464 %uint_42 = OpConstant %uint 42 465 )"; 466 EXPECT_THAT(EncodeAndDecodeSuccessfully( 467 input, SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES), 468 expected); 469 } 470 471 TEST_F(TextToBinaryTest, ShowByteOffsetsWhenRequested) { 472 const std::string input = R"( 473 OpCapability Shader 474 OpMemoryModel Logical GLSL450 475 %1 = OpTypeInt 32 0 476 %2 = OpTypeVoid 477 )"; 478 const std::string expected = 479 R"(OpCapability Shader ; 0x00000014 480 OpMemoryModel Logical GLSL450 ; 0x0000001c 481 %1 = OpTypeInt 32 0 ; 0x00000028 482 %2 = OpTypeVoid ; 0x00000038 483 )"; 484 EXPECT_THAT(EncodeAndDecodeSuccessfully( 485 input, SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET), 486 expected); 487 } 488 489 // Test version string. 490 TEST_F(TextToBinaryTest, VersionString) { 491 auto words = CompileSuccessfully(""); 492 spv_text decoded_text = nullptr; 493 EXPECT_THAT(spvBinaryToText(ScopedContext().context, words.data(), 494 words.size(), SPV_BINARY_TO_TEXT_OPTION_NONE, 495 &decoded_text, &diagnostic), 496 Eq(SPV_SUCCESS)); 497 EXPECT_EQ(nullptr, diagnostic); 498 499 EXPECT_THAT(decoded_text->str, HasSubstr("Version: 1.0\n")) 500 << EncodeAndDecodeSuccessfully(""); 501 spvTextDestroy(decoded_text); 502 } 503 504 // Test generator string. 505 506 // A test case for the generator string. This allows us to 507 // test both of the 16-bit components of the generator word. 508 struct GeneratorStringCase { 509 uint16_t generator; 510 uint16_t misc; 511 std::string expected; 512 }; 513 514 using GeneratorStringTest = spvtest::TextToBinaryTestBase< 515 ::testing::TestWithParam<GeneratorStringCase>>; 516 517 TEST_P(GeneratorStringTest, Sample) { 518 auto words = CompileSuccessfully(""); 519 EXPECT_EQ(2u, SPV_INDEX_GENERATOR_NUMBER); 520 words[SPV_INDEX_GENERATOR_NUMBER] = 521 SPV_GENERATOR_WORD(GetParam().generator, GetParam().misc); 522 523 spv_text decoded_text = nullptr; 524 EXPECT_THAT(spvBinaryToText(ScopedContext().context, words.data(), 525 words.size(), SPV_BINARY_TO_TEXT_OPTION_NONE, 526 &decoded_text, &diagnostic), 527 Eq(SPV_SUCCESS)); 528 EXPECT_THAT(diagnostic, Eq(nullptr)); 529 EXPECT_THAT(std::string(decoded_text->str), HasSubstr(GetParam().expected)); 530 spvTextDestroy(decoded_text); 531 } 532 533 INSTANTIATE_TEST_CASE_P(GeneratorStrings, GeneratorStringTest, 534 ::testing::ValuesIn(std::vector<GeneratorStringCase>{ 535 {SPV_GENERATOR_KHRONOS, 12, "Khronos; 12"}, 536 {SPV_GENERATOR_LUNARG, 99, "LunarG; 99"}, 537 {SPV_GENERATOR_VALVE, 1, "Valve; 1"}, 538 {SPV_GENERATOR_CODEPLAY, 65535, "Codeplay; 65535"}, 539 {SPV_GENERATOR_NVIDIA, 19, "NVIDIA; 19"}, 540 {SPV_GENERATOR_ARM, 1000, "ARM; 1000"}, 541 {SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR, 38, 542 "Khronos LLVM/SPIR-V Translator; 38"}, 543 {SPV_GENERATOR_KHRONOS_ASSEMBLER, 2, 544 "Khronos SPIR-V Tools Assembler; 2"}, 545 {SPV_GENERATOR_KHRONOS_GLSLANG, 1, 546 "Khronos Glslang Reference Front End; 1"}, 547 {1000, 18, "Unknown(1000); 18"}, 548 {65535, 32767, "Unknown(65535); 32767"}, 549 }), ); 550 551 // TODO(dneto): Test new instructions and enums in SPIR-V 1.3 552 553 } // namespace 554 } // namespace spvtools 555