FileTestFixture.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. //===- FileTestFixture.cpp ------------- File Test Fixture Implementation -===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "FileTestFixture.h"
  10. #include <fstream>
  11. #include "FileTestUtils.h"
  12. #include "effcee/effcee.h"
  13. namespace clang {
  14. namespace spirv {
  15. bool FileTest::parseInputFile() {
  16. const char hlslStartLabel[] = "// Run:";
  17. std::stringstream inputSS;
  18. std::ifstream inputFile;
  19. inputFile.exceptions(std::ifstream::failbit);
  20. try {
  21. inputFile.open(inputFilePath);
  22. inputSS << inputFile.rdbuf();
  23. } catch (...) {
  24. fprintf(
  25. stderr,
  26. "Error: Exception occurred while opening/reading the input file %s\n",
  27. inputFilePath.c_str());
  28. return false;
  29. }
  30. // Close the input file.
  31. inputFile.close();
  32. // Effcee skips any input line which doesn't have a CHECK directive, therefore
  33. // we can pass the entire input to effcee. This way, any warning/error message
  34. // provided by effcee also reflects the correct line number in the input file.
  35. checkCommands = inputSS.str();
  36. const auto runCmdStartPos = checkCommands.find(hlslStartLabel);
  37. if (runCmdStartPos != std::string::npos) {
  38. const auto runCmdEndPos = checkCommands.find('\n', runCmdStartPos);
  39. const auto runCommand = checkCommands.substr(runCmdStartPos, runCmdEndPos);
  40. if (!utils::processRunCommandArgs(runCommand, &targetProfile, &entryPoint,
  41. &restArgs)) {
  42. // An error has occured when parsing the Run command.
  43. return false;
  44. }
  45. } else {
  46. fprintf(stderr, "Error: Missing \"Run:\" command.\n");
  47. return false;
  48. }
  49. // Everything was successful.
  50. return true;
  51. }
  52. void FileTest::runFileTest(llvm::StringRef filename, Expect expect,
  53. bool runValidation) {
  54. if (beforeHLSLLegalization)
  55. assert(runValidation);
  56. inputFilePath = utils::getAbsPathOfInputDataFile(filename);
  57. // Parse the input file.
  58. ASSERT_TRUE(parseInputFile());
  59. std::string errorMessages;
  60. // Feed the HLSL source into the Compiler.
  61. const bool compileOk = utils::runCompilerWithSpirvGeneration(
  62. inputFilePath, entryPoint, targetProfile, restArgs, &generatedBinary,
  63. &errorMessages);
  64. effcee::Result result(effcee::Result::Status::Ok);
  65. if (expect == Expect::Success) {
  66. ASSERT_TRUE(compileOk);
  67. // Disassemble the generated SPIR-V binary.
  68. ASSERT_TRUE(utils::disassembleSpirvBinary(
  69. generatedBinary, &generatedSpirvAsm, true /* generateHeader */));
  70. auto options = effcee::Options()
  71. .SetChecksName(filename.str())
  72. .SetInputName("<codegen>");
  73. // Run CHECK commands via effcee on disassembly.
  74. result = effcee::Match(generatedSpirvAsm, checkCommands, options);
  75. // Print effcee's error message (if any).
  76. if (result.status() != effcee::Result::Status::Ok) {
  77. fprintf(stderr, "%s\n", result.message().c_str());
  78. }
  79. // All checks must have passed.
  80. ASSERT_EQ(result.status(), effcee::Result::Status::Ok);
  81. if (runValidation)
  82. EXPECT_TRUE(utils::validateSpirvBinary(targetEnv, generatedBinary,
  83. beforeHLSLLegalization, glLayout,
  84. dxLayout, scalarLayout));
  85. } else if (expect == Expect::Warning) {
  86. ASSERT_TRUE(compileOk);
  87. // Still check that we can disassemble the generated SPIR-V binary.
  88. ASSERT_TRUE(utils::disassembleSpirvBinary(
  89. generatedBinary, &generatedSpirvAsm, true /* generateHeader */));
  90. auto options = effcee::Options()
  91. .SetChecksName(filename.str())
  92. .SetInputName("<message>");
  93. // Run CHECK commands via effcee on warning messages.
  94. result = effcee::Match(errorMessages, checkCommands, options);
  95. // Print effcee's error message (if any).
  96. if (result.status() != effcee::Result::Status::Ok) {
  97. fprintf(stderr, "%s\n", result.message().c_str());
  98. }
  99. // All checks must have passed.
  100. ASSERT_EQ(result.status(), effcee::Result::Status::Ok);
  101. if (runValidation)
  102. EXPECT_TRUE(utils::validateSpirvBinary(targetEnv, generatedBinary,
  103. beforeHLSLLegalization, glLayout,
  104. dxLayout, scalarLayout));
  105. } else if (expect == Expect::Failure) {
  106. ASSERT_FALSE(compileOk);
  107. auto options = effcee::Options()
  108. .SetChecksName(filename.str())
  109. .SetInputName("<message>");
  110. // Run CHECK commands via effcee on error messages.
  111. result = effcee::Match(errorMessages, checkCommands, options);
  112. // Print effcee's error message (if any).
  113. if (result.status() != effcee::Result::Status::Ok) {
  114. fprintf(stderr, "%s\n", result.message().c_str());
  115. }
  116. // All checks must have passed.
  117. ASSERT_EQ(result.status(), effcee::Result::Status::Ok);
  118. } else {
  119. ASSERT_TRUE(compileOk);
  120. // Disassemble the generated SPIR-V binary.
  121. ASSERT_TRUE(utils::disassembleSpirvBinary(
  122. generatedBinary, &generatedSpirvAsm, true /* generateHeader */));
  123. std::string valMessages;
  124. EXPECT_FALSE(utils::validateSpirvBinary(
  125. targetEnv, generatedBinary, beforeHLSLLegalization, glLayout, dxLayout,
  126. scalarLayout, &valMessages));
  127. auto options = effcee::Options()
  128. .SetChecksName(filename.str())
  129. .SetInputName("<val-message>");
  130. // Run CHECK commands via effcee on error messages.
  131. result = effcee::Match(valMessages, checkCommands, options);
  132. // All checks over validation message must have passed.
  133. ASSERT_EQ(result.status(), effcee::Result::Status::Ok);
  134. }
  135. }
  136. } // end namespace spirv
  137. } // end namespace clang