[Utils] Add prefix parameter in update test checks to avoid FileCheck conflicts
authorGiorgis Georgakoudis <georgakoudis1@llnl.gov>
Fri, 26 Mar 2021 12:58:05 +0000 (05:58 -0700)
committerGiorgis Georgakoudis <georgakoudis1@llnl.gov>
Fri, 26 Mar 2021 18:49:42 +0000 (11:49 -0700)
IR values convert to check prefix FileCheck variables for IR checks. For example, nameless values, e.g., %0, convert to check prefix TMP FileCheck variables, e.g., [[TMP0:%.*]]. This check prefix may clash with named values that have the same name and that causes auto-generated tests to fail. Currently a warning is emitted to change the names of the IR values but this is not always possible, if for example they are generated by clang. Manual intervention to fix the FileCheck variable names is too tedious. This patch add a parameter to prefix conflicting FileCheck variable names with a user-provided string to automate the process.

Reviewed By: jdoerfert

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

clang/test/utils/update_cc_test_checks/Inputs/resolve-tmp-conflict.cpp [new file with mode: 0644]
clang/test/utils/update_cc_test_checks/Inputs/resolve-tmp-conflict.cpp.expected [new file with mode: 0644]
clang/test/utils/update_cc_test_checks/resolve-tmp-conflict.test [new file with mode: 0644]
llvm/utils/UpdateTestChecks/common.py

diff --git a/clang/test/utils/update_cc_test_checks/Inputs/resolve-tmp-conflict.cpp b/clang/test/utils/update_cc_test_checks/Inputs/resolve-tmp-conflict.cpp
new file mode 100644 (file)
index 0000000..d82490e
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+void foo(int a) {
+  int &tmp0 = a;
+  int &&tmp1 = 1;
+  tmp1 = a;
+  return;
+}
diff --git a/clang/test/utils/update_cc_test_checks/Inputs/resolve-tmp-conflict.cpp.expected b/clang/test/utils/update_cc_test_checks/Inputs/resolve-tmp-conflict.cpp.expected
new file mode 100644 (file)
index 0000000..9a3c458
--- /dev/null
@@ -0,0 +1,25 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --prefix-filecheck-ir-name _
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: define {{[^@]+}}@_Z3fooi
+// CHECK-SAME: (i32 [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[_TMP0:%.*]] = alloca i32*, align 8
+// CHECK-NEXT:    [[_TMP1:%.*]] = alloca i32*, align 8
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[A]], i32* [[A_ADDR]], align 4
+// CHECK-NEXT:    store i32* [[A_ADDR]], i32** [[_TMP0]], align 8
+// CHECK-NEXT:    store i32 1, i32* [[REF_TMP]], align 4
+// CHECK-NEXT:    store i32* [[REF_TMP]], i32** [[_TMP1]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32*, i32** [[_TMP1]], align 8
+// CHECK-NEXT:    store i32 [[TMP0]], i32* [[TMP1]], align 4
+// CHECK-NEXT:    ret void
+//
+void foo(int a) {
+  int &tmp0 = a;
+  int &&tmp1 = 1;
+  tmp1 = a;
+  return;
+}
diff --git a/clang/test/utils/update_cc_test_checks/resolve-tmp-conflict.test b/clang/test/utils/update_cc_test_checks/resolve-tmp-conflict.test
new file mode 100644 (file)
index 0000000..a802e1a
--- /dev/null
@@ -0,0 +1,8 @@
+## Test that CHECK lines generated avoid naming conflicts with FileCheck IR variables
+
+# RUN: cp %S/Inputs/resolve-tmp-conflict.cpp %t.cpp && %update_cc_test_checks --function-signature --prefix-filecheck-ir-name _ %t.cpp
+# RUN: diff -u %S/Inputs/resolve-tmp-conflict.cpp.expected %t.cpp
+
+## Check that re-running update_cc_test_checks doesn't change the output
+# RUN: %update_cc_test_checks %t.cpp
+# RUN: diff -u %S/Inputs/resolve-tmp-conflict.cpp.expected %t.cpp
index 1940ac3..4598475 100644 (file)
@@ -16,6 +16,7 @@ else:
 
 
 _verbose = False
+_prefix_filecheck_ir_name = ''
 
 def parse_commandline_args(parser):
   parser.add_argument('--include-generated-funcs', action='store_true',
@@ -32,6 +33,8 @@ def parse_commandline_args(parser):
                       help='Deactivate CHECK line generation from this point forward')
   parser.add_argument('--replace-function-regex', nargs='+', default=[],
                       help='List of regular expressions to replace matching function names')
+  parser.add_argument('--prefix-filecheck-ir-name', default='',
+                      help='Add a prefix to FileCheck IR value names to avoid conflicts with scripted names')
   args = parser.parse_args()
   global _verbose
   _verbose = args.verbose
@@ -53,6 +56,9 @@ class TestInfo(object):
     self.argparse_callback = argparse_callback
     self.path = test
     self.args = args
+    if args.prefix_filecheck_ir_name:
+      global _prefix_filecheck_ir_name
+      _prefix_filecheck_ir_name = args.prefix_filecheck_ir_name
     self.argv = argv
     self.input_lines = input_lines
     self.run_lines = find_run_lines(test, self.input_lines)
@@ -512,11 +518,21 @@ def is_local_def_ir_value_match(match):
 def is_global_scope_ir_value_match(match):
     return nameless_values[get_idx_from_ir_value_match(match)].global_ir_prefix is not None
 
+# Return true if var clashes with the scripted FileCheck check_prefix.
+def may_clash_with_default_check_prefix_name(check_prefix, var):
+  return check_prefix and re.match(r'^' + check_prefix + r'[0-9]+?$', var, re.IGNORECASE)
+
 # Create a FileCheck variable name based on an IR name.
 def get_value_name(var, check_prefix):
   var = var.replace('!', '')
+  # This is a nameless value, prepend check_prefix.
   if var.isdigit():
     var = check_prefix + var
+  else:
+    # This is a named value that clashes with the check_prefix, prepend with _prefix_filecheck_ir_name,
+    # if it has been defined.
+    if may_clash_with_default_check_prefix_name(check_prefix, var) and _prefix_filecheck_ir_name:
+      var = _prefix_filecheck_ir_name + var
   var = var.replace('.', '_')
   var = var.replace('-', '_')
   return var.upper()
@@ -546,8 +562,9 @@ def generalize_check_lines(lines, is_analyze, vars_seen, global_vars_seen):
     pre, check = get_ir_prefix_from_ir_value_match(match)
     var = get_name_from_ir_value_match(match)
     for nameless_value in nameless_values:
-        if nameless_value.check_prefix and re.match(r'^' + nameless_value.check_prefix + r'[0-9]+?$', var, re.IGNORECASE):
-            warn("Change IR value name '%s' to prevent possible conflict with scripted FileCheck name." % (var,))
+        if may_clash_with_default_check_prefix_name(nameless_value.check_prefix, var):
+          warn("Change IR value name '%s' or use -prefix-ir-filecheck-name to prevent possible conflict"
+            " with scripted FileCheck name." % (var,))
     key = (var, get_check_key_from_ir_value_match(match))
     is_local_def = is_local_def_ir_value_match(match)
     if is_local_def and key in vars_seen: