Add analysis for move-result target

Added analysis for target of move-result. Removed useless counters.

Added verbosity options to reduce spam:
-0: Print only summary
-1: Print summary and distribution
-2: Print all the things

Test: test-art-host
Bug: 77721545

Change-Id: Ib002754d4f50fdf4a3d2e57c83d565dc8d64a054
diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc
index c90bb9c..e1989d0 100644
--- a/tools/dexanalyze/dexanalyze.cc
+++ b/tools/dexanalyze/dexanalyze.cc
@@ -58,7 +58,7 @@
         << "    -a (Run all experiments)\n"
         << "    -n <int> (run experiment with 1 .. n as argument)\n"
         << "    -d (Dump on per Dex basis)\n"
-        << "    -v (Verbose dumping)\n";
+        << "    -v (quiet(0) to everything(2))\n";
     return kExitCodeUsageError;
   }
 
@@ -71,7 +71,17 @@
           verify_checksum_ = false;
           run_dex_file_verifier_ = false;
         } else if (arg == "-v") {
-          verbose_ = true;
+          if (i + 1 >= argc) {
+            return Usage(argv);
+          }
+          std::istringstream iss(argv[i + 1]);
+          size_t verbose_level = 0u;
+          iss >> verbose_level;
+          if (verbose_level > static_cast<size_t>(VerboseLevel::kEverything)) {
+            return Usage(argv);
+          }
+          ++i;
+          verbose_level_ = static_cast<VerboseLevel>(verbose_level);
         } else if (arg == "-a") {
           run_all_experiments_ = true;
         } else if (arg == "-n") {
@@ -104,7 +114,7 @@
       return 0;
     }
 
-    bool verbose_ = false;
+    VerboseLevel verbose_level_ = VerboseLevel::kNormal;
     bool verify_checksum_ = true;
     bool run_dex_file_verifier_ = true;
     bool dump_per_input_dex_ = false;
@@ -147,7 +157,7 @@
         }
       }
       for (const std::unique_ptr<Experiment>& experiment : experiments_) {
-        experiment->dump_ = options->verbose_;
+        experiment->verbose_level_ = options->verbose_level_;
       }
     }
 
diff --git a/tools/dexanalyze/dexanalyze_bytecode.cc b/tools/dexanalyze/dexanalyze_bytecode.cc
index d18b0df..1c5a5d5 100644
--- a/tools/dexanalyze/dexanalyze_bytecode.cc
+++ b/tools/dexanalyze/dexanalyze_bytecode.cc
@@ -88,7 +88,7 @@
         if (method.GetCodeItem() == nullptr || !visited.insert(method.GetCodeItem()).second) {
           continue;
         }
