[update_(llc_)test_checks.py] Support pre-processing commands
authorAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Wed, 21 Apr 2021 11:19:08 +0000 (12:19 +0100)
committerAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Wed, 28 Apr 2021 11:19:19 +0000 (12:19 +0100)
This has been rather useful in our downstream CHERI target where we want
to run tests both with addrspace(0) and addrspace(200) pointers.
With this patch we can prefix the opt command with
`sed -e 's/addrspace(200)/addrspace(0)/g' -e 's/-A200-P200-G200//g'` to
test both cases using the same IR input.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D95137

llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/pre-process.ll [new file with mode: 0644]
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/pre-process.ll.expected [new file with mode: 0644]
llvm/test/tools/UpdateTestChecks/update_llc_test_checks/pre-process.test [new file with mode: 0644]
llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/pre-process.ll [new file with mode: 0644]
llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/pre-process.ll.expected [new file with mode: 0644]
llvm/test/tools/UpdateTestChecks/update_test_checks/pre-process.test [new file with mode: 0644]
llvm/utils/UpdateTestChecks/common.py
llvm/utils/update_llc_test_checks.py
llvm/utils/update_test_checks.py

diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/pre-process.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/pre-process.ll
new file mode 100644 (file)
index 0000000..4f7f313
--- /dev/null
@@ -0,0 +1,15 @@
+; Test that update_llc_test_checks.py can run pre-processing commands.
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK-ADD
+; RUN: sed 's/add /sub /g' %s | llc -mtriple=x86_64-unknown-unknown \
+; RUN:   | FileCheck %s --check-prefix=CHECK-SUB
+; Check that multiple pre-processing commands are handled
+; RUN: sed 's/add /sub /g' %s | sed 's/i64 /i16 /g' | cat \
+; RUN:  | llc -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK-SUB-I16
+
+define i64 @test_add_constant(i64 %arg) nounwind {
+entry:
+  %a1 = add i64 %arg, 1
+  %a2 = add i64 %a1, 2
+  %a3 = add i64 %a2, 3
+  ret i64 %a3
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/pre-process.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/pre-process.ll.expected
new file mode 100644 (file)
index 0000000..750c951
--- /dev/null
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; Test that update_llc_test_checks.py can run pre-processing commands.
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK-ADD
+; RUN: sed 's/add /sub /g' %s | llc -mtriple=x86_64-unknown-unknown \
+; RUN:   | FileCheck %s --check-prefix=CHECK-SUB
+; Check that multiple pre-processing commands are handled
+; RUN: sed 's/add /sub /g' %s | sed 's/i64 /i16 /g' | cat \
+; RUN:  | llc -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK-SUB-I16
+
+define i64 @test_add_constant(i64 %arg) nounwind {
+; CHECK-ADD-LABEL: test_add_constant:
+; CHECK-ADD:       # %bb.0: # %entry
+; CHECK-ADD-NEXT:    leaq 6(%rdi), %rax
+; CHECK-ADD-NEXT:    retq
+;
+; CHECK-SUB-LABEL: test_add_constant:
+; CHECK-SUB:       # %bb.0: # %entry
+; CHECK-SUB-NEXT:    leaq -6(%rdi), %rax
+; CHECK-SUB-NEXT:    retq
+;
+; CHECK-SUB-I16-LABEL: test_add_constant:
+; CHECK-SUB-I16:       # %bb.0: # %entry
+; CHECK-SUB-I16-NEXT:    # kill: def $edi killed $edi def $rdi
+; CHECK-SUB-I16-NEXT:    leal -6(%rdi), %eax
+; CHECK-SUB-I16-NEXT:    # kill: def $ax killed $ax killed $eax
+; CHECK-SUB-I16-NEXT:    retq
+entry:
+  %a1 = add i64 %arg, 1
+  %a2 = add i64 %a1, 2
+  %a3 = add i64 %a2, 3
+  ret i64 %a3
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/pre-process.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/pre-process.test
new file mode 100644 (file)
index 0000000..c60651c
--- /dev/null
@@ -0,0 +1,10 @@
+# REQUIRES: x86-registered-target
+## Test that update_llc_test_checks.py can run pre-processing commands.
+
+## Test that update_test_checks.py can run pre-processing commands.
+# RUN: cp -f %S/Inputs/pre-process.ll %t.ll && %update_llc_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/pre-process.ll.expected
+## Check that running the script again does not change the result:
+# RUN: %update_llc_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/pre-process.ll.expected
+
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/pre-process.ll b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/pre-process.ll
new file mode 100644 (file)
index 0000000..c082e5e
--- /dev/null
@@ -0,0 +1,18 @@
+; Test that update_test_checks.py can run pre-processing commands.
+; RUN: opt < %s -instsimplify -S | FileCheck %s --check-prefix=CHECK-AS200
+; RUN: sed -e 's/addrspace(200)/addrspace(0)/g' -e 's/-A200-P200-G200//g' %s \
+; RUN:   | opt -instsimplify -S | FileCheck %s --check-prefix=CHECK-AS0
+; Check that multiple pre-processing commands are handled
+; RUN: sed 's/addrspace(200)/addrspace(1)/g' %s | sed 's/-A1-P1-G1//g' \
+; RUN:   | opt -instsimplify -S | FileCheck %s --check-prefix=CHECK-AS1
+; More than two commands should also be fine
+; RUN: cat %s | cat | cat | cat | opt < %s -instsimplify -S \
+; RUN:   | FileCheck %s --check-prefix=CHECK-AS200-NOOP-PRE-PROCESS
+
+target datalayout = "e-m:e-p200:128:128:128:64-p:64:64-A200-P200-G200"
+
+define i8 addrspace(200)* @test_zerogep_in_different_as(i8 addrspace(200)* %arg) addrspace(200) nounwind {
+entry:
+  %ret = getelementptr inbounds i8, i8 addrspace(200)* %arg, i64 0
+  ret i8 addrspace(200)* %ret
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/pre-process.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/pre-process.ll.expected
new file mode 100644 (file)
index 0000000..af98d6d
--- /dev/null
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
+; Test that update_test_checks.py can run pre-processing commands.
+; RUN: opt < %s -instsimplify -S | FileCheck %s --check-prefix=CHECK-AS200
+; RUN: sed -e 's/addrspace(200)/addrspace(0)/g' -e 's/-A200-P200-G200//g' %s \
+; RUN:   | opt -instsimplify -S | FileCheck %s --check-prefix=CHECK-AS0
+; Check that multiple pre-processing commands are handled
+; RUN: sed 's/addrspace(200)/addrspace(1)/g' %s | sed 's/-A1-P1-G1//g' \
+; RUN:   | opt -instsimplify -S | FileCheck %s --check-prefix=CHECK-AS1
+; More than two commands should also be fine
+; RUN: cat %s | cat | cat | cat | opt < %s -instsimplify -S \
+; RUN:   | FileCheck %s --check-prefix=CHECK-AS200-NOOP-PRE-PROCESS
+
+target datalayout = "e-m:e-p200:128:128:128:64-p:64:64-A200-P200-G200"
+
+define i8 addrspace(200)* @test_zerogep_in_different_as(i8 addrspace(200)* %arg) addrspace(200) nounwind {
+; CHECK-AS200-LABEL: define {{[^@]+}}@test_zerogep_in_different_as
+; CHECK-AS200-SAME: (i8 addrspace(200)* [[ARG:%.*]]) addrspace(200) #[[ATTR0:[0-9]+]] {
+; CHECK-AS200-NEXT:  entry:
+; CHECK-AS200-NEXT:    ret i8 addrspace(200)* [[ARG]]
+;
+; CHECK-AS0-LABEL: define {{[^@]+}}@test_zerogep_in_different_as
+; CHECK-AS0-SAME: (i8* [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-AS0-NEXT:  entry:
+; CHECK-AS0-NEXT:    ret i8* [[ARG]]
+;
+; CHECK-AS1-LABEL: define {{[^@]+}}@test_zerogep_in_different_as
+; CHECK-AS1-SAME: (i8 addrspace(1)* [[ARG:%.*]]) addrspace(1) #[[ATTR0:[0-9]+]] {
+; CHECK-AS1-NEXT:  entry:
+; CHECK-AS1-NEXT:    ret i8 addrspace(1)* [[ARG]]
+;
+; CHECK-AS200-NOOP-PRE-PROCESS-LABEL: define {{[^@]+}}@test_zerogep_in_different_as
+; CHECK-AS200-NOOP-PRE-PROCESS-SAME: (i8 addrspace(200)* [[ARG:%.*]]) addrspace(200) #[[ATTR0:[0-9]+]] {
+; CHECK-AS200-NOOP-PRE-PROCESS-NEXT:  entry:
+; CHECK-AS200-NOOP-PRE-PROCESS-NEXT:    ret i8 addrspace(200)* [[ARG]]
+;
+entry:
+  %ret = getelementptr inbounds i8, i8 addrspace(200)* %arg, i64 0
+  ret i8 addrspace(200)* %ret
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/pre-process.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/pre-process.test
new file mode 100644 (file)
index 0000000..389c33b
--- /dev/null
@@ -0,0 +1,6 @@
+## Test that update_test_checks.py can run pre-processing commands.
+# RUN: cp -f %S/Inputs/pre-process.ll %t.ll && %update_test_checks --function-signature %t.ll
+# RUN: diff -u %t.ll %S/Inputs/pre-process.ll.expected
+## Check that running the script again does not change the result:
+# RUN: %update_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/pre-process.ll.expected
index 4598475..449ccb0 100644 (file)
@@ -2,6 +2,7 @@ from __future__ import print_function
 
 import copy
 import glob
+import os
 import re
 import subprocess
 import sys
@@ -141,11 +142,23 @@ def should_add_line_to_output(input_line, prefix_set, skip_global_checks = False
   return True
 
 # Invoke the tool that is being tested.
-def invoke_tool(exe, cmd_args, ir):
+def invoke_tool(exe, cmd_args, ir, preprocess_cmd=None, verbose=False):
   with open(ir) as ir_file:
     # TODO Remove the str form which is used by update_test_checks.py and
     # update_llc_test_checks.py
     # The safer list form is used by update_cc_test_checks.py
+    if preprocess_cmd:
+      # Allow pre-processing the IR file (e.g. using sed):
+      assert isinstance(preprocess_cmd, str)  # TODO: use a list instead of using shell
+      preprocess_cmd = preprocess_cmd.replace('%s', ir).strip()
+      if verbose:
+        print('Pre-processing input file: ', ir, " with command '",
+              preprocess_cmd, "'", sep="", file=sys.stderr)
+      # Python 2.7 doesn't have subprocess.DEVNULL:
+      with open(os.devnull, 'w') as devnull:
+        pp = subprocess.Popen(preprocess_cmd, shell=True, stdin=devnull,
+                              stdout=subprocess.PIPE)
+        ir_file = pp.stdout
     if isinstance(cmd_args, list):
       stdout = subprocess.check_output([exe] + cmd_args, stdin=ir_file)
     else:
index 614cd07..0f1117b 100755 (executable)
@@ -60,8 +60,13 @@ def main():
         common.warn('Skipping unparseable RUN line: ' + l)
         continue
 
-      commands = [cmd.strip() for cmd in l.split('|', 1)]
-      llc_cmd = commands[0]
+      commands = [cmd.strip() for cmd in l.split('|')]
+      assert len(commands) >= 2
+      preprocess_cmd = None
+      if len(commands) > 2:
+        preprocess_cmd = " | ".join(commands[:-2])
+      llc_cmd = commands[-2]
+      filecheck_cmd = commands[-1]
       llc_tool = llc_cmd.split(' ')[0]
 
       triple_in_cmd = None
@@ -74,9 +79,6 @@ def main():
       if m:
         march_in_cmd = m.groups()[0]
 
-      filecheck_cmd = ''
-      if len(commands) > 1:
-        filecheck_cmd = commands[1]
       common.verify_filecheck_prefixes(filecheck_cmd)
       if llc_tool not in LLC_LIKE_TOOLS:
         common.warn('Skipping non-llc RUN line: ' + l)
@@ -97,7 +99,8 @@ def main():
 
       # FIXME: We should use multiple check prefixes to common check lines. For
       # now, we just ignore all but the last.
-      run_list.append((check_prefixes, llc_cmd_args, triple_in_cmd, march_in_cmd))
+      run_list.append((check_prefixes, llc_tool, llc_cmd_args, preprocess_cmd,
+                       triple_in_cmd, march_in_cmd))
 
     if ti.path.endswith('.mir'):
       check_indent = '  '
@@ -113,12 +116,13 @@ def main():
             'replace_function_regex': []}),
         scrubber_args=[ti.args])
 
-    for prefixes, llc_args, triple_in_cmd, march_in_cmd in run_list:
+    for prefixes, llc_tool, llc_args, preprocess_cmd, triple_in_cmd, march_in_cmd in run_list:
       common.debug('Extracted LLC cmd:', llc_tool, llc_args)
       common.debug('Extracted FileCheck prefixes:', str(prefixes))
 
       raw_tool_output = common.invoke_tool(ti.args.llc_binary or llc_tool,
-                                           llc_args, ti.path)
+                                           llc_args, ti.path, preprocess_cmd,
+                                           verbose=ti.args.verbose)
       triple = triple_in_cmd or triple_in_ir
       if not triple:
         triple = asm.get_triple_from_march(march_in_cmd)
index 4a55ac6..e240c6c 100755 (executable)
@@ -80,7 +80,13 @@ def main():
         common.warn('Skipping unparseable RUN line: ' + l)
         continue
 
-      (tool_cmd, filecheck_cmd) = tuple([cmd.strip() for cmd in l.split('|', 1)])
+      commands = [cmd.strip() for cmd in l.split('|')]
+      assert len(commands) >= 2
+      preprocess_cmd = None
+      if len(commands) > 2:
+        preprocess_cmd = " | ".join(commands[:-2])
+      tool_cmd = commands[-2]
+      filecheck_cmd = commands[-1]
       common.verify_filecheck_prefixes(filecheck_cmd)
       if not tool_cmd.startswith(opt_basename + ' '):
         common.warn('Skipping non-%s RUN line: %s' % (opt_basename, l))
@@ -101,7 +107,7 @@ def main():
 
       # FIXME: We should use multiple check prefixes to common check lines. For
       # now, we just ignore all but the last.
-      prefix_list.append((check_prefixes, tool_cmd_args))
+      prefix_list.append((check_prefixes, tool_cmd_args, preprocess_cmd))
 
     global_vars_seen_dict = {}
     builder = common.FunctionTestBuilder(
@@ -109,12 +115,13 @@ def main():
       flags=ti.args,
       scrubber_args=[])
 
-    for prefixes, opt_args in prefix_list:
+    for prefixes, opt_args, preprocess_cmd in prefix_list:
       common.debug('Extracted opt cmd: ' + opt_basename + ' ' + opt_args)
       common.debug('Extracted FileCheck prefixes: ' + str(prefixes))
 
       raw_tool_output = common.invoke_tool(ti.args.opt_binary, opt_args,
-                                           ti.path)
+                                           ti.path, preprocess_cmd=preprocess_cmd,
+                                           verbose=ti.args.verbose)
       builder.process_run_line(common.OPT_FUNCTION_RE, common.scrub_body,
               raw_tool_output, prefixes)
 
@@ -122,7 +129,7 @@ def main():
     is_in_function = False
     is_in_function_start = False
     has_checked_pre_function_globals = False
-    prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes])
+    prefix_set = set([prefix for prefixes, _, _ in prefix_list for prefix in prefixes])
     common.debug('Rewriting FileCheck prefixes:', str(prefix_set))
     output_lines = []