Dump instruction set features in .cfg

This commit adds a compilation block at the beginning of the .cfg
dumped by the optimizing compiler when --dump-cfg is enabled.

The compilation block appears in the following form:

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

This compilation block dump is passed to checker script (see
https://android-review.googlesource.com/c/platform/art/+/1290997)
for checking if a certain instruction set feature was used at compile
time.

Author:    Fabio Rinaldi
Committer: Artem Serov

Bug: 147876827
Test: ./art/tools/checker/run_unit_tests.py
Test: test.py --target --optimizing
Change-Id: If4309af4bab892f715aad1d3bd338f8ee11e497c
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 23b93fc..922a6f6 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -21,6 +21,7 @@
 #include <cctype>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
 #include "art_method.h"
 #include "base/intrusive_forward_list.h"
 #include "bounds_check_elimination.h"
@@ -42,6 +43,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static bool HasWhitespace(const char* str) {
   DCHECK(str != nullptr);
   while (str[0] != 0) {
@@ -903,6 +906,19 @@
   printer.Flush();
 }
 
+std::string HGraphVisualizer::InsertMetaDataAsCompilationBlock(const std::string& meta_data) {
+  std::string time_str = std::to_string(time(nullptr));
+  std::string quoted_meta_data = "\"" + meta_data + "\"";
+  return StringPrintf("begin_compilation\n"
+                      "  name %s\n"
+                      "  method %s\n"
+                      "  date %s\n"
+                      "end_compilation\n",
+                      quoted_meta_data.c_str(),
+                      quoted_meta_data.c_str(),
+                      time_str.c_str());
+}
+
 void HGraphVisualizer::DumpGraph(const char* pass_name,
                                  bool is_after_pass,
                                  bool graph_in_bad_state) const {
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index 66588f6..e01d03c 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -107,6 +107,11 @@
   void DumpGraph(const char* pass_name, bool is_after_pass, bool graph_in_bad_state) const;
   void DumpGraphWithDisassembly() const;
 
+  // C1visualizer file format does not support inserting arbitrary metadata into a cfg
+  // file. As a workaround a fake compilation block with the metadata in the name and the
+  // method attributes is used. Such empty blocks don't break the c1visualizer parser.
+  static std::string InsertMetaDataAsCompilationBlock(const std::string& meta_data);
+
  private:
   std::ostream* const output_;
   HGraph* const graph_;
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index bae402e..de86c44 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -400,6 +400,9 @@
 
   std::vector<uint8_t> GenerateJitDebugInfo(const debug::MethodDebugInfo& method_debug_info);
 
+  // This must be called before any other function that dumps data to the cfg
+  void DumpInstructionSetFeaturesToCfg() const;
+
   std::unique_ptr<OptimizingCompilerStats> compilation_stats_;
 
   std::unique_ptr<std::ostream> visualizer_output_;
@@ -421,6 +424,7 @@
     std::ios_base::openmode cfg_file_mode =
         compiler_options.GetDumpCfgAppend() ? std::ofstream::app : std::ofstream::out;
     visualizer_output_.reset(new std::ofstream(cfg_file_name, cfg_file_mode));
+    DumpInstructionSetFeaturesToCfg();
   }
   if (compiler_options.GetDumpStats()) {
     compilation_stats_.reset(new OptimizingCompilerStats());
@@ -433,6 +437,16 @@
   }
 }
 
+void OptimizingCompiler::DumpInstructionSetFeaturesToCfg() const {
+  const CompilerOptions& compiler_options = GetCompilerOptions();
+  const InstructionSetFeatures* features = compiler_options.GetInstructionSetFeatures();
+  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);
+}
+
 bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx ATTRIBUTE_UNUSED,
                                           const DexFile& dex_file ATTRIBUTE_UNUSED) const {
   return true;