-        if (dump_) {
+        if (verbose_level_ >= VerboseLevel::kEverything) {
           std::cout << std::endl
                     << "Processing " << dex_file->PrettyMethod(method.GetIndex(), true);
         }
@@ -122,8 +122,6 @@
   os << "Total Dex code bytes: " << Percent(dex_code_bytes_, total_size) << "\n";
   os << "Total output code bytes: " << Percent(output_size_, total_size) << "\n";
   os << "Total deduped code bytes: " << Percent(deduped_size_, total_size) << "\n";
-  os << "Missing field idx count: " << missing_field_idx_count_ << "\n";
-  os << "Missing method idx count: " << missing_method_idx_count_ << "\n";
   std::vector<std::pair<size_t, std::vector<uint8_t>>> pairs;
   for (auto&& pair : instruction_freq_) {
     if (pair.second > 0 && !pair.first.empty()) {
@@ -133,11 +131,14 @@
     }
   }
   std::sort(pairs.rbegin(), pairs.rend());
-  os << "Top instruction bytecode sizes and hex dump" << "\n";
+  static constexpr size_t kMaxMacros = 128;
   uint64_t top_instructions_savings = 0u;
-  for (size_t i = 0; i < 128 && i < pairs.size(); ++i) {
+  for (size_t i = 0; i < kMaxMacros && i < pairs.size(); ++i) {
     top_instructions_savings += pairs[i].first;
-    if (dump_ || (true)) {
+  }
+  if (verbose_level_ >= VerboseLevel::kNormal) {
+    os << "Top " << kMaxMacros << " instruction bytecode sizes and hex dump" << "\n";
+    for (size_t i = 0; i < kMaxMacros && i < pairs.size(); ++i) {
       auto bytes = pairs[i].second;
       // Remove opcode bytes.
       bytes.erase(bytes.begin());
@@ -145,6 +146,12 @@
          << Instruction::Name(static_cast<Instruction::Code>(pairs[i].second[0]))
          << "(" << bytes << ")\n";
     }
+    os << "Move result register distribution" << "\n";
+    const size_t move_result_total =
+        std::accumulate(move_result_reg_.begin(), move_result_reg_.end(), 0u);
+    for (size_t i = 0; i < move_result_reg_.size(); ++i) {
+      os << i << ": " << Percent(move_result_reg_[i], move_result_total) << "\n";
+    }
   }
   os << "Top instructions 1b macro savings "
      << Percent(top_instructions_savings, total_size) << "\n";
@@ -167,7 +174,7 @@
     if (inst == code_item.end()) {
       break;
     }
-    if (dump_) {
+    if (verbose_level_ >= VerboseLevel::kEverything) {
       std::cout << std::endl;
       std::cout << inst->DumpString(nullptr);
       if (skip_next) {
@@ -323,6 +330,7 @@
                   next->Opcode() == Instruction::MOVE_RESULT_OBJECT;
               if (next_move_result) {
                 dest_reg = next->VRegA_11x();
+                ++move_result_reg_[dest_reg];
               }
             }
 
@@ -406,9 +414,9 @@
             ++current_type.types_.FindOrAdd(type_idx)->second;
           } else {
             bool next_is_init = false;
-            if (opcode == Instruction::NEW_INSTANCE && inst != code_item.end()) {
+            if (opcode == Instruction::NEW_INSTANCE) {
               auto next = std::next(inst);
-              if (next->Opcode() == Instruction::INVOKE_DIRECT) {
+              if (next != code_item.end() && next->Opcode() == Instruction::INVOKE_DIRECT) {
                 uint32_t args[6] = {};
                 uint32_t arg_count = next->GetVarArgs(args);
                 uint32_t method_idx = DexMethodIndex(next.Inst());
@@ -449,7 +457,7 @@
       Add(new_opcode, inst.Inst());
     }
   }
-  if (dump_) {
+  if (verbose_level_ >= VerboseLevel::kEverything) {
     std::cout << std::endl
               << "Bytecode size " << code_item.InsnsSizeInBytes() << " -> " << buffer_.size();
     std::cout << std::endl;
@@ -504,7 +512,7 @@
 }
 
 bool NewRegisterInstructions::InstNibbles(uint8_t opcode, const std::vector<uint32_t>& args) {
-  if (dump_) {
+  if (verbose_level_ >= VerboseLevel::kEverything) {
     std::cout << " ==> " << Instruction::Name(static_cast<Instruction::Code>(opcode)) << " ";
     for (int v : args) {
       std::cout << v << ", ";
@@ -512,7 +520,7 @@
   }
   for (int v : args) {
     if (v >= 16) {
-      if (dump_) {
+      if (verbose_level_ >= VerboseLevel::kEverything) {
         std::cout << "(OUT_OF_RANGE)";
       }
       return false;
diff --git a/tools/dexanalyze/dexanalyze_bytecode.h b/tools/dexanalyze/dexanalyze_bytecode.h
index 9ea819b..ed40ba7 100644
--- a/tools/dexanalyze/dexanalyze_bytecode.h
+++ b/tools/dexanalyze/dexanalyze_bytecode.h
@@ -17,6 +17,7 @@
 #ifndef ART_TOOLS_DEXANALYZE_DEXANALYZE_BYTECODE_H_
 #define ART_TOOLS_DEXANALYZE_DEXANALYZE_BYTECODE_H_
 
+#include <array>
 #include <vector>
 #include <map>
 
@@ -75,9 +76,8 @@
   uint64_t output_size_ = 0u;
   uint64_t deduped_size_ = 0u;
   uint64_t dex_code_bytes_ = 0u;
-  uint64_t missing_field_idx_count_ = 0u;
-  uint64_t missing_method_idx_count_ = 0u;
   uint64_t experiments_ = std::numeric_limits<uint64_t>::max();
+  std::array<size_t, 256> move_result_reg_;
   std::map<std::vector<uint8_t>, size_t> instruction_freq_;
   // Output instruction buffer.
   std::vector<uint8_t> buffer_;
diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h
index 468b74b..312330b 100644
--- a/tools/dexanalyze/dexanalyze_experiments.h
+++ b/tools/dexanalyze/dexanalyze_experiments.h
@@ -32,6 +32,12 @@
 
 namespace dexanalyze {
 
+enum class VerboseLevel : size_t {
+  kQuiet,
+  kNormal,
+  kEverything,
+};
+
 bool IsRange(Instruction::Code code);
 
 uint16_t NumberOfArgs(const Instruction& inst);
@@ -52,7 +58,7 @@
   virtual void ProcessDexFile(const DexFile&) {}
   virtual void Dump(std::ostream& os, uint64_t total_size) const = 0;
 
-  bool dump_ = false;
+  VerboseLevel verbose_level_ = VerboseLevel::kNormal;
 };
 
 // Analyze string data and strings accessed from code.