summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alexandre Rames <alexandre.rames@linaro.org> 2015-08-06 14:49:28 +0100
committer David Brazdil <dbrazdil@google.com> 2015-08-06 15:32:28 +0100
commit5e2c8d323fbab4db8a71041ff94b6baf3953bca9 (patch)
tree12030091e7359b656abe46f601aa5230b1dec880
parent1f3f766d3b365d01f36b85dc19d40f754fa48533 (diff)
Introduce arch-specific checker tests.
- The '.cfg' output is now created on target. - Arch-specific checker tests can be created by inserting a suffix. For example: /// CHECK-START-ARM64: int Main.foo(int) register (after) /// CHECK-DAG: <<Arg:i\d+>> ParameterValue Change-Id: I55cdb37f8e806c7ffdde6b676c8f44ac30b59051
-rw-r--r--disassembler/disassembler_arm64.cc2
-rw-r--r--test/526-checker-caller-callee-regs/expected.txt0
-rw-r--r--test/526-checker-caller-callee-regs/info.txt1
-rw-r--r--test/526-checker-caller-callee-regs/src/Main.java73
-rwxr-xr-xtest/run-test32
-rw-r--r--tools/checker/README8
-rwxr-xr-xtools/checker/checker.py9
-rw-r--r--tools/checker/common/archs.py15
-rw-r--r--tools/checker/file_format/c1visualizer/parser.py21
-rw-r--r--tools/checker/file_format/checker/parser.py34
-rw-r--r--tools/checker/file_format/checker/struct.py6
-rw-r--r--tools/checker/file_format/checker/test.py49
-rw-r--r--tools/checker/file_format/common.py11
-rw-r--r--tools/checker/match/file.py4
-rwxr-xr-xtools/checker/run_unit_tests.py3
15 files changed, 229 insertions, 39 deletions
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 348b2a5d00..5f8871470d 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -94,7 +94,7 @@ void CustomDisassembler::VisitLoadStoreUnsignedOffset(const vixl::Instruction* i
int64_t offset = instr->ImmLSUnsigned() << instr->SizeLS();
std::ostringstream tmp_stream;
Thread::DumpThreadOffset<8>(tmp_stream, static_cast<uint32_t>(offset));
- AppendToOutput(" (%s)", tmp_stream.str().c_str());
+ AppendToOutput(" ; %s", tmp_stream.str().c_str());
}
}
diff --git a/test/526-checker-caller-callee-regs/expected.txt b/test/526-checker-caller-callee-regs/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/526-checker-caller-callee-regs/expected.txt
diff --git a/test/526-checker-caller-callee-regs/info.txt b/test/526-checker-caller-callee-regs/info.txt
new file mode 100644
index 0000000000..0e0373ac95
--- /dev/null
+++ b/test/526-checker-caller-callee-regs/info.txt
@@ -0,0 +1 @@
+Test allocation of caller and callee saved registers.
diff --git a/test/526-checker-caller-callee-regs/src/Main.java b/test/526-checker-caller-callee-regs/src/Main.java
new file mode 100644
index 0000000000..a1f33014ef
--- /dev/null
+++ b/test/526-checker-caller-callee-regs/src/Main.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+ public static void assertIntEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ static boolean doThrow = false;
+
+ // This function always returns 1.
+ // We use 'throw' to prevent the function from being inlined.
+ public static int $opt$noinline$function_call(int arg) {
+ if (doThrow) throw new Error();
+ return 1 % arg;
+ }
+
+ // | registers available to | regexp
+ // | the register allocator |
+ // ------------------------------|------------------------|-----------------
+ // ARM64 callee-saved registers | [x20-x29] | x2[0-9]
+ // ARM callee-saved registers | [r5-r8,r10,r11] | r([5-8]|10|11)
+
+ /**
+ * Check that a value live across a function call is allocated in a callee
+ * saved register.
+ */
+
+ /// CHECK-START-ARM: int Main.$opt$LiveInCall(int) register (after)
+ /// CHECK-DAG: <<Arg:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<t1:i\d+>> Add [<<Arg>>,<<Const1>>] {{.*->r([5-8]|10|11)}}
+ /// CHECK: <<t2:i\d+>> InvokeStaticOrDirect
+ /// CHECK: Sub [<<t1>>,<<t2>>]
+ /// CHECK: Return
+
+ /// CHECK-START-ARM64: int Main.$opt$LiveInCall(int) register (after)
+ /// CHECK-DAG: <<Arg:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<t1:i\d+>> Add [<<Arg>>,<<Const1>>] {{.*->x2[0-9]}}
+ /// CHECK: <<t2:i\d+>> InvokeStaticOrDirect
+ /// CHECK: Sub [<<t1>>,<<t2>>]
+ /// CHECK: Return
+
+ // TODO: Add tests for other architectures.
+
+ public static int $opt$LiveInCall(int arg) {
+ int t1 = arg + 1;
+ int t2 = $opt$noinline$function_call(arg);
+ return t1 - t2;
+ }
+
+ public static void main(String[] args) {
+ int arg = 123;
+ assertIntEquals($opt$LiveInCall(arg), arg);
+ }
+}
diff --git a/test/run-test b/test/run-test
index 3d6f073d31..84c818b444 100755
--- a/test/run-test
+++ b/test/run-test
@@ -626,12 +626,19 @@ if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]]; then
# on a particular DEX output, keep building them with dx for now (b/19467889).
USE_JACK="false"
- if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$target_mode" = "no" -a "$debuggable" = "no" ]; then
+ if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$debuggable" = "no" ]; then
# In no-prebuild mode, the compiler is only invoked if both dex2oat and
# patchoat are available. Disable Checker otherwise (b/22552692).
if [ "$prebuild_mode" = "yes" ] || [ "$have_patchoat" = "yes" -a "$have_dex2oat" = "yes" ]; then
run_checker="yes"
- run_args="${run_args} -Xcompiler-option --dump-cfg=$tmp_dir/$cfg_output \
+ if [ "$target_mode" = "no" ]; then
+ cfg_output_dir="$tmp_dir"
+ checker_arch_option=
+ else
+ cfg_output_dir="$DEX_LOCATION"
+ checker_arch_option="--arch=${target_arch_name^^}"
+ fi
+ run_args="${run_args} -Xcompiler-option --dump-cfg=$cfg_output_dir/$cfg_output \
-Xcompiler-option -j1"
fi
fi
@@ -647,6 +654,12 @@ elif echo "$test_dir" | grep 083; then
build_file_size_limit=5120
run_file_size_limit=5120
fi
+if [ "$run_checker" = "yes" -a "$target_mode" = "yes" ]; then
+ # We will need to `adb pull` the .cfg output from the target onto the host to
+ # run checker on it. This file can be big.
+ build_file_size_limit=16384
+ run_file_size_limit=16384
+fi
if [ ${USE_JACK} = "false" ]; then
# Set ulimit if we build with dx only, Jack can generate big temp files.
if ! ulimit -S "$build_file_size_limit"; then
@@ -671,7 +684,10 @@ if [ "$dev_mode" = "yes" ]; then
if [ "$run_exit" = "0" ]; then
if [ "$run_checker" = "yes" ]; then
- "$checker" "$cfg_output" "$tmp_dir" 2>&1
+ if [ "$target_mode" = "yes" ]; then
+ adb pull $cfg_output_dir/$cfg_output &> /dev/null
+ fi
+ "$checker" $checker_arch_option "$cfg_output" "$tmp_dir" 2>&1
checker_exit="$?"
if [ "$checker_exit" = "0" ]; then
good="yes"
@@ -693,7 +709,10 @@ elif [ "$update_mode" = "yes" ]; then
echo "${test_dir}: running..." 1>&2
"./${run}" $run_args "$@" >"$output" 2>&1
if [ "$run_checker" = "yes" ]; then
- "$checker" -q "$cfg_output" "$tmp_dir" >> "$output" 2>&1
+ if [ "$target_mode" = "yes" ]; then
+ adb pull $cfg_output_dir/$cfg_output &> /dev/null
+ fi
+ "$checker" -q $checker_arch_option "$cfg_output" "$tmp_dir" >> "$output" 2>&1
fi
sed -e 's/[[:cntrl:]]$//g' < "$output" >"${td_expected}"
good="yes"
@@ -731,7 +750,10 @@ else
echo "run exit status: $run_exit" 1>&2
good_run="no"
elif [ "$run_checker" = "yes" ]; then
- "$checker" -q "$cfg_output" "$tmp_dir" >> "$output" 2>&1
+ if [ "$target_mode" = "yes" ]; then
+ adb pull $cfg_output_dir/$cfg_output &> /dev/null
+ fi
+ "$checker" -q $checker_arch_option "$cfg_output" "$tmp_dir" >> "$output" 2>&1
checker_exit="$?"
if [ "$checker_exit" != "0" ]; then
echo "checker exit status: $checker_exit" 1>&2
diff --git a/tools/checker/README b/tools/checker/README
index 858a773768..259691e500 100644
--- a/tools/checker/README
+++ b/tools/checker/README
@@ -52,3 +52,11 @@ Example:
The engine will attempt to match the check lines against the output of the
group named on the first line. Together they verify that the CFG after
constant folding returns an integer constant with value either 11 or 22.
+
+A group of check lines can be made architecture-specific by inserting '-<arch>'
+after the 'CHECK-START' keyword. The previous example can be updated to run for
+arm64 only with:
+
+ // CHECK-START-ARM64: int MyClass.MyMethod() constant_folding (after)
+ // CHECK: <<ID:i\d+>> IntConstant {{11|22}}
+ // CHECK: Return [<<ID>>]
diff --git a/tools/checker/checker.py b/tools/checker/checker.py
index 4e516deee0..bc5e17da6a 100755
--- a/tools/checker/checker.py
+++ b/tools/checker/checker.py
@@ -17,6 +17,7 @@
import argparse
import os
+from common.archs import archs_list
from common.logger import Logger
from file_format.c1visualizer.parser import ParseC1visualizerStream
from file_format.checker.parser import ParseCheckerStream
@@ -34,6 +35,8 @@ def ParseArguments():
help="print a list of all passes found in the tested file")
parser.add_argument("--dump-pass", dest="dump_pass", metavar="PASS",
help="print a compiler pass dump")
+ parser.add_argument("--arch", dest="arch", choices=archs_list,
+ help="Run the tests for the specified target architecture.")
parser.add_argument("-q", "--quiet", action="store_true",
help="print only errors")
return parser.parse_args()
@@ -80,13 +83,13 @@ def FindCheckerFiles(path):
Logger.fail("Source path \"" + path + "\" not found")
-def RunTests(checkPrefix, checkPath, outputFilename):
+def RunTests(checkPrefix, checkPath, outputFilename, targetArch):
c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
for checkFilename in FindCheckerFiles(checkPath):
checkerFile = ParseCheckerStream(os.path.basename(checkFilename),
checkPrefix,
open(checkFilename, "r"))
- MatchFiles(checkerFile, c1File)
+ MatchFiles(checkerFile, c1File, targetArch)
if __name__ == "__main__":
@@ -100,4 +103,4 @@ if __name__ == "__main__":
elif args.dump_pass:
DumpPass(args.tested_file, args.dump_pass)
else:
- RunTests(args.check_prefix, args.source_path, args.tested_file)
+ RunTests(args.check_prefix, args.source_path, args.tested_file, args.arch)
diff --git a/tools/checker/common/archs.py b/tools/checker/common/archs.py
new file mode 100644
index 0000000000..84bded9281
--- /dev/null
+++ b/tools/checker/common/archs.py
@@ -0,0 +1,15 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+archs_list = ['ARM', 'ARM64', 'MIPS64', 'X86', 'X86_64']
diff --git a/tools/checker/file_format/c1visualizer/parser.py b/tools/checker/file_format/c1visualizer/parser.py
index 335a195883..bdcde9db51 100644
--- a/tools/checker/file_format/c1visualizer/parser.py
+++ b/tools/checker/file_format/c1visualizer/parser.py
@@ -27,10 +27,12 @@ class C1ParserState:
def __parseC1Line(line, lineNo, state, fileName):
""" This function is invoked on each line of the output file and returns
- a pair which instructs the parser how the line should be handled. If the
+ a triplet which instructs the parser how the line should be handled. If the
line is to be included in the current group, it is returned in the first
value. If the line starts a new output group, the name of the group is
- returned in the second value.
+ returned in the second value. The third value is only here to make the
+ function prototype compatible with `SplitStream` and is always set to
+ `None` here.
"""
if state.currentState == C1ParserState.StartingCfgBlock:
# Previous line started a new 'cfg' block which means that this one must
@@ -39,16 +41,16 @@ def __parseC1Line(line, lineNo, state, fileName):
# Extract the pass name, prepend it with the name of the method and
# return as the beginning of a new group.
state.currentState = C1ParserState.InsideCfgBlock
- return (None, state.lastMethodName + " " + line.split("\"")[1])
+ return (None, state.lastMethodName + " " + line.split("\"")[1], None)
else:
Logger.fail("Expected output group name", fileName, lineNo)
elif state.currentState == C1ParserState.InsideCfgBlock:
if line == "end_cfg":
state.currentState = C1ParserState.OutsideBlock
- return (None, None)
+ return (None, None, None)
else:
- return (line, None)
+ return (line, None, None)
elif state.currentState == C1ParserState.InsideCompilationBlock:
# Search for the method's name. Format: method "<name>"
@@ -59,7 +61,7 @@ def __parseC1Line(line, lineNo, state, fileName):
state.lastMethodName = methodName
elif line == "end_compilation":
state.currentState = C1ParserState.OutsideBlock
- return (None, None)
+ return (None, None, None)
else:
assert state.currentState == C1ParserState.OutsideBlock
@@ -69,10 +71,10 @@ def __parseC1Line(line, lineNo, state, fileName):
if state.lastMethodName is None:
Logger.fail("Expected method header", fileName, lineNo)
state.currentState = C1ParserState.StartingCfgBlock
- return (None, None)
+ return (None, None, None)
elif line == "begin_compilation":
state.currentState = C1ParserState.InsideCompilationBlock
- return (None, None)
+ return (None, None, None)
else:
Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
@@ -82,6 +84,7 @@ def ParseC1visualizerStream(fileName, stream):
fnProcessLine = lambda line, lineNo: __parseC1Line(line, lineNo, state, fileName)
fnLineOutsideChunk = lambda line, lineNo: \
Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
- for passName, passLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+ for passName, passLines, startLineNo, testArch in \
+ SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
C1visualizerPass(c1File, passName, passLines, startLineNo + 1)
return c1File
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
index f354395171..001f72a225 100644
--- a/tools/checker/file_format/checker/parser.py
+++ b/tools/checker/file_format/checker/parser.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from common.archs import archs_list
from common.logger import Logger
from file_format.common import SplitStream
from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
@@ -21,17 +22,18 @@ import re
def __isCheckerLine(line):
return line.startswith("///") or line.startswith("##")
-def __extractLine(prefix, line):
+def __extractLine(prefix, line, arch = None):
""" Attempts to parse a check line. The regex searches for a comment symbol
followed by the CHECK keyword, given attribute and a colon at the very
beginning of the line. Whitespaces are ignored.
"""
rIgnoreWhitespace = r"\s*"
rCommentSymbols = [r"///", r"##"]
+ arch_specifier = r"-%s" % arch if arch is not None else r""
regexPrefix = rIgnoreWhitespace + \
r"(" + r"|".join(rCommentSymbols) + r")" + \
rIgnoreWhitespace + \
- prefix + r":"
+ prefix + arch_specifier + r":"
# The 'match' function succeeds only if the pattern is matched at the
# beginning of the line.
@@ -42,39 +44,42 @@ def __extractLine(prefix, line):
return None
def __processLine(line, lineNo, prefix, fileName):
- """ This function is invoked on each line of the check file and returns a pair
+ """ This function is invoked on each line of the check file and returns a triplet
which instructs the parser how the line should be handled. If the line is
to be included in the current check group, it is returned in the first
value. If the line starts a new check group, the name of the group is
- returned in the second value.
+ returned in the second value. The third value indicates whether the line
+ contained an architecture-specific suffix.
"""
if not __isCheckerLine(line):
- return None, None
+ return None, None, None
# Lines beginning with 'CHECK-START' start a new test case.
- startLine = __extractLine(prefix + "-START", line)
- if startLine is not None:
- return None, startLine
+ # We currently only consider the architecture suffix in "CHECK-START" lines.
+ for arch in [None] + archs_list:
+ startLine = __extractLine(prefix + "-START", line, arch)
+ if startLine is not None:
+ return None, startLine, arch
# Lines starting only with 'CHECK' are matched in order.
plainLine = __extractLine(prefix, line)
if plainLine is not None:
- return (plainLine, TestAssertion.Variant.InOrder, lineNo), None
+ return (plainLine, TestAssertion.Variant.InOrder, lineNo), None, None
# 'CHECK-NEXT' lines are in-order but must match the very next line.
nextLine = __extractLine(prefix + "-NEXT", line)
if nextLine is not None:
- return (nextLine, TestAssertion.Variant.NextLine, lineNo), None
+ return (nextLine, TestAssertion.Variant.NextLine, lineNo), None, None
# 'CHECK-DAG' lines are no-order assertions.
dagLine = __extractLine(prefix + "-DAG", line)
if dagLine is not None:
- return (dagLine, TestAssertion.Variant.DAG, lineNo), None
+ return (dagLine, TestAssertion.Variant.DAG, lineNo), None, None
# 'CHECK-NOT' lines are no-order negative assertions.
notLine = __extractLine(prefix + "-NOT", line)
if notLine is not None:
- return (notLine, TestAssertion.Variant.Not, lineNo), None
+ return (notLine, TestAssertion.Variant.Not, lineNo), None, None
Logger.fail("Checker assertion could not be parsed: '" + line + "'", fileName, lineNo)
@@ -146,8 +151,9 @@ def ParseCheckerStream(fileName, prefix, stream):
fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix, fileName)
fnLineOutsideChunk = lambda line, lineNo: \
Logger.fail("Checker line not inside a group", fileName, lineNo)
- for caseName, caseLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
- testCase = TestCase(checkerFile, caseName, startLineNo)
+ for caseName, caseLines, startLineNo, testArch in \
+ SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+ testCase = TestCase(checkerFile, caseName, startLineNo, testArch)
for caseLine in caseLines:
ParseCheckerAssertion(testCase, caseLine[0], caseLine[1], caseLine[2])
return checkerFile
diff --git a/tools/checker/file_format/checker/struct.py b/tools/checker/file_format/checker/struct.py
index 6a541428df..2b2e4429e7 100644
--- a/tools/checker/file_format/checker/struct.py
+++ b/tools/checker/file_format/checker/struct.py
@@ -26,6 +26,9 @@ class CheckerFile(PrintableMixin):
def addTestCase(self, new_test_case):
self.testCases.append(new_test_case)
+ def testCasesForArch(self, targetArch):
+ return [t for t in self.testCases if t.testArch == targetArch]
+
def __eq__(self, other):
return isinstance(other, self.__class__) \
and self.testCases == other.testCases
@@ -33,13 +36,14 @@ class CheckerFile(PrintableMixin):
class TestCase(PrintableMixin):
- def __init__(self, parent, name, startLineNo):
+ def __init__(self, parent, name, startLineNo, testArch = None):
assert isinstance(parent, CheckerFile)
self.parent = parent
self.name = name
self.assertions = []
self.startLineNo = startLineNo
+ self.testArch = testArch
if not self.name:
Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)
diff --git a/tools/checker/file_format/checker/test.py b/tools/checker/file_format/checker/test.py
index ff24cc1239..36ed4b1592 100644
--- a/tools/checker/file_format/checker/test.py
+++ b/tools/checker/file_format/checker/test.py
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from common.archs import archs_list
from common.testing import ToUnicode
from file_format.checker.parser import ParseCheckerStream
from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
@@ -280,3 +281,51 @@ class CheckerParser_FileLayoutTest(unittest.TestCase):
/// CHECK-START: Example Group
/// CHECK-NEXT: bar
""")
+
+
+class CheckerParser_ArchTests(unittest.TestCase):
+
+ noarch_block = """
+ /// CHECK-START: Group
+ /// CHECK: foo
+ /// CHECK-NEXT: bar
+ /// CHECK-NOT: baz
+ /// CHECK-DAG: yoyo
+ """
+
+ arch_block = """
+ /// CHECK-START-{test_arch}: Group
+ /// CHECK: foo
+ /// CHECK-NEXT: bar
+ /// CHECK-NOT: baz
+ /// CHECK-DAG: yoyo
+ """
+
+ def test_NonArchTests(self):
+ for arch in [None] + archs_list:
+ checkerFile = ParseCheckerStream("<test-file>",
+ "CHECK",
+ io.StringIO(ToUnicode(self.noarch_block)))
+ self.assertEqual(len(checkerFile.testCases), 1)
+ self.assertEqual(len(checkerFile.testCases[0].assertions), 4)
+
+ def test_IgnoreNonTargetArch(self):
+ for targetArch in archs_list:
+ for testArch in [a for a in archs_list if a != targetArch]:
+ checkerText = self.arch_block.format(test_arch = testArch)
+ checkerFile = ParseCheckerStream("<test-file>",
+ "CHECK",
+ io.StringIO(ToUnicode(checkerText)))
+ self.assertEqual(len(checkerFile.testCases), 1)
+ self.assertEqual(len(checkerFile.testCasesForArch(testArch)), 1)
+ self.assertEqual(len(checkerFile.testCasesForArch(targetArch)), 0)
+
+ def test_Arch(self):
+ for arch in archs_list:
+ checkerText = self.arch_block.format(test_arch = arch)
+ checkerFile = ParseCheckerStream("<test-file>",
+ "CHECK",
+ io.StringIO(ToUnicode(checkerText)))
+ self.assertEqual(len(checkerFile.testCases), 1)
+ self.assertEqual(len(checkerFile.testCasesForArch(arch)), 1)
+ self.assertEqual(len(checkerFile.testCases[0].assertions), 4)
diff --git a/tools/checker/file_format/common.py b/tools/checker/file_format/common.py
index f91fdeb9cc..4931550355 100644
--- a/tools/checker/file_format/common.py
+++ b/tools/checker/file_format/common.py
@@ -18,8 +18,9 @@ def SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
Arguments:
- fnProcessLine: Called on each line with the text and line number. Must
- return a pair, name of the chunk started on this line and data extracted
- from this line (or None in both cases).
+ return a triplet, composed of the name of the chunk started on this line,
+ the data extracted, and the name of the architecture this test applies to
+ (or None to indicate that all architectures should run this test).
- fnLineOutsideChunk: Called on attempt to attach data prior to creating
a chunk.
"""
@@ -36,9 +37,11 @@ def SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
# Let the child class process the line and return information about it.
# The _processLine method can modify the content of the line (or delete it
# entirely) and specify whether it starts a new group.
- processedLine, newChunkName = fnProcessLine(line, lineNo)
+ processedLine, newChunkName, testArch = fnProcessLine(line, lineNo)
+ # Currently, only a full chunk can be specified as architecture-specific.
+ assert testArch is None or newChunkName is not None
if newChunkName is not None:
- currentChunk = (newChunkName, [], lineNo)
+ currentChunk = (newChunkName, [], lineNo, testArch)
allChunks.append(currentChunk)
if processedLine is not None:
if currentChunk is not None:
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
index b22211ab56..42ca7df439 100644
--- a/tools/checker/match/file.py
+++ b/tools/checker/match/file.py
@@ -150,8 +150,10 @@ def MatchTestCase(testCase, c1Pass):
matchFrom = match.scope.end + 1
variables = match.variables
-def MatchFiles(checkerFile, c1File):
+def MatchFiles(checkerFile, c1File, targetArch):
for testCase in checkerFile.testCases:
+ if testCase.testArch not in [None, targetArch]:
+ continue
# TODO: Currently does not handle multiple occurrences of the same group
# name, e.g. when a pass is run multiple times. It will always try to
# match a check group against the first output group of the same name.
diff --git a/tools/checker/run_unit_tests.py b/tools/checker/run_unit_tests.py
index 01708dbd27..2f5b1feaa6 100755
--- a/tools/checker/run_unit_tests.py
+++ b/tools/checker/run_unit_tests.py
@@ -18,7 +18,8 @@ from common.logger import Logger
from file_format.c1visualizer.test import C1visualizerParser_Test
from file_format.checker.test import CheckerParser_PrefixTest, \
CheckerParser_RegexExpressionTest, \
- CheckerParser_FileLayoutTest
+ CheckerParser_FileLayoutTest, \
+ CheckerParser_ArchTests
from match.test import MatchLines_Test, \
MatchFiles_Test