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 --histogram - | 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 --histogram - | 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 histogram: Flag<["--"], "histogram">, + HelpText<"Display histograms of mnemonics and immediates">; + 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,11 @@ bool objdump::SymbolTable; static bool SymbolizeOperands; +static bool Histogram; +std::map HistInst; +std::map HistSize; +std::map HistImm; + static bool DynamicSymbolTable; std::string objdump::TripleName; bool objdump::UnwindInfo; @@ -1482,6 +1487,30 @@ {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS, "", *STI, &SP, Obj->getFileName(), &Rels, LVP); + if (Disassembled && Histogram) { + const char *Mnemonic; + int Bytes; + std::tie(Mnemonic, Bytes) = IP->getMnemonic(&Inst); + + std::string ins = Mnemonic; + if (PrimaryIsThumb) { + if (Size == 2) + ins += " (T1)"; + else + ins += " (T2)"; + } + + HistInst[ins]++; + HistSize[ins] += Size; + + for (unsigned i = 0; i < Inst.getNumOperands(); i++) { + MCOperand Op = Inst.getOperand(i); + if (!Op.isImm()) + continue; + HistImm[Op.getImm()]++; + } + } + IP->setCommentStream(llvm::nulls()); // If disassembly has failed, avoid analysing invalid/incomplete @@ -2153,6 +2182,83 @@ outs() << ' ' << SymName << '\n'; } +static void printHistogram(const ObjectFile *O) { + std::vector> List; + unsigned TotalBytes = 0; + for (auto &I : HistSize) + TotalBytes += I.second; + for (auto &I : HistInst) + 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); + + // Add 1 for a whitespace. + MaxStrLen++; + MaxDigits++; + + outs() << "\nMnemonic histogram:\n\n"; + + // Print the columns, the format, the width should match that of the enties. + const char *MCol = "Mnemonic"; + const char *FCol = "Freq"; + const char *BCol = "Bytes"; + + outs() << format("%*s", MaxStrLen, MCol); + outs() << " "; // ":" + outs() << format("%*s", MaxDigits, FCol); + outs() << " "; // " (" + outs() << " "; + outs() << " "; // "%)" + outs() << format("%*s", MaxDigits + 2, BCol); + outs() << "\n"; + + // Now print the entries. + for (auto &I : List) { + outs() << format("%*s", MaxStrLen, I.first.c_str()); + outs() << ":"; + outs() << format("%*d", MaxDigits, I.second); + outs() << " ("; + outs() << format("%8g", ((float)I.second / (float)Total) * 100); + outs() << "%)"; + outs() << format("%*d", MaxDigits + 2, HistSize[I.first]); + outs() << " ("; + outs() << format("%8g", ((float) HistSize[I.first] / (float) TotalBytes) * 100); + outs() << "%)"; + outs() << "\n"; + } + + outs() << "\nImmediate histogram:\n\n"; + + std::vector> ImmList; + for (auto &I : HistImm) + ImmList.push_back(I); + + std::sort(ImmList.begin(), ImmList.end(), + [] (std::pair &L, + std::pair &R) { + return L.second > R.second; }); + + for (auto &I : ImmList) { + outs() << format("%10d", I.first); + outs() << ":"; + outs() << format("%10d", I.second); + outs() << "\n"; + } +} + static void printUnwindInfo(const ObjectFile *O) { outs() << "Unwind info:\n\n"; @@ -2412,6 +2518,8 @@ printSectionContents(O); if (Disassemble) disassembleObject(O, Relocations); + if (Histogram) + printHistogram(O); if (UnwindInfo) printUnwindInfo(O); @@ -2622,6 +2730,7 @@ HasStopAddressFlag = InputArgs.hasArg(OBJDUMP_stop_address_EQ); SymbolTable = InputArgs.hasArg(OBJDUMP_syms); SymbolizeOperands = InputArgs.hasArg(OBJDUMP_symbolize_operands); + Histogram = InputArgs.hasArg(OBJDUMP_histogram); DynamicSymbolTable = InputArgs.hasArg(OBJDUMP_dynamic_syms); TripleName = InputArgs.getLastArgValue(OBJDUMP_triple_EQ).str(); UnwindInfo = InputArgs.hasArg(OBJDUMP_unwind_info);