Dump ISA into .cfg

The optimizing compiler dumps ISA features into .cfg which can be used
by the checker. A new tool perf2cfg needs to know ISA a CFG corresponds
to. The tool uses this to check that input perf data has the same ISA.

This CL implements in the compiler dumping ISA in addition to ISA features:

begin_compilation
  name "isa:some_isa isa_features:feature1,-feature2"
  method "isa:some_isa isa_features:feature1,-feature2"
  date 1580721972
end_compilation

Bug: 147876827
Test: ./art/tools/checker/run_unit_tests.py
Test: test.py --target --optimizing --jit --interpreter
Test: test.py --host --optimizing --jit --interpreter
Change-Id: I189eae0f4de61e6a49c01d925e7136b5f7027c91
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index de86c44..f201f80 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -440,11 +440,14 @@
 void OptimizingCompiler::DumpInstructionSetFeaturesToCfg() const {
   const CompilerOptions& compiler_options = GetCompilerOptions();
   const InstructionSetFeatures* features = compiler_options.GetInstructionSetFeatures();
+  std::string isa_string =
+      std::string("isa:") + GetInstructionSetString(features->GetInstructionSet());
   std::string features_string = "isa_features:" + features->GetFeatureString();
   // It is assumed that visualizer_output_ is empty when calling this function, hence the fake
   // compilation block containing the ISA features will be printed at the beginning of the .cfg
   // file.
-  *visualizer_output_ << HGraphVisualizer::InsertMetaDataAsCompilationBlock(features_string);
+  *visualizer_output_
+      << HGraphVisualizer::InsertMetaDataAsCompilationBlock(isa_string + ' ' + features_string);
 }
 
 bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx ATTRIBUTE_UNUSED,
diff --git a/tools/checker/file_format/c1visualizer/parser.py b/tools/checker/file_format/c1visualizer/parser.py
index e16382e..a31bc56 100644
--- a/tools/checker/file_format/c1visualizer/parser.py
+++ b/tools/checker/file_format/c1visualizer/parser.py
@@ -59,7 +59,7 @@
       if not methodName:
         Logger.fail("Empty method name in output", fileName, lineNo)
 
-      m = re.match("isa_features:([\w,-]+)", methodName)
+      m = re.search("isa_features:([\w,-]+)", methodName)
       if (m):
         rawFeatures = m.group(1).split(",")
         # Create a map of features in the form {featureName: isEnabled}.
diff --git a/tools/checker/file_format/c1visualizer/test.py b/tools/checker/file_format/c1visualizer/test.py
index 11a6f0e..e5acd62 100644
--- a/tools/checker/file_format/c1visualizer/test.py
+++ b/tools/checker/file_format/c1visualizer/test.py
@@ -145,3 +145,33 @@
       ( ImmutableDict({"feature1": True, "feature2": False}), [
         ( "MyMethod1 pass1", [ "foo", "bar" ] )
       ]))
+    self.assertParsesTo(
+      """
+        begin_compilation
+          name "isa:some_isa isa_features:feature1,-feature2"
+          method "isa:some_isa isa_features:feature1,-feature2"
+          date 1234
+        end_compilation
+      """,
+      ( ImmutableDict({"feature1": True, "feature2": False}), []))
+    self.assertParsesTo(
+      """
+        begin_compilation
+          name "isa:some_isa isa_features:feature1,-feature2"
+          method "isa:some_isa isa_features:feature1,-feature2"
+          date 1234
+        end_compilation
+        begin_compilation
+          name "xyz1"
+          method "MyMethod1"
+          date 1234
+        end_compilation
+        begin_cfg
+          name "pass1"
+          foo
+          bar
+        end_cfg
+      """,
+      ( ImmutableDict({"feature1": True, "feature2": False}), [
+        ( "MyMethod1 pass1", [ "foo", "bar" ] )
+      ]))
diff --git a/tools/checker/match/test.py b/tools/checker/match/test.py
index 69e515f..16ace56 100644
--- a/tools/checker/match/test.py
+++ b/tools/checker/match/test.py
@@ -103,27 +103,36 @@
 
 class MatchFiles_Test(unittest.TestCase):
 
-  def assertMatches(self, checkerString, c1String, instructionSetFeatures=None):
+  def assertMatches(self, checkerString, c1String, isa=None, instructionSetFeatures=None):
     checkerString = \
       """
         /// CHECK-START: MyMethod MyPass
       """ + checkerString
-    featureString = ""
+    metaData = ""
+    if isa:
+      metaData += "isa:" + isa
+
     if instructionSetFeatures:
+      if metaData:
+        metaData += " "
+
       joinedFeatures = ",".join(map(lambda feature: feature
                                                     if instructionSetFeatures[feature]
                                                     else "-" + feature,
                                     instructionSetFeatures))
+      metaData += "isa_features:" + joinedFeatures
 
-      featureString = \
+    metaDataString = ""
+    if metaData:
+      metaDataString = \
         """
           begin_compilation
-            name "isa_features:%s"
-            method "isa_features:%s"
+            name "%s"
+            method "%s"
             date 1234
           end_compilation
-        """ % (joinedFeatures, joinedFeatures)
-    c1String = featureString + \
+        """ % (metaData, metaData)
+    c1String = metaDataString + \
       """
         begin_compilation
           name "MyMethod"
@@ -142,9 +151,9 @@
     assert len(c1File.passes) == 1
     MatchTestCase(checkerFile.testCases[0], c1File.passes[0], c1File.instructionSetFeatures)
 
-  def assertDoesNotMatch(self, checkerString, c1String, instructionSetFeatures=None):
+  def assertDoesNotMatch(self, checkerString, c1String, isa=None, instructionSetFeatures=None):
     with self.assertRaises(MatchFailedException):
-      self.assertMatches(checkerString, c1String, instructionSetFeatures)
+      self.assertMatches(checkerString, c1String, isa, instructionSetFeatures)
 
   def assertBadStructure(self, checkerString, c1String):
     with self.assertRaises(BadStructureException):
@@ -933,6 +942,7 @@
       """)
 
   def test_hasIsaFeature(self):
+    no_isa = None
     self.assertMatches(
       """
         /// CHECK-EVAL: hasIsaFeature('feature1') and not hasIsaFeature('feature2')
@@ -940,6 +950,7 @@
       """
       foo
       """,
+      no_isa,
       ImmutableDict({"feature1": True})
     )
     self.assertDoesNotMatch(
@@ -949,6 +960,7 @@
       """
       foo
       """,
+      no_isa,
       ImmutableDict({"feature1": True})
     )
     self.assertMatches(
@@ -963,6 +975,41 @@
       foo
       bar1
       """,
+      no_isa,
       ImmutableDict({"feature1": False, "feature2": True})
     )
-
+    self.assertMatches(
+      """
+        /// CHECK-EVAL: hasIsaFeature('feature1') and not hasIsaFeature('feature2')
+      """,
+      """
+      foo
+      """,
+      "some_isa",
+      ImmutableDict({"feature1": True})
+    )
+    self.assertDoesNotMatch(
+      """
+        /// CHECK-EVAL: not hasIsaFeature('feature1')
+      """,
+      """
+      foo
+      """,
+      "some_isa",
+      ImmutableDict({"feature1": True})
+    )
+    self.assertMatches(
+      """
+        /// CHECK-IF: hasIsaFeature('feature2')
+        ///   CHECK: bar1
+        /// CHECK-ELSE:
+        ///   CHECK: bar2
+        /// CHECK-FI:
+      """,
+      """
+      foo
+      bar1
+      """,
+      "some_isa",
+      ImmutableDict({"feature1": False, "feature2": True})
+    )