Update parse_hlsl_errors script

- Split text to search by whether it's for fxc or dxc, or both
- Search from top-down, not bottom-up
- Improve output to emit errors with [fxc] or [dxc] prefix
- Add '-ir-only' argument

Change-Id: I8a8782b05a7d7a878dfd91b958ad08dcb7f76fb2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/207175
Reviewed-by: James Price <jrprice@google.com>
diff --git a/test/tint/parse_hlsl_errors.py b/test/tint/parse_hlsl_errors.py
index 2c51e51..68a4978 100644
--- a/test/tint/parse_hlsl_errors.py
+++ b/test/tint/parse_hlsl_errors.py
@@ -40,56 +40,92 @@
 parser.add_argument('--list-files', dest='list_files', action='store_true')
 parser.add_argument('--no-list-files', dest='list_files', action='store_false')
 parser.set_defaults(list_files=True)
+parser.add_argument('--ir-only', dest='ir_only', action='store_false')
+parser.set_defaults(ir_only=False)
 args = parser.parse_args()
 
-def add_error(error_to_file, error, file):
-    if not error in error_to_file:
-        error_to_file[error] = [file]
+def add_error(error_to_files, error, file):
+    error = error.strip()
+    if not error in error_to_files:
+        error_to_files[error] = [file]
     else:
-        error_to_file[error].append(file)
+        error_to_files[error].append(file)
 
-def find_and_print_errors(glob_pathname):
+def find_error(f, all_lines, error_to_files, is_fxc):
+    # Search for specific errors from top to bottom
+    for line in all_lines:
+        # Both
+        if line.startswith('test timed out after'):
+            add_error(error_to_files, line, f)
+            return True
+        if 'internal compiler error' in line:
+            add_error(error_to_files, line, f)
+            return True
+        if line.startswith('tint executable returned error:'):
+            add_error(error_to_files, line, f)
+            return True
+        m = re.search('Failed to generate:.*?(error:.*)', line)
+        if m:
+            add_error(error_to_files, m.groups()[0], f)
+            return True
+        # DXC
+        if not is_fxc:
+            if line.startswith('error: validation errors'):
+                continue # Skip line, next line should have better error
+
+            if line.startswith('error:'):
+                add_error(error_to_files, line, f)
+                return True
+
+            m = re.search('.*\.hlsl:[0-9]+:.*?(error.*)', line) # DXC???
+            if m:
+                add_error(error_to_files, m.groups()[0], f)
+                return True
+        # FXC
+        else:
+            if line.startswith('internal error:'):
+                add_error(error_to_files, line, f)
+                return True
+            m = re.search('error( X[0-9]+)+?:(.*)', line)
+            if m:
+                add_error(error_to_files, m.group(), f)
+                return True
+    return False
+
+
+def find_and_print_errors(glob_pathname, is_fxc):
     files = glob.glob(glob_pathname, recursive=True)
-    error_to_file = {}
+    error_to_files = {}
 
     for f in files:
         found_error = False
         with open(f, "r") as fs:
             all_lines = fs.readlines()
             first_line = all_lines[0]
-            if not first_line.startswith("SKIP:"):
+            if not first_line.startswith("SKIP:"): # Only process SKIPs
                 continue
-            # The most refined errors are printed at the end, so search for error lines from bottom-up
-            all_lines.reverse()
-            for line in all_lines:
-                m = re.search('.*\.hlsl:[0-9]+:.*?(error.*)', line)
-                if m:
-                    add_error(error_to_file, m.groups()[0], f)
-                    found_error = True
-                else:
-                    m = re.search('error( X[0-9]+)*?:(.*)', line)
-                    if m:
-                        add_error(error_to_file, m.group(), f)
-                        found_error = True
-                    else:
-                        if "exit status" in line:
-                            add_error(error_to_file, line, f)
-                            found_error = True
-                if found_error:
-                    break # Stop on first error string found
+            if first_line.startswith("SKIP: INVALID"): # Except for INVALIDs
+                continue
+            found_error = find_error(f, all_lines, error_to_files, is_fxc)
 
         if not found_error:
             # If no error message was found, add the SKIP line as it may contain the reason for skipping
-            add_error(error_to_file, first_line.strip(), f)
+            add_error(error_to_files, first_line, f)
 
-    for error,files in sorted(error_to_file.items()):
-        print('{} (count: {})'.format(error, len(files)))
+    for error,files in sorted(error_to_files.items()):
+        print('[{}] {} (count: {})'.format('fxc' if is_fxc else 'dxc', error, len(files)))
         if args.list_files:
             for f in files:
                 print('\t{}'.format(f))
 
-print("=== FXC ===")
-find_and_print_errors('./**/*.fxc.hlsl')
 
-print("=== DXC ===")
-find_and_print_errors('./**/*.dxc.hlsl')
+if args.ir_only:
+    print("=== FXC (IR only) ===")
+    find_and_print_errors('./**/*.ir.fxc.hlsl', is_fxc=True)
+    print("=== DXC (IR only) ===")
+    find_and_print_errors('./**/*.ir.dxc.hlsl', is_fxc=False)
+else:
+    print("=== FXC ===")
+    find_and_print_errors('./**/*.fxc.hlsl', is_fxc=True)
+    print("=== DXC ===")
+    find_and_print_errors('./**/*.dxc.hlsl', is_fxc=False)