[clang] [update_cc_test_checks] Use lit's shell to run commands (PR #65333)

Alexander Richardson via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 5 08:17:05 PDT 2023


https://github.com/arichardson created https://github.com/llvm/llvm-project/pull/65333:

I was trying to update a test that redirected stderr to a file and hit
errors because the `2>%t.out` was being passed as a positional argument to
clang. Instead of re-implementing basic shell parsing in this script, we
can reuse lit's internal shell to run these commands and handle
redirection and pipelines.

A more minimal fix could have been to use the shell=True parameter in
python's subprocess modules, but this would not work e.g. on Windows.
Additionally, I am planning to simplify the common.py infrastructure by
reusing the shell helpers from lit and this is the first step in that
direction.

>From e3e754390b000fc8b5aa737c112f33ee0be42a8e Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 1 Sep 2023 15:42:53 -0700
Subject: [PATCH 1/2] [UpdateTestChecks] Add tests for using shell redirects

While update_test_checks and update_llc_test_checks handle these correctly,
it does not currently work in update_cc_test_checks.
---
 .../Inputs/shell-redirection.c                |  9 +++++++
 .../Inputs/shell-redirection.c.expected       | 26 +++++++++++++++++++
 .../shell-redirection.test                    |  8 ++++++
 .../Inputs/shell-redirection.ll               |  9 +++++++
 .../Inputs/shell-redirection.ll.expected      | 21 +++++++++++++++
 .../shell-redirection.test                    |  3 +++
 .../Inputs/shell-redirection.ll               | 10 +++++++
 .../Inputs/shell-redirection.ll.expected      | 17 ++++++++++++
 .../update_test_checks/shell-redirection.test |  3 +++
 9 files changed, 106 insertions(+)
 create mode 100644 clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c
 create mode 100644 clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c.expected
 create mode 100644 clang/test/utils/update_cc_test_checks/shell-redirection.test
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll.expected
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_llc_test_checks/shell-redirection.test
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll.expected
 create mode 100644 llvm/test/tools/UpdateTestChecks/update_test_checks/shell-redirection.test

