瀏覽代碼

Add `-verify` flag to DXC (#5032)

Chris B 2 年之前
父節點
當前提交
740dd0951b

+ 1 - 0
include/dxc/Support/HLSLOptions.h

@@ -210,6 +210,7 @@ public:
   bool NewInlining = false; // OPT_fnew_inlining_behavior
   bool TimeReport = false; // OPT_ftime_report
   std::string TimeTrace = ""; // OPT_ftime_trace[EQ]
+  bool VerifyDiagnostics = false; // OPT_verify
 
   // Optimization pass enables, disables and selects
   std::map<std::string, bool> DxcOptimizationToggles; // OPT_opt_enable & OPT_opt_disable

+ 4 - 0
include/dxc/Support/HLSLOptions.td

@@ -187,6 +187,10 @@ def ftime_trace_EQ : Joined<["-"], "ftime-trace=">,
   Group<hlslcomp_Group>, Flags<[CoreOption]>,
   HelpText<"Print hierchial time tracing to file">;
 
+def verify : Joined<["-"], "verify">,
+  Group<hlslcomp_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Verify diagnostic output using comment directives">;
+
 /*
 def fno_caret_diagnostics : Flag<["-"], "fno-caret-diagnostics">, Group<hlslcomp_Group>,
  Flags<[CoreOption]>;

+ 1 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -788,6 +788,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
       Args.hasFlag(OPT_fnew_inlining_behavior, OPT_INVALID, false);
   opts.TimeReport = Args.hasFlag(OPT_ftime_report, OPT_INVALID, false);
   opts.TimeTrace = Args.hasFlag(OPT_ftime_trace, OPT_INVALID, false) ? "-" : "";
+  opts.VerifyDiagnostics = Args.hasFlag(OPT_verify, OPT_INVALID, false);
   if (Args.hasArg(OPT_ftime_trace_EQ))
     opts.TimeTrace = Args.getLastArgValue(OPT_ftime_trace_EQ);
   opts.EnablePayloadQualifiers = Args.hasFlag(OPT_enable_payload_qualifiers, OPT_INVALID,

+ 11 - 0
tools/clang/test/DXC/diagnostic-verifier.hlsl

@@ -0,0 +1,11 @@
+// RUN: %dxc -T lib_6_3 %s -verify
+// RUN: not %dxc -T lib_6_3 %s -DEXTRA_ERROR -verify 2>&1 | FileCheck %s
+
+foo(); // expected-error {{HLSL requires a type specifier for all declarations}}
+
+#ifdef EXTRA_ERROR
+baz(); // Woah!
+#endif
+
+// CHECK: error: 'error' diagnostics seen but not expected: 
+// CHECK: File {{.*}}diagnostic-verifier.hlsl Line 7: HLSL requires a type specifier for all declarations

+ 2 - 2
tools/clang/tools/dxclib/dxc.cpp

@@ -316,7 +316,7 @@ int DxcContext::ActOnBlob(IDxcBlob *pBlob, IDxcBlob *pDebugBlob, LPCWSTR pDebugB
   }
 
   // Text output.
-  if (m_Opts.AstDump || m_Opts.OptDump) {
+  if (m_Opts.AstDump || m_Opts.OptDump || m_Opts.VerifyDiagnostics) {
     WriteBlobToConsole(pBlob);
     return retVal;
   }
@@ -867,7 +867,7 @@ int DxcContext::Compile() {
   HRESULT status;
   IFT(pCompileResult->GetStatus(&status));
   if (SUCCEEDED(status) || m_Opts.AstDump || m_Opts.OptDump ||
-      m_Opts.DumpDependencies) {
+      m_Opts.DumpDependencies || m_Opts.VerifyDiagnostics) {
     CComPtr<IDxcBlob> pProgram;
     IFT(pCompileResult->GetResult(&pProgram));
     if (pProgram.p != nullptr) {

+ 21 - 3
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -760,7 +760,8 @@ public:
       IFT(pOutputStream.QueryInterface(&pOutputBlob));
 
       primaryOutput.kind = DXC_OUT_OBJECT;
-      if (opts.AstDump || opts.OptDump || opts.DumpDependencies)
+      if (opts.AstDump || opts.OptDump || opts.DumpDependencies ||
+          opts.VerifyDiagnostics)
         primaryOutput.kind = DXC_OUT_TEXT;
       else if (isPreprocessing)
         primaryOutput.kind = DXC_OUT_HLSL;
@@ -919,7 +920,8 @@ public:
         // validator can be used as a fallback.
         produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump &&
                                !opts.OptDump && rootSigMajor == 0 &&
-                               !opts.DumpDependencies;
+                               !opts.DumpDependencies &&
+                               !opts.VerifyDiagnostics;
         needsValidation = produceFullContainer && !opts.DisableValidation;
 
         if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_x") {
@@ -1012,6 +1014,13 @@ public:
               pOutputBlob, &compiler.getDiagnostics());
           }
         }
+      } else if (opts.VerifyDiagnostics) {
+        SyntaxOnlyAction action;
+        FrontendInputFile file(pUtf8SourceName, IK_HLSL);
+        if (action.BeginSourceFile(compiler, file)) {
+          action.Execute();
+          action.EndSourceFile();
+        }
       }
       // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
@@ -1289,7 +1298,15 @@ public:
 
       IFT(primaryOutput.SetObject(pOutputBlob, opts.DefaultTextCodePage));
       IFT(pResult->SetOutput(primaryOutput));
-      IFT(pResult->SetStatusAndPrimaryResult(hasErrorOccurred ? E_FAIL : S_OK, primaryOutput.kind));
+      
+      // It is possible for errors to occur, but the diagnostic or AST consumers
+      // can recover from them, or translate them to mean something different.
+      // This happens with the `-verify` flag where an error may be expected.
+      // The correct way to identify errors in this case is to query the
+      // DiagnosticClient for the number of errors.
+      unsigned NumErrors = compiler.getDiagnostics().getClient()->getNumErrors();
+      IFT(pResult->SetStatusAndPrimaryResult(NumErrors > 0 ? E_FAIL : S_OK,
+                                             primaryOutput.kind));
       IFT(pResult->QueryInterface(riid, ppResult));
 
       hr = S_OK;
@@ -1401,6 +1418,7 @@ public:
     compiler.HlslLangExtensions = helper;
     compiler.getDiagnosticOpts().ShowOptionNames = Opts.ShowOptionNames ? 1 : 0;
     compiler.getDiagnosticOpts().Warnings = std::move(Opts.Warnings);
+    compiler.getDiagnosticOpts().VerifyDiagnostics = Opts.VerifyDiagnostics;
     compiler.createDiagnostics(diagPrinter, false);
     // don't output warning to stderr/file if "/no-warnings" is present.
     compiler.getDiagnostics().setIgnoreAllWarnings(!Opts.OutputWarnings);

+ 5 - 0
utils/hct/hcttestcmds.cmd

@@ -500,6 +500,11 @@ call :run dxc.exe /T ps_6_0 "%testfiles%\Inputs\bom-main-utf8.hlsl"
 call :run dxc.exe /T ps_6_0 "%testfiles%\Inputs\bom-main-utf16le.hlsl"
 if %Failed% neq 0 goto :failed
 
+set testname=DXC Diagnostic Verifier
+call :run dxc.exe /T lib_6_3 "%testfiles%\diagnostic-verifier.hlsl" -verify
+call :run-fail dxc.exe /T lib_6_3 -DEXTRA_ERROR "%testfiles%\diagnostic-verifier.hlsl" -verify
+if %Failed% neq 0 goto :failed
+
 rem SPIR-V Change Starts
 echo Smoke test for SPIR-V CodeGen ...
 set spirv_smoke_success=0

+ 7 - 0
utils/not/not.cpp

@@ -43,6 +43,13 @@ int main(int argc, const char **argv) {
   int Result = sys::ExecuteAndWait(*Program, argv, nullptr, nullptr, 0, 0,
                                    &ErrMsg);
 #ifdef _WIN32
+  // HLSL Change Start
+  // DXC returns HRESULT values as return codes, which on Windows means the
+  // process status is always negative for failures.
+  if (Result == 0)
+    return 1;
+  return 0;
+  // HLSL Change End
   // Handle abort() in msvcrt -- It has exit code as 3.  abort(), aka
   // unreachable, should be recognized as a crash.  However, some binaries use
   // exit code 3 on non-crash failure paths, so only do this if we expect a