Index: llvm/test/tools/llvm-objdump/ARM/mnemonic-hist0.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-objdump/ARM/mnemonic-hist0.test @@ -0,0 +1,10 @@ +#RUN: llvm-mc -filetype=obj -triple=thumbv7 %s -o - | \ +#RUN: llvm-objdump --triple=thumbv7 -d --mnemonic-hist - | FileCheck %s + + .text + .thumb +foo: + +#CHECK: Mnemonic histogram:{{[[:space:]]}} +#CHECK: {{[[:space:]]}} +#CHECK-NOT: {{.*}}: Index: llvm/test/tools/llvm-objdump/ARM/mnemonic-hist1.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-objdump/ARM/mnemonic-hist1.test @@ -0,0 +1,17 @@ +#RUN: llvm-mc -filetype=obj -triple=thumbv7 %s -o - | \ +#RUN: llvm-objdump --triple=thumbv7 -d --mnemonic-hist - | FileCheck %s + + .syntax unified + .text + .thumb + +foo: + add r0,r1,r2 + sub r2,r1,r3 + add r4,r0,r2 + mul r5,r4,r1 + +#CHECK:Mnemonic histogram: +#CHECK: add: 2 (50%) +#CHECK: mul: 1 (25%) +#CHECK: sub: 1 (25%) Index: llvm/tools/llvm-objdump/ObjdumpOpts.td =================================================================== --- llvm/tools/llvm-objdump/ObjdumpOpts.td +++ llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -174,6 +174,9 @@ def symbolize_operands : Flag<["--"], "symbolize-operands">, HelpText<"Symbolize instruction operands when disassembling">; +def mnemonic_hist: Flag<["--"], "mnemonic-hist">, + HelpText<"Display a histogram of all mnemonics">; + def dynamic_syms : Flag<["--"], "dynamic-syms">, HelpText<"Display the contents of the dynamic symbol table">; def : Flag<["-"], "T">, Alias, Index: llvm/tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- llvm/tools/llvm-objdump/llvm-objdump.cpp +++ llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -213,6 +213,9 @@ bool objdump::SymbolTable; static bool SymbolizeOperands; +static bool MnemonicHistogram; +std::map Hist; + static bool DynamicSymbolTable; std::string objdump::TripleName; bool objdump::UnwindInfo; @@ -1482,6 +1485,13 @@ {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS, "", *STI, &SP, Obj->getFileName(), &Rels, LVP); + if (Disassembled && MnemonicHistogram) { + const char *Mnemonic; + int Bytes; + std::tie(Mnemonic, Bytes) = IP->getMnemonic(&Inst); + Hist[Mnemonic]++; + } + IP->setCommentStream(llvm::nulls()); // If disassembly has failed, avoid analysing invalid/incomplete @@ -2153,6 +2163,36 @@ outs() << ' ' << SymName << '\n'; } +static void printMnemonicHistogram(const ObjectFile *O) { + std::vector> List; + for (auto &I : Hist) + List.push_back(I); + + std::sort(List.begin(), List.end(), [] (std::pair &L, + std::pair &R) { + return L.second > R.second; }); + + unsigned Total = 0; + unsigned MaxStrLen = 0; + for (auto &I : List) { + Total += I.second; + MaxStrLen = I.first.length() > MaxStrLen ? I.first.length() : MaxStrLen; + } + + unsigned MaxDigits = List.empty() ? 0 : + unsigned(std::log10(List.front().second) + 1); + + outs() << "\nMnemonic histogram:\n\n"; + for (auto &I : List) { + outs() << format("%*s", MaxStrLen + 1, I.first.c_str()); + outs() << ":"; + outs() << format("%*d", MaxDigits + 1, I.second); + outs() << " ("; + outs() << format("%g", ((float)I.second / (float)Total) * 100); + outs() << "%)\n"; + } +} + static void printUnwindInfo(const ObjectFile *O) { outs() << "Unwind info:\n\n"; @@ -2412,6 +2452,8 @@ printSectionContents(O); if (Disassemble) disassembleObject(O, Relocations); + if (MnemonicHistogram) + printMnemonicHistogram(O); if (UnwindInfo) printUnwindInfo(O); @@ -2622,6 +2664,7 @@ HasStopAddressFlag = InputArgs.hasArg(OBJDUMP_stop_address_EQ); SymbolTable = InputArgs.hasArg(OBJDUMP_syms); SymbolizeOperands = InputArgs.hasArg(OBJDUMP_symbolize_operands); + MnemonicHistogram = InputArgs.hasArg(OBJDUMP_mnemonic_hist); DynamicSymbolTable = InputArgs.hasArg(OBJDUMP_dynamic_syms); TripleName = InputArgs.getLastArgValue(OBJDUMP_triple_EQ).str(); UnwindInfo = InputArgs.hasArg(OBJDUMP_unwind_info);