diff --git a/clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c b/clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c
new file mode 100644
index 000000000000000..2ca26ea3eed38d8
--- /dev/null
+++ b/clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c
@@ -0,0 +1,9 @@
+/// Check that shell redirections in the RUN line are handled
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm < %s 2>/dev/null | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm \
+// RUN:   -disable-O0-optnone -o - %s 2>&1 | opt -S -passes=mem2reg \
+// RUN:   | FileCheck %s --check-prefix=MEM2REG
+
+int test(int a, int b) {
+  return a + b;
+}
diff --git a/clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c.expected b/clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c.expected
new file mode 100644
index 000000000000000..7f78650f03018c9
--- /dev/null
+++ b/clang/test/utils/update_cc_test_checks/Inputs/shell-redirection.c.expected
@@ -0,0 +1,26 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+/// Check that shell redirections in the RUN line are handled
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm < %s 2>/dev/null | FileCheck %s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -emit-llvm \
+// RUN:   -disable-O0-optnone -o - %s 2>&1 | opt -S -passes=mem2reg \
+// RUN:   | FileCheck %s --check-prefix=MEM2REG
+
+// CHECK-LABEL: @test(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4
+// CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
+// CHECK-NEXT:    ret i32 [[ADD]]
+//
+// MEM2REG-LABEL: @test(
+// MEM2REG-NEXT:  entry:
+// MEM2REG-NEXT:    [[ADD:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
+// MEM2REG-NEXT:    ret i32 [[ADD]]
+//
+int test(int a, int b) {
+  return a + b;
+}
diff --git a/clang/test/utils/update_cc_test_checks/shell-redirection.test b/clang/test/utils/update_cc_test_checks/shell-redirection.test
new file mode 100644
index 000000000000000..bcb73f0ee72c8ba
--- /dev/null
+++ b/clang/test/utils/update_cc_test_checks/shell-redirection.test
@@ -0,0 +1,8 @@
+## Check that update_cc_test_checks can parse RUN lines with shell redirection
+## This currently fails with errors such as:
+## error: error reading '<': No such file or directory
+## error: error reading '2>/dev/null': No such file or directory
+# FIXME: these commands should succeed
+# RUN: cp -f %S/Inputs/shell-redirection.c %t.c && not %update_cc_test_checks %t.c
+# RUN: not diff -u %t.c %S/Inputs/shell-redirection.c.expected
+
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll
new file mode 100644
index 000000000000000..b0d7187b3c4fa86
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll
@@ -0,0 +1,9 @@
+;; Check that we can parse RUN lines that have shell redirections
+; RUN: llc -mtriple=x86_64 %s -o - 2>/dev/null | FileCheck %s --check-prefix=I32
+; RUN: llc < %s -mtriple=x86_64 2>&1 | FileCheck %s --check-prefix=I32
+; RUN: sed 's/i32/i64/g' %s | llc -mtriple=x86_64 2>&1 | FileCheck %s --check-prefix=I64
+
+define i32 @add(i32 %X, i32 %Y) {
+  %Q = add i32 %X, %Y
+  ret i32 %Q
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll.expected
new file mode 100644
index 000000000000000..5ec6e5c7c0743ab
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/shell-redirection.ll.expected
@@ -0,0 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+;; Check that we can parse RUN lines that have shell redirections
+; RUN: llc -mtriple=x86_64 %s -o - 2>/dev/null | FileCheck %s --check-prefix=I32
+; RUN: llc < %s -mtriple=x86_64 2>&1 | FileCheck %s --check-prefix=I32
+; RUN: sed 's/i32/i64/g' %s | llc -mtriple=x86_64 2>&1 | FileCheck %s --check-prefix=I64
+
+define i32 @add(i32 %X, i32 %Y) {
+; I32-LABEL: add:
+; I32:       # %bb.0:
+; I32-NEXT:    # kill: def $esi killed $esi def $rsi
+; I32-NEXT:    # kill: def $edi killed $edi def $rdi
+; I32-NEXT:    leal (%rdi,%rsi), %eax
+; I32-NEXT:    retq
+;
+; I64-LABEL: add:
+; I64:       # %bb.0:
+; I64-NEXT:    leaq (%rdi,%rsi), %rax
+; I64-NEXT:    retq
+  %Q = add i32 %X, %Y
+  ret i32 %Q
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/shell-redirection.test b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/shell-redirection.test
new file mode 100644
index 000000000000000..61ea700cd95e21b
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/shell-redirection.test
@@ -0,0 +1,3 @@
+## Check that update_llc_test_checks can parse RUN lines with shell redirection
+# RUN: cp -f %S/Inputs/shell-redirection.ll %t.ll && %update_llc_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/shell-redirection.ll.expected
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll
new file mode 100644
index 000000000000000..5ca4c81ea1d968f
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll
@@ -0,0 +1,10 @@
+;; Check that we can parse RUN lines that have shell redirections
+; RUN: opt %s -passes=instsimplify -S -o - 2>/dev/null | FileCheck %s --check-prefix=I32
+; RUN: opt < %s -passes=instsimplify -S 2>&1 | FileCheck %s --check-prefix=I32
+; RUN: sed 's/i32/i64/g' %s | opt -passes=instsimplify -S | FileCheck %s --check-prefix=I64
+
+define i32 @common_sub_operand(i32 %X, i32 %Y) {
+  %Z = sub i32 %X, %Y
+  %Q = add i32 %Z, %Y
+  ret i32 %Q
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll.expected b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll.expected
new file mode 100644
index 000000000000000..f21e3f944512944
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/Inputs/shell-redirection.ll.expected
@@ -0,0 +1,17 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+;; Check that we can parse RUN lines that have shell redirections
+; RUN: opt %s -passes=instsimplify -S -o - 2>/dev/null | FileCheck %s --check-prefix=I32
+; RUN: opt < %s -passes=instsimplify -S 2>&1 | FileCheck %s --check-prefix=I32
+; RUN: sed 's/i32/i64/g' %s | opt -passes=instsimplify -S | FileCheck %s --check-prefix=I64
+
+define i32 @common_sub_operand(i32 %X, i32 %Y) {
+; I32-LABEL: @common_sub_operand(
+; I32-NEXT:    ret i32 [[X:%.*]]
+;
+; I64-LABEL: @common_sub_operand(
+; I64-NEXT:    ret i64 [[X:%.*]]
+;
+  %Z = sub i32 %X, %Y
+  %Q = add i32 %Z, %Y
+  ret i32 %Q
+}
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/shell-redirection.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/shell-redirection.test
new file mode 100644
index 000000000000000..29a3219c424a32e
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/shell-redirection.test
@@ -0,0 +1,3 @@
+## Check that update_test_checks can parse RUN lines with shell redirection
+# RUN: cp -f %S/Inputs/shell-redirection.ll %t.ll && %update_test_checks %t.ll
+# RUN: diff -u %t.ll %S/Inputs/shell-redirection.ll.expected

>From 849588189cb47c469103d1dda02014cc8056dba1 Mon Sep 17 00:00:00 2001
From: Alex Richardson <alexrichardson at google.com>
Date: Fri, 1 Sep 2023 15:42:56 -0700
Subject: [PATCH 2/2] [update_cc_test_checks] Use lit's shell to run commands

I was trying to update a test that redirected stderr to a file and hit
errors because the 2>%t.out was being passed as a positional argument to
clang. Instead of re-implementing basic shell parsing in this script, we
can reuse lit's internal shell to run these commands and handle
redirection and pipelines.

A more minimal fix could have been to use the shell=True parameter in
python's subprocess modules, but this would not work e.g. on Windows.
Additionally, I am planning to simplify the common.py infrastructure by
reusing the shell helpers from lit and this is the first step in that
direction.
---
 .../shell-redirection.test                    |   5 +-
 llvm/utils/UpdateTestChecks/common.py         |  18 ++
 llvm/utils/lit/lit/ShCommands.py              |   2 +-
 llvm/utils/update_cc_test_checks.py           | 159 +++++++++---------
 4 files changed, 99 insertions(+), 85 deletions(-)

diff --git a/clang/test/utils/update_cc_test_checks/shell-redirection.test b/clang/test/utils/update_cc_test_checks/shell-redirection.test
index bcb73f0ee72c8ba..3e6a0cc56132657 100644
--- a/clang/test/utils/update_cc_test_checks/shell-redirection.test
+++ b/clang/test/utils/update_cc_test_checks/shell-redirection.test
@@ -2,7 +2,6 @@
 ## This currently fails with errors such as:
 ## error: error reading '<': No such file or directory
 ## error: error reading '2>/dev/null': No such file or directory
-# FIXME: these commands should succeed
-# RUN: cp -f %S/Inputs/shell-redirection.c %t.c && not %update_cc_test_checks %t.c
-# RUN: not diff -u %t.c %S/Inputs/shell-redirection.c.expected
+# RUN: cp -f %S/Inputs/shell-redirection.c %t.c && %update_cc_test_checks %t.c
+# RUN: diff -u %t.c %S/Inputs/shell-redirection.c.expected
 
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index 22c05322d9c7dbc..0f075d39f286907 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -12,6 +12,11 @@
 
 from typing import List
 
+sys.path.append(os.path.join(os.path.dirname(__file__), "../lit"))
+from lit.TestRunner import ShellEnvironment, executeShCmd, ShellCommandResult
+from lit.ShUtil import Pipeline
+
+
 ##### Common utilities for update_*test_checks.py
 
 
@@ -464,6 +469,19 @@ def invoke_tool(exe, cmd_args, ir, preprocess_cmd=None, verbose=False):
     return stdout.replace("\r\n", "\n")
 
 
+def execute_pipeline(commands: Pipeline) -> "list[ShellCommandResult]":
+    shenv = ShellEnvironment(os.getcwd(), os.environ)
+    results: "list[ShellCommandResult]" = []
+    exitcode, _ = executeShCmd(commands, shenv, results)
+    if exitcode != 0:
+        sys.stderr.write("Failed to run " + str(commands) + "\n")
+        for result in results:
+            sys.stderr.write(result.stderr)
+            sys.stderr.write(result.stdout)
+        sys.exit(3)
+    return results
+
+
 ##### LLVM IR parser
 RUN_LINE_RE = re.compile(r"^\s*(?://|[;#])\s*RUN:\s*(.*)$")
 CHECK_PREFIX_RE = re.compile(r"--?check-prefix(?:es)?[= ](\S+)")
diff --git a/llvm/utils/lit/lit/ShCommands.py b/llvm/utils/lit/lit/ShCommands.py
index 68655a41d7934b7..0baf8a2fd6ee5e1 100644
--- a/llvm/utils/lit/lit/ShCommands.py
+++ b/llvm/utils/lit/lit/ShCommands.py
@@ -62,7 +62,7 @@ def resolve(self, cwd):
 
 
 class Pipeline:
-    def __init__(self, commands, negate=False, pipe_err=False):
+    def __init__(self, commands: "list[Command]", negate=False, pipe_err=False):
         self.commands = commands
         self.negate = negate
         self.pipe_err = pipe_err
diff --git a/llvm/utils/update_cc_test_checks.py b/llvm/utils/update_cc_test_checks.py
index e96d4167e6567f4..00650debde4e9a9 100755
--- a/llvm/utils/update_cc_test_checks.py
+++ b/llvm/utils/update_cc_test_checks.py
@@ -26,6 +26,7 @@
 import tempfile
 
 from UpdateTestChecks import common
+from lit.ShUtil import ShParser, Pipeline, Command
 
 SUBST = {
     "%clang": [],
@@ -34,29 +35,22 @@
 }
 
 
-def get_line2func_list(args, clang_args):
+def get_line2func_list(clang_cmd: Command):
     ret = collections.defaultdict(list)
     # Use clang's JSON AST dump to get the mangled name
-    json_dump_args = [args.clang] + clang_args + ["-fsyntax-only", "-o", "-"]
+    json_dump_args = clang_cmd.args + ["-fsyntax-only", "-o", "/dev/null"]
     if "-cc1" not in json_dump_args:
         # For tests that invoke %clang instead if %clang_cc1 we have to use
         # -Xclang -ast-dump=json instead:
         json_dump_args.append("-Xclang")
     json_dump_args.append("-ast-dump=json")
     common.debug("Running", " ".join(json_dump_args))
-
-    popen = subprocess.Popen(
-        json_dump_args,
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-        universal_newlines=True,
+    # Ignore the output redirections, only keep the input file ones.
+    new_redirects = [x for x in clang_cmd.redirects if x[0][0] == "<"]
+    results = common.execute_pipeline(
+        Pipeline([Command(json_dump_args, new_redirects)])
     )
-    stdout, stderr = popen.communicate()
-    if popen.returncode != 0:
-        sys.stderr.write("Failed to run " + " ".join(json_dump_args) + "\n")
-        sys.stderr.write(stderr)
-        sys.stderr.write(stdout)
-        sys.exit(2)
+    stdout = results[0].stdout
 
     # Parse the clang JSON and add all children of type FunctionDecl.
     # TODO: Should we add checks for global variables being emitted?
@@ -246,26 +240,14 @@ def config():
     return args, parser
 
 
-def get_function_body(builder, args, filename, clang_args, extra_commands, prefixes):
+def get_function_body(
+    builder, args, filename, clang_pipeline: "list[Command]", prefixes
+):
     # TODO Clean up duplication of asm/common build_function_body_dictionary
     # Invoke external tool and extract function bodies.
-    raw_tool_output = common.invoke_tool(args.clang, clang_args, filename)
-    for extra_command in extra_commands:
-        extra_args = shlex.split(extra_command)
-        with tempfile.NamedTemporaryFile() as f:
-            f.write(raw_tool_output.encode())
-            f.flush()
-            if extra_args[0] == "opt":
-                if args.opt is None:
-                    print(
-                        filename,
-                        "needs to run opt. " "Please specify --llvm-bin or --opt",
-                        file=sys.stderr,
-                    )
-                    sys.exit(1)
-                extra_args[0] = args.opt
-            raw_tool_output = common.invoke_tool(extra_args[0], extra_args[1:], f.name)
-    if "-emit-llvm" in clang_args:
+    results = common.execute_pipeline(Pipeline(clang_pipeline))
+    raw_tool_output = results[-1].stdout.replace("\r\n", "\n")
+    if "-emit-llvm" in clang_pipeline[0].args:
         builder.process_run_line(
             common.OPT_FUNCTION_RE, common.scrub_body, raw_tool_output, prefixes, False
         )
@@ -279,18 +261,6 @@ def get_function_body(builder, args, filename, clang_args, extra_commands, prefi
         sys.exit(1)
 
 
-def exec_run_line(exe):
-    popen = subprocess.Popen(
-        exe, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
-    )
-    stdout, stderr = popen.communicate()
-    if popen.returncode != 0:
-        sys.stderr.write("Failed to run " + " ".join(exe) + "\n")
-        sys.stderr.write(stderr)
-        sys.stderr.write(stdout)
-        sys.exit(3)
-
-
 def main():
     initial_args, parser = config()
     script_name = os.path.basename(__file__)
@@ -306,52 +276,79 @@ def main():
         run_list = []
         line2func_list = collections.defaultdict(list)
 
-        subs = {
-            "%s": ti.path,
-            "%t": tempfile.NamedTemporaryFile().name,
-            "%S": os.path.dirname(ti.path),
-        }
+        subs = [
+            ("%s", ti.path),
+            ("%t", tempfile.NamedTemporaryFile().name),
+            ("%S", os.path.dirname(ti.path)),
+        ]
 
         for l in ti.run_lines:
-            commands = [cmd.strip() for cmd in l.split("|")]
-
+            pipeline = ShParser(l, win32Escapes=False, pipefail=False).parse()
+            if not isinstance(pipeline, Pipeline):
+                # Could be a sequence separated by &&/||/; but we don't handle that yet.
+                print(
+                    "WARNING: RUN: line is too complex for this script: ",
+                    pipeline,
+                    file=sys.stderr,
+                )
+                continue
             triple_in_cmd = None
-            m = common.TRIPLE_ARG_RE.search(commands[0])
+            clang_cmd: Command = pipeline.commands[0]
+            m = common.TRIPLE_ARG_RE.search(" ".join(clang_cmd.args))
             if m:
                 triple_in_cmd = m.groups()[0]
 
+            # Do lit-like substitutions on the command and redirects.
+            for cmd in pipeline.commands:
+                if cmd.args[0] == "opt":
+                    if ti.args.opt is None:
+                        sys.exit(
+                            ti.path + " needs to run opt. "
+                            "Please specify --llvm-bin or --opt"
+                        )
+                    cmd.args[0] = ti.args.opt
+                cmd.args = [common.applySubstitutions(i, subs) for i in cmd.args]
+                for i, redirect in enumerate(cmd.redirects):
+                    cmd.redirects[i] = redirect[0], common.applySubstitutions(
+                        redirect[1], subs
+                    )
+
             # Parse executable args.
-            exec_args = shlex.split(commands[0])
             # Execute non-clang runline.
-            if exec_args[0] not in SUBST:
-                # Do lit-like substitutions.
-                for s in subs:
-                    exec_args = [
-                        i.replace(s, subs[s]) if s in i else i for i in exec_args
-                    ]
-                run_list.append((None, exec_args, None, None))
+            if clang_cmd.args[0] not in SUBST:
+                # Ignore FileCheck-only 'RUN: lines'
+                if pipeline.commands[0].args[0] == "FileCheck":
+                    print(
+                        "NOTE: Skipping FileCheck-only RUN line: ",
+                        pipeline,
+                        file=sys.stderr,
+                    )
+                    continue
+                run_list.append((None, pipeline, None))
                 continue
             # This is a clang runline, apply %clang substitution rule, do lit-like substitutions,
             # and append args.clang_args
-            clang_args = exec_args
-            clang_args[0:1] = SUBST[clang_args[0]]
-            for s in subs:
-                clang_args = [
-                    i.replace(s, subs[s]) if s in i else i for i in clang_args
-                ]
-            clang_args += ti.args.clang_args
+            clang_cmd.args[0:1] = SUBST[clang_cmd.args[0]]
+            print(clang_cmd)
+            clang_cmd.args.insert(0, ti.args.clang)
+            clang_cmd.args += ti.args.clang_args
+            # Remove all -verify arguments since they could cause the IR generation to fail
+            clang_cmd.args = [x for x in clang_cmd.args if not x.startswith("-verify")]
 
             # Extract -check-prefix in FileCheck args
-            filecheck_cmd = commands[-1]
+            filecheck_cmd = " ".join(pipeline.commands[-1].args)
             common.verify_filecheck_prefixes(filecheck_cmd)
             if not filecheck_cmd.startswith("FileCheck "):
                 # Execute non-filechecked clang runline.
-                exe = [ti.args.clang] + clang_args
-                run_list.append((None, exe, None, None))
+                print(
+                    "WARNING: Executing but ignoring non-filechecked RUN line: " + l,
+                    file=sys.stderr,
+                )
+                run_list.append((None, pipeline, None))
                 continue
 
             check_prefixes = common.get_check_prefixes(filecheck_cmd)
-            run_list.append((check_prefixes, clang_args, commands[1:-1], triple_in_cmd))
+            run_list.append((check_prefixes, pipeline, triple_in_cmd))
 
         # Execute clang, generate LLVM IR, and extract functions.
 
@@ -361,27 +358,27 @@ def main():
             run_list=filecheck_run_list, flags=ti.args, scrubber_args=[], path=ti.path
         )
 
-        for prefixes, args, extra_commands, triple_in_cmd in run_list:
+        for prefixes, pipeline, triple_in_cmd in run_list:
+            assert isinstance(pipeline, Pipeline)
             # Execute non-filechecked runline.
             if not prefixes:
                 print(
-                    "NOTE: Executing non-FileChecked RUN line: " + " ".join(args),
+                    "NOTE: Executing non-FileChecked RUN line: ",
+                    pipeline,
                     file=sys.stderr,
                 )
-                exec_run_line(args)
+                common.execute_pipeline(pipeline)
                 continue
 
-            clang_args = args
-            common.debug("Extracted clang cmd: clang {}".format(clang_args))
+            clang_cmd = pipeline.commands[0:-1]
+            common.debug("Extracted clang cmd: clang {}".format(clang_cmd))
             common.debug("Extracted FileCheck prefixes: {}".format(prefixes))
 
-            get_function_body(
-                builder, ti.args, ti.path, clang_args, extra_commands, prefixes
-            )
+            get_function_body(builder, ti.args, ti.path, clang_cmd, prefixes)
 
             # Invoke clang -Xclang -ast-dump=json to get mapping from start lines to
             # mangled names. Forward all clang args for now.
-            for k, v in get_line2func_list(ti.args, clang_args).items():
+            for k, v in get_line2func_list(pipeline.commands[0]).items():
                 line2func_list[k].extend(v)
 
         func_dict = builder.finish_and_get_func_dict()
@@ -412,7 +409,7 @@ def main():
 
             # Now generate all the checks.
             def check_generator(my_output_lines, prefixes, func):
-                if "-emit-llvm" in clang_args:
+                if "-emit-llvm" in pipeline.commands[0].args:
                     return common.add_ir_checks(
                         my_output_lines,
                         "//",



More information about the cfe-commits mailing list