diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1134,9 +1134,12 @@ bool HasAnyRealCode = false; int NumInstsInFunction = 0; + bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE); + const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); for (auto &MBB : *MF) { // Print a label for the basic block. emitBasicBlockStart(MBB); + DenseMap OpcodeCounts; for (auto &MI : MBB) { // Print the assembly for the instruction. if (!MI.isPosition() && !MI.isImplicitDef() && !MI.isKill() && @@ -1202,6 +1205,10 @@ break; default: emitInstruction(&MI); + if (CanDoExtraAnalysis) { + auto I = OpcodeCounts.insert({MI.getOpcode(), 0u}); + I.first->second++; + } break; } @@ -1245,6 +1252,35 @@ } } emitBasicBlockEnd(MBB); + + if (CanDoExtraAnalysis) { + // Skip empty blocks. + if (MBB.begin() == MBB.end()) + continue; + + MachineOptimizationRemarkAnalysis R(DEBUG_TYPE, "InstructionMix", + MBB.begin()->getDebugLoc(), &MBB); + + // Generate instruction mix remark. First, convert opcodes to string + // names, then sort them in descending order by count and name. + SmallVector, 128> OpcodeCountsVec; + for (auto &KV : OpcodeCounts) { + auto Name = (Twine("INST_") + TII->getName(KV.first)).str(); + OpcodeCountsVec.emplace_back(Name, KV.second); + } + sort(OpcodeCountsVec, [](const std::pair &A, + const std::pair &B) { + if (A.second > B.second) + return true; + if (A.second == B.second) + return A.first < B.first; + return false; + }); + R << "BasicBlock: " << ore::NV("BasicBlock", MBB.getName()) << "\n"; + for (auto &KV : OpcodeCountsVec) + R << KV.first << ": " << ore::NV(KV.first, KV.second) << "\n"; + ORE->emit(R); + } } EmittedInsts += NumInstsInFunction; diff --git a/llvm/test/CodeGen/AArch64/arm64-instruction-mix-remarks.ll b/llvm/test/CodeGen/AArch64/arm64-instruction-mix-remarks.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64-instruction-mix-remarks.ll @@ -0,0 +1,75 @@ +; RUN: llc -mtriple=arm64-apple-ios7.0 -pass-remarks-output=%t -pass-remarks=asm-printer -o - %s | FileCheck %s +; RUN: FileCheck --input-file=%t --check-prefix=YAML %s + +; CHECK-LABEL: %entry +; CHECK-NEXT: ldr w8, [x0] +; CHECK-NEXT: add w8, w8, w1 +; CHECK-NEXT: cmp w8, #100 +; CHECK-NEXT: b.ne LBB0_2 + +; YAML: Name: InstructionMix +; YAML-NEXT: DebugLoc: { File: arm64-instruction-mix-remarks.ll, Line: 10, Column: 10 } +; YAML-NEXT: Function: foo +; YAML-NEXT: Args: +; YAML: - BasicBlock: entry +; YAML: - INST_ADDWrs: '1' +; YAML: - INST_Bcc: '1' +; YAML: - INST_LDRWui: '1' +; YAML: - INST_SUBSWri: '1' + + +; CHECK-LABEL: %then +; CHECK-NEXT: mov w0, w8 +; CHECK-NEXT: ret + +; YAML: Name: InstructionMix +; YAML-NEXT: DebugLoc: { File: arm64-instruction-mix-remarks.ll, Line: 20, Column: 20 } +; YAML-NEXT: Function: foo +; YAML-NEXT: Args: +; YAML: - BasicBlock: then +; YAML: - INST_ORRWrs: '1' +; YAML: - INST_RET: '1' + +; CHECK-LABEL: %else +; CHECK-NEXT: mul w8, w8, w1 +; CHECK-NEXT: mov w9, #10 +; CHECK-NEXT: mul w8, w8, w1 +; CHECK-NEXT: str w9, [x0] +; CHECK-NEXT: mov w0, w8 +; CHECK-NEXT: ret + +; YAML: Name: InstructionMix +; YAML-NEXT: DebugLoc: { File: arm64-instruction-mix-remarks.ll, Line: 30, Column: 30 } +; YAML-NEXT: Function: foo +; YAML-NEXT: Args: +; YAML: - BasicBlock: else +; YAML: - INST_MADDWrrr: '2' +; YAML: - INST_ORRWrs: '1' +; YAML: - INST_RET: '1' +; YAML: - INST_STRWui: '1' +define i32 @foo(i32* %ptr, i32 %x) !dbg !3 { +entry: + %l = load i32, i32* %ptr, !dbg !4 + %add = add i32 %l, %x, !dbg !4 + %c = icmp eq i32 %add, 100, !dbg !4 + br i1 %c, label %then, label %else, !dbg !4 + +then: + ret i32 %add, !dbg !5 + +else: + store i32 10, i32* %ptr, !dbg !6 + %res = mul i32 %add, %x, !dbg !6 + %res.2 = mul i32 %res, %x, !dbg !6 + ret i32 %res.2, !dbg !6 +} +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2} + +!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1) +!1 = !DIFile(filename: "arm64-instruction-mix-remarks.ll", directory: "") +!2 = !{i32 2, !"Debug Info Version", i32 3} +!3 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, scopeLine: 5, unit: !0) +!4 = distinct !DILocation(line: 10, column: 10, scope: !3) +!5 = distinct !DILocation(line: 20, column: 20, scope: !3) +!6 = distinct !DILocation(line: 30, column: 30, scope: !3)