浏览代码

[dxil2spv] Command line parsing and output file (#4454)

Add command line argument parsing with the CommandLine library,
and support writing SPIR-V module binary to an output file when
specified.
Natalie Chouinard 3 年之前
父节点
当前提交
2e49e6809b

+ 22 - 6
tools/clang/tools/dxil2spv/dxil2spvmain.cpp

@@ -39,9 +39,21 @@
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendOptions.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MSFileSystem.h"
 #include "llvm/Support/raw_ostream.h"
+#include <string>
+
+// Command line options for dxil2spv. The general approach is to mirror the
+// relevant options from HLSLOptions.td.
+static llvm::cl::opt<bool> optHelp("help",
+                                   llvm::cl::desc("Display available options"));
+static llvm::cl::opt<std::string>
+    optInputFilename(llvm::cl::Positional, llvm::cl::desc("<input file>"));
+static llvm::cl::opt<std::string>
+    optOutputFilename("Fo", llvm::cl::desc("Output object file"),
+                      llvm::cl::value_desc("file"));
 
 #ifdef _WIN32
 int __cdecl wmain(int argc, const wchar_t **argv_) {
@@ -61,9 +73,13 @@ int main(int argc, const char **argv_) {
   llvm::STDStreamCloser stdStreamCloser;
 
   // Check input arguments.
-  if (argc < 2) {
-    llvm::errs() << "Required input file argument is missing\n";
-    return EXIT_FAILURE;
+  const char *helpMessage =
+      "dxil2spv is a tool that translates DXIL code to SPIR-V.\n\n"
+      "WARNING: This tool is a prototype in early development.\n";
+  llvm::cl::ParseCommandLineOptions(argc, argv_, helpMessage);
+  if (optInputFilename.empty() || optHelp) {
+    llvm::cl::PrintHelpMessage();
+    return EXIT_SUCCESS;
   }
 
   // Setup a compiler instance with diagnostics.
@@ -76,9 +92,9 @@ int main(int argc, const char **argv_) {
   // TODO: Allow configuration of targetEnv via options.
   instance.getCodeGenOpts().SpirvOptions.targetEnv = "vulkan1.0";
 
-  // Set input filename.
-  const llvm::StringRef inputFilename(argv_[1]);
-  instance.getCodeGenOpts().MainFileName = inputFilename;
+  // Set input and ouptut filenames.
+  instance.getCodeGenOpts().MainFileName = optInputFilename;
+  instance.getFrontendOpts().OutputFile = optOutputFilename;
 
   // Run translator.
   clang::dxil2spv::Translator translator(instance);

+ 35 - 12
tools/clang/tools/dxil2spv/lib/dxil2spv.cpp

@@ -35,6 +35,7 @@
 #include "clang/Frontend/CodeGenOptions.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/SPIRV/SpirvUtils.h"
+#include "llvm/Support/FileSystem.h"
 
 namespace clang {
 namespace dxil2spv {
@@ -147,26 +148,48 @@ void Translator::Run() {
   }
 
   // Contsruct the SPIR-V module.
-  std::vector<uint32_t> m = spvBuilder.takeModuleForDxilToSpv();
+  std::vector<uint32_t> spirvModule = spvBuilder.takeModuleForDxilToSpv();
 
   // Validate the generated SPIR-V code.
   std::string messages;
-  if (!spirvToolsValidate(&m, &messages)) {
+  if (!spirvToolsValidate(spirvModule, &messages)) {
     emitError("Generated SPIR-V is invalid: %0") << messages;
   }
 
-  // Disassemble SPIR-V for output.
-  std::string assembly;
-  spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
-  uint32_t spirvDisOpts = (SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
-                           SPV_BINARY_TO_TEXT_OPTION_INDENT);
+  outputSpirvModule(spirvModule);
+}
+
+void Translator::outputSpirvModule(llvm::ArrayRef<uint32_t> spirvModule) {
+  std::string outputFileName = ci.getFrontendOpts().OutputFile;
+
+  // If output file not specified, disassemble SPIR-V for stdout.
+  if (outputFileName.empty()) {
+    std::string assembly;
+    spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_0);
+    uint32_t spirvDisOpts = (SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
+                             SPV_BINARY_TO_TEXT_OPTION_INDENT);
+
+    if (!spirvTools.Disassemble(spirvModule, &assembly, spirvDisOpts)) {
+      emitError("SPIR-V disassembly failed");
+      return;
+    }
+
+    *ci.getOutStream() << assembly;
+    return;
+  }
 
-  if (!spirvTools.Disassemble(m, &assembly, spirvDisOpts)) {
-    emitError("SPIR-V disassembly failed");
+  // Output SPIR-V binary to file.
+  std::error_code outputFileError;
+  llvm::raw_fd_ostream outputFileStream(outputFileName, outputFileError,
+                                        llvm::sys::fs::F_RW);
+  if (outputFileError) {
+    emitError("Unable to open output file %0: %1")
+        << outputFileName << outputFileError.message();
     return;
   }
 
-  *ci.getOutStream() << assembly;
+  outputFileStream.write(reinterpret_cast<const char *>(spirvModule.data()),
+                         spirvModule.size() * 4);
 }
 
 void Translator::createStageIOVariables(
@@ -686,7 +709,7 @@ void Translator::createExtractValueInstruction(
   instructionMap[&instruction] = accessChain;
 }
 
-bool Translator::spirvToolsValidate(std::vector<uint32_t> *mod,
+bool Translator::spirvToolsValidate(llvm::ArrayRef<uint32_t> spirvModule,
                                     std::string *messages) {
   spvtools::SpirvTools tools(featureManager.getTargetEnv());
 
@@ -696,7 +719,7 @@ bool Translator::spirvToolsValidate(std::vector<uint32_t> *mod,
                  const char *message) { *messages += message; });
 
   spvtools::ValidatorOptions options;
-  return tools.Validate(mod->data(), mod->size(), options);
+  return tools.Validate(spirvModule.data(), spirvModule.size(), options);
 }
 
 const spirv::SpirvType *Translator::toSpirvType(hlsl::CompType compType) {

+ 5 - 1
tools/clang/tools/dxil2spv/lib/dxil2spv.h

@@ -95,7 +95,11 @@ private:
   void createExtractValueInstruction(llvm::ExtractValueInst &instruction);
 
   // SPIR-V Tools wrapper functions.
-  bool spirvToolsValidate(std::vector<uint32_t> *mod, std::string *messages);
+  bool spirvToolsValidate(llvm::ArrayRef<uint32_t> spirvModule,
+                          std::string *messages);
+
+  // Output SPIR-V module.
+  void outputSpirvModule(llvm::ArrayRef<uint32_t> spirvModule);
 
   // Translate HLSL/DXIL types to corresponding SPIR-V types.
   const spirv::SpirvType *toSpirvType(hlsl::CompType compType);