|
8 | 8 |
|
9 | 9 | #include "BenchmarkRunner.h"
|
10 | 10 | #include "Assembler.h"
|
| 11 | +#include "DisassemblerHelper.h" |
11 | 12 | #include "Error.h"
|
12 | 13 | #include "MCInstrDescView.h"
|
13 | 14 | #include "MmapUtils.h"
|
|
20 | 21 | #include "llvm/ADT/Twine.h"
|
21 | 22 | #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
|
22 | 23 | #include "llvm/Support/CrashRecoveryContext.h"
|
| 24 | +#include "llvm/Support/Debug.h" |
23 | 25 | #include "llvm/Support/Error.h"
|
24 | 26 | #include "llvm/Support/FileSystem.h"
|
25 | 27 | #include "llvm/Support/MemoryBuffer.h"
|
@@ -588,6 +590,89 @@ class SubProcessFunctionExecutorImpl
|
588 | 590 | const std::optional<int> BenchmarkProcessCPU;
|
589 | 591 | };
|
590 | 592 | #endif // __linux__
|
| 593 | + |
| 594 | +// Structure to hold instruction information for assembly printing |
| 595 | +struct InstructionInfo { |
| 596 | + std::string Text; |
| 597 | + uint64_t Address; |
| 598 | + std::string HexBytes; |
| 599 | +}; |
| 600 | + |
| 601 | +// Helper function to print generated assembly snippets |
| 602 | +void printInstructions(const std::vector<InstructionInfo> &Instructions, |
| 603 | + int InitialLinesCount, int LastLinesCount) { |
| 604 | + int N = Instructions.size(); |
| 605 | + dbgs() << "Generated assembly snippet:\n```\n"; |
| 606 | + |
| 607 | + // Print initial lines |
| 608 | + for (int i = 0; i < InitialLinesCount; ++i) |
| 609 | + dbgs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t" |
| 610 | + << Instructions[i].HexBytes << Instructions[i].Text << '\n'; |
| 611 | + |
| 612 | + // Show truncation message if needed |
| 613 | + int SkippedInstructions = N - InitialLinesCount - LastLinesCount; |
| 614 | + if (SkippedInstructions > 0) |
| 615 | + dbgs() << "...\t(" << SkippedInstructions << " more instructions)\n"; |
| 616 | + |
| 617 | + // Print last min(PreviewLast, N - PreviewFirst) lines |
| 618 | + int LastLinesToPrint = std::min( |
| 619 | + LastLinesCount, N > InitialLinesCount ? N - InitialLinesCount : 0); |
| 620 | + for (int i = N - LastLinesToPrint; i < N; ++i) |
| 621 | + dbgs() << format_hex_no_prefix(Instructions[i].Address, 0) << ":\t" |
| 622 | + << Instructions[i].HexBytes << Instructions[i].Text << '\n'; |
| 623 | + dbgs() << "```\n"; |
| 624 | +} |
| 625 | + |
| 626 | +// Function to extract and print assembly from snippet |
| 627 | +Error printAssembledSnippet(const LLVMState &State, |
| 628 | + const SmallString<0> &Snippet) { |
| 629 | + // Extract the actual function bytes from the object file |
| 630 | + std::vector<uint8_t> FunctionBytes; |
| 631 | + if (auto Err = getBenchmarkFunctionBytes(Snippet, FunctionBytes)) |
| 632 | + return make_error<Failure>("Failed to extract function bytes: " + |
| 633 | + toString(std::move(Err))); |
| 634 | + |
| 635 | + // Decode all instructions first |
| 636 | + DisassemblerHelper DisHelper(State); |
| 637 | + uint64_t Address = 0; |
| 638 | + std::vector<InstructionInfo> Instructions; |
| 639 | + const size_t FunctionBytesSize = FunctionBytes.size(); |
| 640 | + |
| 641 | + while (Address < FunctionBytesSize) { |
| 642 | + MCInst Inst; |
| 643 | + uint64_t Size; |
| 644 | + ArrayRef<uint8_t> Bytes(FunctionBytes.data() + Address, |
| 645 | + FunctionBytesSize - Address); |
| 646 | + |
| 647 | + if (!DisHelper.decodeInst(Inst, Size, Bytes)) { |
| 648 | + Instructions.push_back({"<decode error>", Address, ""}); |
| 649 | + break; |
| 650 | + } |
| 651 | + |
| 652 | + // Format instruction text |
| 653 | + std::string InstStr; |
| 654 | + raw_string_ostream OS(InstStr); |
| 655 | + DisHelper.printInst(&Inst, OS); |
| 656 | + |
| 657 | + // Create hex string for this instruction (big-endian order) |
| 658 | + std::string HexStr; |
| 659 | + raw_string_ostream HexOS(HexStr); |
| 660 | + for (int i = Size - 1; i >= 0; --i) |
| 661 | + HexOS << format_hex_no_prefix(Bytes[i], 2); |
| 662 | + |
| 663 | + Instructions.push_back({OS.str(), Address, HexOS.str()}); |
| 664 | + Address += Size; |
| 665 | + } |
| 666 | + |
| 667 | +#undef DEBUG_TYPE |
| 668 | +#define DEBUG_TYPE "preview-gen-assembly" |
| 669 | + LLVM_DEBUG(printInstructions(Instructions, 10, 3)); |
| 670 | +#undef DEBUG_TYPE |
| 671 | +#define DEBUG_TYPE "print-gen-assembly" |
| 672 | + LLVM_DEBUG(printInstructions(Instructions, Instructions.size(), 0)); |
| 673 | +#undef DEBUG_TYPE |
| 674 | + return Error::success(); |
| 675 | +} |
591 | 676 | } // namespace
|
592 | 677 |
|
593 | 678 | Expected<SmallString<0>> BenchmarkRunner::assembleSnippet(
|
@@ -655,6 +740,10 @@ BenchmarkRunner::getRunnableConfiguration(
|
655 | 740 | if (Error E = Snippet.takeError())
|
656 | 741 | return std::move(E);
|
657 | 742 | RC.ObjectFile = getObjectFromBuffer(*Snippet);
|
| 743 | + |
| 744 | + // Print the assembled snippet by disassembling the binary data |
| 745 | + if (Error E = printAssembledSnippet(State, *Snippet)) |
| 746 | + return std::move(E); |
658 | 747 | }
|
659 | 748 |
|
660 | 749 | return std::move(RC);
|
|
0 commit comments