FileTestFixture.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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 (relaxLogicalPointer)
  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(
  83. targetEnv, generatedBinary, relaxLogicalPointer, glLayout, dxLayout));
  84. } else if (expect == Expect::Warning) {
  85. ASSERT_TRUE(compileOk);
  86. // Still check that we can disassemble the generated SPIR-V binary.
  87. ASSERT_TRUE(utils::disassembleSpirvBinary(
  88. generatedBinary, &generatedSpirvAsm, true /* generateHeader */));
  89. auto options = effcee::Options()
  90. .SetChecksName(filename.str())
  91. .SetInputName("<message>");
  92. // Run CHECK commands via effcee on warning messages.
  93. result = effcee::Match(errorMessages, checkCommands, options);
  94. // Print effcee's error message (if any).
  95. if (result.status() != effcee::Result::Status::Ok) {
  96. fprintf(stderr, "%s\n", result.message().c_str());
  97. }
  98. // All checks must have passed.
  99. ASSERT_EQ(result.status(), effcee::Result::Status::Ok);
  100. if (runValidation)
  101. EXPECT_TRUE(utils::validateSpirvBinary(
  102. targetEnv, generatedBinary, relaxLogicalPointer, glLayout, dxLayout));
  103. } else if (expect == Expect::Failure) {
  104. ASSERT_FALSE(compileOk);
  105. auto options = effcee::Options()
  106. .SetChecksName(filename.str())
  107. .SetInputName("<message>");
  108. // Run CHECK commands via effcee on error messages.
  109. result = effcee::Match(errorMessages, checkCommands, options);
  110. // Print effcee's error message (if any).
  111. if (result.status() != effcee::Result::Status::Ok) {
  112. fprintf(stderr, "%s\n", result.message().c_str());
  113. }
  114. // All checks must have passed.
  115. ASSERT_EQ(result.status(), effcee::Result::Status::Ok);
  116. } else {
  117. ASSERT_TRUE(compileOk);
  118. // Disassemble the generated SPIR-V binary.
  119. ASSERT_TRUE(utils::disassembleSpirvBinary(
  120. generatedBinary, &generatedSpirvAsm, true /* generateHeader */));
  121. std::string valMessages;
  122. EXPECT_FALSE(utils::validateSpirvBinary(targetEnv, generatedBinary,
  123. relaxLogicalPointer, glLayout,
  124. dxLayout, &valMessages));
  125. auto options = effcee::Options()
  126. .SetChecksName(filename.str())
  127. .SetInputName("<val-message>");
  128. // Run CHECK commands via effcee on error messages.
  129. result = effcee::Match(valMessages, checkCommands, options);
  130. // All checks over validation message must have passed.
  131. ASSERT_EQ(result.status(), effcee::Result::Status::Ok);
  132. }
  133. }
  134. } // end namespace spirv
  135. } // end namespace clang