From b2bec7cece9bb7d17799ac0af65a770cab4397ee Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 26 Oct 2020 09:01:51 +0000 Subject: [PATCH] [AsmPrinter] Add per BB instruction mix remark. This patch adds a remarks that provides counts for each opcode per basic block. An snippet of the generated information can be seen below. The current implementation uses the target specific opcode for the counts. For example, on AArch64 this means we currently get 2 entries for `add` instructions if the block contains 32 and 64 bit adds. Similarly, immediate version are treated differently. Unfortunately there seems to be no convenient way to get only the mnemonic part of the instruction as a string AFAIK. This could be improved in the future. ``` --- !Analysis Pass: asm-printer Name: InstructionMix DebugLoc: { File: arm64-instruction-mix-remarks.ll, Line: 30, Column: 30 } Function: foo Args: - String: 'BasicBlock: ' - BasicBlock: else - String: "\n" - String: INST_MADDWrrr - String: ': ' - INST_MADDWrrr: '2' - String: "\n" - String: INST_MOVZWi - String: ': ' - INST_MOVZWi: '1' ``` Reviewed By: anemet, thegameg, paquette Differential Revision: https://reviews.llvm.org/D89892 --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 36 +++++++++++ .../AArch64/arm64-instruction-mix-remarks.ll | 75 ++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 llvm/test/CodeGen/AArch64/arm64-instruction-mix-remarks.ll diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 97236a5..f491fb1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1134,9 +1134,12 @@ void AsmPrinter::emitFunctionBody() { 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 @@ void AsmPrinter::emitFunctionBody() { break; default: emitInstruction(&MI); + if (CanDoExtraAnalysis) { + auto I = OpcodeCounts.insert({MI.getOpcode(), 0u}); + I.first->second++; + } break; } @@ -1245,6 +1252,35 @@ void AsmPrinter::emitFunctionBody() { } } emitBasicBlockEnd(MBB); + + if (CanDoExtraAnalysis) { + // Skip empty blocks. + if (MBB.empty()) + 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 index 0000000..f56d0d2 --- /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) -- 2.7.4