ソースを参照

Add support for external libraries to dxopt. (#324)

Adds support for external and external-fn arguments.
Adds support for a pf file with the pass configuration.
Marcelo Lopez Ruiz 8 年 前
コミット
4b834beaf9
2 ファイル変更156 行追加32 行削除
  1. 103 16
      tools/clang/tools/dxopt/dxopt.cpp
  2. 53 16
      utils/hct/hcttestcmds.cmd

+ 103 - 16
tools/clang/tools/dxopt/dxopt.cpp

@@ -34,6 +34,11 @@ inline bool wcsieq(LPCWSTR a, LPCWSTR b) { return _wcsicmp(a, b) == 0; }
 inline bool wcsistarts(LPCWSTR text, LPCWSTR prefix) {
 inline bool wcsistarts(LPCWSTR text, LPCWSTR prefix) {
   return wcslen(text) >= wcslen(prefix) && _wcsnicmp(text, prefix, wcslen(prefix)) == 0;
   return wcslen(text) >= wcslen(prefix) && _wcsnicmp(text, prefix, wcslen(prefix)) == 0;
 }
 }
+inline bool wcsieqopt(LPCWSTR text, LPCWSTR opt) {
+  return (text[0] == L'-' || text[0] == L'/') && wcsieq(text + 1, opt);
+}
+
+static dxc::DxcDllSupport g_DxcSupport;
 
 
 enum class ProgramAction {
 enum class ProgramAction {
   PrintHelp,
   PrintHelp,
@@ -82,7 +87,7 @@ static HRESULT ReadStdin(std::string &input) {
 static void BlobFromFile(LPCWSTR pFileName, IDxcBlob **ppBlob) {
 static void BlobFromFile(LPCWSTR pFileName, IDxcBlob **ppBlob) {
   CComPtr<IDxcLibrary> pLibrary;
   CComPtr<IDxcLibrary> pLibrary;
   CComPtr<IDxcBlobEncoding> pFileBlob;
   CComPtr<IDxcBlobEncoding> pFileBlob;
-  IFT(DxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&pLibrary)));
+  IFT(g_DxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
   if (isStdIn(pFileName)) {
   if (isStdIn(pFileName)) {
     std::string input;
     std::string input;
     IFT(ReadStdin(input));
     IFT(ReadStdin(input));
@@ -98,7 +103,7 @@ static void BlobFromFile(LPCWSTR pFileName, IDxcBlob **ppBlob) {
 static void PrintOptOutput(LPCWSTR pFileName, IDxcBlob *pBlob, IDxcBlobEncoding *pOutputText) {
 static void PrintOptOutput(LPCWSTR pFileName, IDxcBlob *pBlob, IDxcBlobEncoding *pOutputText) {
   CComPtr<IDxcLibrary> pLibrary;
   CComPtr<IDxcLibrary> pLibrary;
   CComPtr<IDxcBlobEncoding> pOutputText16;
   CComPtr<IDxcBlobEncoding> pOutputText16;
-  IFT(DxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&pLibrary)));
+  IFT(g_DxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
   IFT(pLibrary->GetBlobAsUtf16(pOutputText, &pOutputText16));
   IFT(pLibrary->GetBlobAsUtf16(pOutputText, &pOutputText16));
   wprintf(L"%*s", (int)pOutputText16->GetBufferSize(),
   wprintf(L"%*s", (int)pOutputText16->GetBufferSize(),
           (wchar_t *)pOutputText16->GetBufferPointer());
           (wchar_t *)pOutputText16->GetBufferPointer());
@@ -149,16 +154,54 @@ static void PrintPasses(IDxcOptimizer *pOptimizer, bool includeDetails) {
   }
   }
 }
 }
 
 
+static void ReadFileOpts(LPCWSTR pPassFileName, IDxcBlobEncoding **ppPassOpts, std::vector<LPCWSTR> &passes, LPCWSTR **pOptArgs, UINT32 *pOptArgCount) {
+  *ppPassOpts = nullptr;
+  // If there is no file, there is no work to be done.
+  if (!pPassFileName || !*pPassFileName) {
+    return;
+  }
+
+  CComPtr<IDxcBlob> pPassOptsBlob;
+  CComPtr<IDxcBlobEncoding> pPassOpts;
+  BlobFromFile(pPassFileName, &pPassOptsBlob);
+  IFT(hlsl::DxcGetBlobAsUtf16(pPassOptsBlob, &pPassOpts));
+  LPWSTR pCursor = (LPWSTR)pPassOpts->GetBufferPointer();
+  while (*pCursor) {
+    passes.push_back(pCursor);
+    while (*pCursor && *pCursor != L'\n' && *pCursor != L'\r') {
+      ++pCursor;
+    }
+    while (*pCursor && (*pCursor == L'\n' || *pCursor == L'\r')) {
+      *pCursor = L'\0';
+      ++pCursor;
+    }
+  }
+
+  // Remove empty entries and comments.
+  size_t i = passes.size();
+  do {
+    --i;
+    if (wcslen(passes[i]) == 0 || passes[i][0] == L'#') {
+      passes.erase(passes.begin() + i);
+    }
+  } while (i != 0);
+
+  *pOptArgs = passes.data();
+  *pOptArgCount = passes.size();
+  *ppPassOpts = pPassOpts.Detach();
+}
+
 static void PrintHelp() {
 static void PrintHelp() {
   wprintf(L"%s",
   wprintf(L"%s",
     L"Performs optimizations on a bitcode file by running a sequence of passes.\n\n"
     L"Performs optimizations on a bitcode file by running a sequence of passes.\n\n"
-    L"dxopt [-? | -passes | -pass-details | IN-FILE [-o=OUT-FILE] OPT-ARGUMENTS ...]\n\n"
+    L"dxopt [-? | -passes | -pass-details | -pf [PASS-FILE] | [-o=OUT-FILE] | IN-FILE OPT-ARGUMENTS ...]\n\n"
     L"Arguments:\n"
     L"Arguments:\n"
     L"  -?  Displays this help message\n"
     L"  -?  Displays this help message\n"
     L"  -passes        Displays a list of pass names\n"
     L"  -passes        Displays a list of pass names\n"
     L"  -pass-details  Displays a list of passes with detailed information\n"
     L"  -pass-details  Displays a list of passes with detailed information\n"
-    L"  IN-FILE        File with with bitcode to optimize\n"
+    L"  -pf PASS-FILE  Loads passes from the specified file\n"
     L"  -o=OUT-FILE    Output file for processed module\n"
     L"  -o=OUT-FILE    Output file for processed module\n"
+    L"  IN-FILE        File with with bitcode to optimize\n"
     L"  OPT-ARGUMENTS  One or more passes to run in sequence\n"
     L"  OPT-ARGUMENTS  One or more passes to run in sequence\n"
     L"\n"
     L"\n"
     L"Text that is traced during optimization is written to the standard output.\n"
     L"Text that is traced during optimization is written to the standard output.\n"
@@ -175,21 +218,51 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
     ProgramAction action = ProgramAction::PrintHelp;
     ProgramAction action = ProgramAction::PrintHelp;
     LPCWSTR inFileName = nullptr;
     LPCWSTR inFileName = nullptr;
     LPCWSTR outFileName = nullptr;
     LPCWSTR outFileName = nullptr;
+    LPCWSTR externalLib = nullptr;
+    LPCWSTR externalFn = nullptr;
+    LPCWSTR passFileName = nullptr;
     const wchar_t **optArgs = nullptr;
     const wchar_t **optArgs = nullptr;
     UINT32 optArgCount = 0;
     UINT32 optArgCount = 0;
 
 
-    if (argc > 1) {
-      int argIdx = 1;
-      LPCWSTR arg = argv_[1];
-      if (wcsieq(arg, L"-?") || wcsieq(arg, L"/?")) {
+    int argIdx = 1;
+    while (argIdx < argc) {
+      LPCWSTR arg = argv_[argIdx];
+      if (wcsieqopt(arg, L"?")) {
         action = ProgramAction::PrintHelp;
         action = ProgramAction::PrintHelp;
       }
       }
-      else if (wcsieq(arg, L"-passes") || wcsieq(arg, L"/passes")) {
+      else if (wcsieqopt(arg, L"passes")) {
         action = ProgramAction::PrintPasses;
         action = ProgramAction::PrintPasses;
       }
       }
-      else if (wcsieq(arg, L"-pass-details") || wcsieq(arg, L"/pass-details")) {
+      else if (wcsieqopt(arg, L"pass-details")) {
         action = ProgramAction::PrintPassesWithDetails;
         action = ProgramAction::PrintPassesWithDetails;
       }
       }
+      else if (wcsieqopt(arg, L"external")) {
+        ++argIdx;
+        if (argIdx == argc) {
+          PrintHelp();
+          return 1;
+        }
+        externalLib = argv_[argIdx];
+      }
+      else if (wcsieqopt(arg, L"external-fn")) {
+        ++argIdx;
+        if (argIdx == argc) {
+          PrintHelp();
+          return 1;
+        }
+        externalFn = argv_[argIdx];
+      }
+      else if (wcsieqopt(arg, L"pf")) {
+        ++argIdx;
+        if (argIdx == argc) {
+          PrintHelp();
+          return 1;
+        }
+        passFileName = argv_[argIdx];
+      }
+      else if (wcsistarts(arg, L"-o=")) {
+        outFileName = argv_[argIdx] + 3;
+      }
       else {
       else {
         action = ProgramAction::RunOptimizer;
         action = ProgramAction::RunOptimizer;
         // See if arg is file input specifier.
         // See if arg is file input specifier.
@@ -201,15 +274,13 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
         else {
         else {
           inFileName = STDIN_FILE_NAME;
           inFileName = STDIN_FILE_NAME;
         }
         }
-        // Look for a file output argument.
-        if (argc > argIdx && wcsistarts(argv_[argIdx], L"-o=")) {
-          outFileName = argv_[argIdx] + 3;
-          argIdx++;
-        }
+
         // The remaining arguments are optimizer args.
         // The remaining arguments are optimizer args.
         optArgs = argv_ + argIdx;
         optArgs = argv_ + argIdx;
         optArgCount = argc - argIdx;
         optArgCount = argc - argIdx;
+        break;
       }
       }
+      ++argIdx;
     }
     }
 
 
     if (action == ProgramAction::PrintHelp) {
     if (action == ProgramAction::PrintHelp) {
@@ -217,11 +288,26 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
       return retVal;
       return retVal;
     }
     }
 
 
+    if (passFileName && optArgCount) {
+      wprintf(L"%s", L"Cannot specify both command-line options and an pass option file.\n");
+      return 1;
+    }
+
+    if (externalLib) {
+      CW2A externalFnA(externalFn, CP_UTF8);
+      IFT(g_DxcSupport.InitializeForDll(externalLib, externalFnA));
+    }
+    else {
+      IFT(g_DxcSupport.Initialize());
+    }
+
     CComPtr<IDxcBlob> pBlob;
     CComPtr<IDxcBlob> pBlob;
     CComPtr<IDxcBlob> pOutputModule;
     CComPtr<IDxcBlob> pOutputModule;
     CComPtr<IDxcBlobEncoding> pOutputText;
     CComPtr<IDxcBlobEncoding> pOutputText;
     CComPtr<IDxcOptimizer> pOptimizer;
     CComPtr<IDxcOptimizer> pOptimizer;
-    IFT(DxcCreateInstance(CLSID_DxcOptimizer, IID_PPV_ARGS(&pOptimizer)));
+    CComPtr<IDxcBlobEncoding> pPassOpts;
+    std::vector<LPCWSTR> passes;
+    IFT(g_DxcSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
     switch (action) {
     switch (action) {
     case ProgramAction::PrintPasses:
     case ProgramAction::PrintPasses:
       pStage = "Printing passes...";
       pStage = "Printing passes...";
@@ -234,6 +320,7 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
     case ProgramAction::RunOptimizer:
     case ProgramAction::RunOptimizer:
       pStage = "Optimizer processing";
       pStage = "Optimizer processing";
       BlobFromFile(inFileName, &pBlob);
       BlobFromFile(inFileName, &pBlob);
+      ReadFileOpts(passFileName, &pPassOpts, passes, &optArgs, &optArgCount);
       IFT(pOptimizer->RunOptimizer(pBlob, optArgs, optArgCount, &pOutputModule, &pOutputText));
       IFT(pOptimizer->RunOptimizer(pBlob, optArgs, optArgCount, &pOutputModule, &pOutputText));
       PrintOptOutput(outFileName, pOutputModule, pOutputText);
       PrintOptOutput(outFileName, pOutputModule, pOutputText);
       break;
       break;

+ 53 - 16
utils/hct/hcttestcmds.cmd

@@ -469,33 +469,70 @@ if %errorlevel% neq 0 (
   exit /b 1
   exit /b 1
 )
 )
 
 
+echo Smoke test for dxopt command line ...
+dxc /Odump /T ps_6_0 smoke.hlsl > passes.txt
+if %errorlevel% neq 0 (
+  echo Failed to /ODump
+  call :cleanup 2>nul
+  exit /b 1
+)
+findstr emit passes.txt 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to find an emit in the default pass configuration.
+  call :cleanup 2>nul
+  exit /b 1
+)
+echo -print-module >> passes.txt
+dxc /T ps_6_0 smoke.hlsl /fcgl > smoke.hl.txt
+if %errorlevel% neq 0 (
+  echo Failed to do a high-level codegen.
+  call :cleanup 2>nul
+  exit /b 1
+)
+dxopt -pf passes.txt -o=smoke.opt.ll smoke.hl.txt >smoke.opt.prn.txt
+if %errorlevel% neq 0 (
+  echo Failed to run the optimizer with default passes.
+  call :cleanup 2>nul
+  exit /b 1
+)
+findstr MODULE-PRINT smoke.opt.prn.txt 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to find the MODULE-PRINT log in the dxcopt output.
+  call :cleanup 2>nul
+  exit /b 1
+)
+
 call :cleanup
 call :cleanup
 exit /b 0
 exit /b 0
 
 
 :cleanup
 :cleanup
-del %CD%\preprocessed.hlsl
-del %CD%\smoke.hlsl.c
-del %CD%\smoke.hlsl.d
-del %CD%\smoke.hlsl.e
-del %CD%\smoke.hlsl.h
-del %CD%\smoke.hlsl.strip
-del %CD%\smoke.cso
+del %CD%\*.lld
 del %CD%\NonUniform.cso
 del %CD%\NonUniform.cso
+del %CD%\NonUniformNoRootSig.cso
+del %CD%\NonUniformRootSig.cso
+del %CD%\TextVS.cso
+del %CD%\nodebug.cso
+del %CD%\noprivate.cso
+del %CD%\noprivdebugroot.cso
+del %CD%\norootsignature.cso
+del %CD%\passes.txt
+del %CD%\preprocessed.hlsl
 del %CD%\private.cso
 del %CD%\private.cso
 del %CD%\private.txt
 del %CD%\private.txt
 del %CD%\private1.txt
 del %CD%\private1.txt
-del %CD%\noprivate.cso
-del %CD%\nodebug.cso
 del %CD%\rootsig.cso
 del %CD%\rootsig.cso
-del %CD%\NonUniformRootSig.cso
-del %CD%\noprivdebugroot.cso
-del %CD%\norootsignature.cso
-del %CD%\NonUniformNoRootSig.cso
-del %CD%\TextVS.cso
-del %CD%\smoke.ll
+del %CD%\smoke.cso
 del %CD%\smoke.cso.ll
 del %CD%\smoke.cso.ll
-del %CD%\*.lld
 del %CD%\smoke.cso.plain.bc
 del %CD%\smoke.cso.plain.bc
+del %CD%\smoke.hl.txt
+del %CD%\smoke.hlsl.c
+del %CD%\smoke.hlsl.d
+del %CD%\smoke.hlsl.e
+del %CD%\smoke.hlsl.h
+del %CD%\smoke.hlsl.strip
+del %CD%\smoke.ll
+del %CD%\smoke.opt.ll
+del %CD%\smoke.opt.prn.txt
 del %CD%\smoke.rebuilt-container.cso
 del %CD%\smoke.rebuilt-container.cso
 del %CD%\smoke.rebuilt-container2.cso
 del %CD%\smoke.rebuilt-container2.cso