summaryrefslogtreecommitdiff
path: root/bootstrap/llvm16/exegesis-mcjit.patch
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap/llvm16/exegesis-mcjit.patch')
-rw-r--r--bootstrap/llvm16/exegesis-mcjit.patch348
1 files changed, 348 insertions, 0 deletions
diff --git a/bootstrap/llvm16/exegesis-mcjit.patch b/bootstrap/llvm16/exegesis-mcjit.patch
new file mode 100644
index 000000000..7363965c2
--- /dev/null
+++ b/bootstrap/llvm16/exegesis-mcjit.patch
@@ -0,0 +1,348 @@
+This is a backport from LLVM 17 that fixes a test failure observed on
+ppc64:
+
+********************
+FAIL: LLVM :: tools/llvm-exegesis/PowerPC/latency-by-opcode-name.s (216 of 47688)
+******************** TEST 'LLVM :: tools/llvm-exegesis/PowerPC/latency-by-opcode-name.s' FAILED ********************
+PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
+Stack dump:
+0. Program arguments: /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/build/bin/llvm-exegesis -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 --benchmark-phase=assemble-measured-code -mode=latency -opcode-name=ADD8
+ #0 0x0000000141a994d0 llvm::sys::RunSignalHandlers() /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/Support/Signals.cpp:103:22
+ #1 0x0000000141a994d0 SignalHandler(int) /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/Support/Unix/Signals.inc:402:31
+ #2 0x00003fff89552444 0x444 __register_frame_info_bases
+ #3 0x00003fff89552444
+ #4 0x00003fff89552444 __register_frame_info (+0x444)
+ #5 0xaaaaaaaaaaaaaaab
+ #6 0x00003fff8907b700 __register_frame (/usr/lib/libgcc_s.so.1+0x12700)
+ #7 0x00003fff8907b760 llvm::RTDyldMemoryManager::registerEHFramesInProcess(unsigned char*, unsigned long) /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp:119:19
+ #8 0x00003fff8907b760 llvm::RTDyldMemoryManager::registerEHFrames(unsigned char*, unsigned long, unsigned long) /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp:131:28
+ #9 0x00003fff8907b7c0 llvm::RuntimeDyldELF::registerEHFrames() /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp:227:28
+#10 0x0000000142e9d1b0 llvm::RuntimeDyld::registerEHFrames() /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:1435:27
+#11 0x0000000142eb4258 llvm::MCJIT::finalizeLoadedModules() /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:251:24
+#12 0x0000000142ea2154 __gthread_mutex_unlock /usr/include/c++/13.3.0/powerpc64-foxkit-linux-musl/bits/gthr-default.h:779:43
+#13 0x0000000142ea2154 __gthread_recursive_mutex_unlock /usr/include/c++/13.3.0/powerpc64-foxkit-linux-musl/bits/gthr-default.h:832:33
+#14 0x0000000142ea2154 std::recursive_mutex::unlock() /usr/include/c++/13.3.0/mutex:139:39
+#15 0x0000000142ea2154 llvm::sys::SmartMutex<false>::unlock() /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/include/llvm/Support/Mutex.h:47:22
+#16 0x0000000142ea2154 std::lock_guard<llvm::sys::SmartMutex<false>>::~lock_guard() /usr/include/c++/13.3.0/bits/std_mutex.h:255:25
+#17 0x0000000142ea2154 llvm::MCJIT::getFunctionAddress(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:410:1
+#18 0x0000000142b6f948 llvm::exegesis::ExecutableFunction::ExecutableFunction(std::unique_ptr<llvm::LLVMTargetMachine, std::default_delete<llvm::LLVMTargetMachine>>, llvm::object::OwningBinary<llvm::object::ObjectFile>&&) /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/tools/llvm-exegesis/lib/Assembler.cpp:319:66
+#19 0x0000000142b73a18 llvm::exegesis::BenchmarkRunner::getRunnableConfiguration(llvm::exegesis::BenchmarkCode const&, unsigned int, unsigned int, llvm::exegesis::SnippetRepetitor const&) const /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp:181:62
+#20 0x0000000141af099c llvm::exegesis::runBenchmarkConfigurations(llvm::exegesis::LLVMState const&, llvm::ArrayRef<llvm::exegesis::BenchmarkCode>, llvm::ArrayRef<std::unique_ptr<llvm::exegesis::SnippetRepetitor const, std::default_delete<llvm::exegesis::SnippetRepetitor const>>>, llvm::exegesis::BenchmarkRunner const&) /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/tools/llvm-exegesis/llvm-exegesis.cpp:376:58
+#21 0x0000000141aca060 llvm::exegesis::benchmarkMain() /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/tools/llvm-exegesis/llvm-exegesis.cpp:506:30
+#22 0x000000013fbe7144 main /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/tools/llvm-exegesis/llvm-exegesis.cpp:660:1
+#23 0x000000013fbea0a8 libc_start_main_stage2 /usr/src/packages/system/musl/src/musl-1.2.3/src/env/__libc_start_main.c:95:2
+#24 0x000000013fb105ac __libc_start_main /usr/src/packages/system/musl/src/musl-1.2.3/src/env/__libc_start_main.c:86:9
+#25 0x00003fff89494038 _start_c /usr/src/packages/system/musl/src/musl-1.2.3/crt/crt1.c:18:2
+#26 0x00003fff894940b4 _start (/lib/ld-musl-powerpc64.so.1+0x220b4)
+Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
+0 llvm-exegesis 0x0000000141a994d0
+1 0x00003fff89552444 __kernel_sigtramp_rt64 + 0
+2 0xaaaaaaaaaaaaaaab __kernel_sigtramp_rt64 + 12297759015719765607
+3 libgcc_s.so.1 0x00003fff8907b700 __register_frame_info_bases + 128
+4 libgcc_s.so.1 0x00003fff8907b760 __register_frame_info + 32
+5 libgcc_s.so.1 0x00003fff8907b7c0 __register_frame + 64
+6 llvm-exegesis 0x0000000142e9d1b0
+7 llvm-exegesis 0x0000000142eb4258
+8 llvm-exegesis 0x0000000142ea2154
+9 llvm-exegesis 0x0000000142b6f948
+10 llvm-exegesis 0x0000000142b73a18
+11 llvm-exegesis 0x0000000141af099c
+12 llvm-exegesis 0x0000000141aca060
+13 llvm-exegesis 0x000000013fbe7144
+14 llvm-exegesis 0x000000013fbea0a8
+15 llvm-exegesis 0x000000013fb105ac
+16 ld-musl-powerpc64.so.1 0x00003fff89494038
+17 ld-musl-powerpc64.so.1 0x00003fff894940b4 __libc_start_main + 100
+18 llvm-exegesis 0x000000013fbdcf78
+19 llvm-exegesis 0x000000013fbdcf20
+FileCheck error: '<stdin>' is empty.
+FileCheck command line: /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/build/bin/FileCheck /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/test/tools/llvm-exegesis/PowerPC/latency-by-opcode-name.s
+
+Tracing with a debug-build libgcc_s yields:
+
+Program received signal SIGSEGV, Segmentation fault.
+classify_object_over_fdes (ob=0x3ffff7904700, this_fde=0x400007ae4004, range=0x3fffffffd700) at /home/awilcox/Code/awilfox/gcc-next/system/gcc/src/gcc-13.3.0/libgcc/unwind-dw2-fde.c:732
+732 for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde))
+(gdb) bt
+#0 classify_object_over_fdes (ob=0x3ffff7904700, this_fde=0x400007ae4004, range=0x3fffffffd700)
+ at /home/awilcox/Code/awilfox/gcc-next/system/gcc/src/gcc-13.3.0/libgcc/unwind-dw2-fde.c:732
+#1 0x00003ffff7b47700 in register_pc_range_for_object (ob=0x3ffff7904700, begin=<optimized out>)
+ at /home/awilcox/Code/awilfox/gcc-next/system/gcc/src/gcc-13.3.0/libgcc/unwind-dw2-fde.c:118
+#2 __register_frame_info_bases (dbase=<optimized out>, tbase=<optimized out>, ob=0x3ffff7904700, begin=<optimized out>)
+ at /home/awilcox/Code/awilfox/gcc-next/system/gcc/src/gcc-13.3.0/libgcc/unwind-dw2-fde.c:144
+#3 __register_frame_info_bases (begin=<optimized out>, ob=0x3ffff7904700, tbase=<optimized out>, dbase=<optimized out>)
+ at /home/awilcox/Code/awilfox/gcc-next/system/gcc/src/gcc-13.3.0/libgcc/unwind-dw2-fde.c:126
+#4 0x00003ffff7b47760 in __register_frame_info (begin=<optimized out>, ob=<optimized out>)
+ at /home/awilcox/Code/awilfox/gcc-next/system/gcc/src/gcc-13.3.0/libgcc/unwind-dw2-fde.c:159
+#5 0x00003ffff7b477c0 in __register_frame (begin=0x3ffff7ae4000)
+ at /home/awilcox/Code/awilfox/gcc-next/system/gcc/src/gcc-13.3.0/libgcc/unwind-dw2-fde.c:172
+#6 0x00000001038da4f0 in llvm::RTDyldMemoryManager::registerEHFramesInProcess (Size=<optimized out>, Addr=<optimized out>)
+ at /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp:119
+#7 llvm::RTDyldMemoryManager::registerEHFrames (this=0x3ffff78b1700, Addr=<optimized out>, LoadAddr=<optimized out>,
+ Size=<optimized out>)
+ at /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp:131
+#8 0x00000001038f1598 in llvm::RuntimeDyldELF::registerEHFrames (this=0x3ffff7b0e550)
+ at /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp:227
+#9 0x00000001038df494 in llvm::RuntimeDyld::registerEHFrames (this=<optimized out>)
+ at /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:1435
+#10 0x00000001035acc88 in llvm::MCJIT::finalizeLoadedModules (this=0x3ffff7aef0b0)
+ at /home/awilcox/Code/awilfox/rust-next/bootstrap/llvm16/src/llvm-project-16.0.6.src/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:251
+
+The reason is because it is trying to interpret a little-endian FDE as a
+native (big-endian) one and failing. This was noted upstream and fixed
+in the LLVM 17 branch but it was never backported to a 16 release.
+
+From 27f37db76a79e746561ad2545ff6ccf0d50cc38c Mon Sep 17 00:00:00 2001
+From: Pavel Kosov <kpdev42@gmail.com>
+Date: Thu, 8 Jun 2023 19:14:00 +0300
+Subject: [PATCH] [llvm-exegesis] Use MCJIT only for execution
+
+Initially, llvm-exegesis was generating the benchmark code for the
+host CPU to execute it inside its own process. Thus, MCJIT was reused
+for fetching function's bytes to fill the assembled_snippet field in
+the benchmark report.
+
+Later, the --mtriple and --benchmark-phase command line options were
+introduced that are handy for testing snippet generation even if
+snippet execution is not possible. In that setup, MCJIT is asked to
+parse an object file for a foreign CPU or operating system that is
+probably not guaranteed to succeed and was actually observed to fail
+in https://reviews.llvm.org/D145763.
+
+This commit implements a much simplified function's code fetching,
+assuming the benchmark function is the only function in the object file
+and it spans across the entire text section (note that MCJIT-based code
+has more or less the same assumption - see TrackingSectionMemoryManager
+class).
+
+~~~
+
+Huawei RRI, OS Lab
+
+Reviewed By: courbet
+
+Differential Revision: https://reviews.llvm.org/D148921
+---
+ .../AArch64/print-assembled-snippet.s | 31 +++++++++++++++++
+ .../Mips/print-assembled-snippet.s | 23 +++++++++++++
+ .../PowerPC/print-assembled-snippet.s | 15 ++++++++
+ .../X86/print-assembled-snippet.s | 32 +++++++++++++++++
+ llvm/tools/llvm-exegesis/lib/Assembler.cpp | 34 +++++++++++++++++++
+ llvm/tools/llvm-exegesis/lib/Assembler.h | 4 +++
+ .../llvm-exegesis/lib/BenchmarkRunner.cpp | 8 ++---
+ 7 files changed, 143 insertions(+), 4 deletions(-)
+ create mode 100644 llvm/test/tools/llvm-exegesis/AArch64/print-assembled-snippet.s
+ create mode 100644 llvm/test/tools/llvm-exegesis/Mips/print-assembled-snippet.s
+ create mode 100644 llvm/test/tools/llvm-exegesis/PowerPC/print-assembled-snippet.s
+ create mode 100644 llvm/test/tools/llvm-exegesis/X86/print-assembled-snippet.s
+
+diff --git a/llvm/test/tools/llvm-exegesis/AArch64/print-assembled-snippet.s b/llvm/test/tools/llvm-exegesis/AArch64/print-assembled-snippet.s
+new file mode 100644
+index 0000000000000..e8b312d7a6ae9
+--- /dev/null
++++ llvm/test/tools/llvm-exegesis/AArch64/print-assembled-snippet.s
+@@ -0,0 +1,31 @@
++# Check that "assembled_snippet" is fetched correctly from object file.
++# Feel free to update the snippet in this test if the code generated by the
++# snippet repetitor was changed intentionally and it is still fetched correctly.
++
++# RUN: llvm-exegesis --mtriple=aarch64-linux-gnu --mcpu=generic --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-LINUX
++
++# RUN: llvm-exegesis --mtriple=aarch64-windows-gnu --mcpu=generic --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-WINDOWS-GNU
++
++# RUN: llvm-exegesis --mtriple=aarch64-windows-msvc --mcpu=generic --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-WINDOWS-MSVC
++
++# LLVM-EXEGESIS-DEFREG X0 0
++# LLVM-EXEGESIS-DEFREG X1 0
++add x0, x0, x1
++
++# CHECK-LINUX: cpu_name: generic
++# CHECK-LINUX: llvm_triple: aarch64-unknown-linux-gnu
++# CHECK-LINUX: assembled_snippet: 000080D2010080D20000018B0000018B0000018B0000018BC0035FD6{{$}}
++
++# CHECK-WINDOWS-GNU: cpu_name: generic
++# CHECK-WINDOWS-GNU: llvm_triple: aarch64-unknown-windows-gnu
++# CHECK-WINDOWS-GNU: assembled_snippet: 000080D2010080D20000018B0000018B0000018B0000018BC0035FD6{{$}}
++
++# CHECK-WINDOWS-MSVC: cpu_name: generic
++# CHECK-WINDOWS-MSVC: llvm_triple: aarch64-unknown-windows-msvc
++# CHECK-WINDOWS-MSVC: assembled_snippet: 000080D2010080D20000018B0000018B0000018B0000018BC0035FD6{{$}}
+diff --git a/llvm/test/tools/llvm-exegesis/Mips/print-assembled-snippet.s b/llvm/test/tools/llvm-exegesis/Mips/print-assembled-snippet.s
+new file mode 100644
+index 0000000000000..f0844c4145a2b
+--- /dev/null
++++ llvm/test/tools/llvm-exegesis/Mips/print-assembled-snippet.s
+@@ -0,0 +1,23 @@
++# Check that "assembled_snippet" is fetched correctly from object file.
++# Feel free to update the snippet in this test if the code generated by the
++# snippet repetitor was changed intentionally and it is still fetched correctly.
++
++# RUN: llvm-exegesis --mtriple=mips-linux-gnu --mcpu=generic --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-LINUX
++
++# RUN: llvm-exegesis --mtriple=mips64-linux-gnu --mcpu=generic --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-LINUX-64
++
++# LLVM-EXEGESIS-DEFREG A0 0
++# LLVM-EXEGESIS-DEFREG A1 0
++add $2, $5, $4
++
++# CHECK-LINUX: cpu_name: generic
++# CHECK-LINUX: llvm_triple: mips-unknown-linux-gnu
++# CHECK-LINUX: assembled_snippet: 340400003405000000A4102000A4102000A4102000A4102003E00008{{$}}
++
++# CHECK-LINUX-64: cpu_name: generic
++# CHECK-LINUX-64: llvm_triple: mips64-unknown-linux-gnu
++# CHECK-LINUX-64: assembled_snippet: 340400003405000000A4102000A4102000A4102000A4102003E00008{{$}}
+diff --git a/llvm/test/tools/llvm-exegesis/PowerPC/print-assembled-snippet.s b/llvm/test/tools/llvm-exegesis/PowerPC/print-assembled-snippet.s
+new file mode 100644
+index 0000000000000..75cad37a768eb
+--- /dev/null
++++ llvm/test/tools/llvm-exegesis/PowerPC/print-assembled-snippet.s
+@@ -0,0 +1,15 @@
++# Check that "assembled_snippet" is fetched correctly from object file.
++# Feel free to update the snippet in this test if the code generated by the
++# snippet repetitor was changed intentionally and it is still fetched correctly.
++
++# RUN: llvm-exegesis --mtriple=powerpc64le-linux-gnu --mcpu=pwr8 --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-LINUX-64-LE
++
++# LLVM-EXEGESIS-DEFREG R3 0
++# LLVM-EXEGESIS-DEFREG R4 0
++add 3, 4, 3
++
++# CHECK-LINUX-64-LE: cpu_name: pwr8
++# CHECK-LINUX-64-LE: llvm_triple: powerpc64le-unknown-linux-gnu
++# CHECK-LINUX-64-LE: assembled_snippet: 0000603800008038141A647C141A647C141A647C141A647C2000804E000000000000000000000000{{$}}
+diff --git a/llvm/test/tools/llvm-exegesis/X86/print-assembled-snippet.s b/llvm/test/tools/llvm-exegesis/X86/print-assembled-snippet.s
+new file mode 100644
+index 0000000000000..532901d0e0430
+--- /dev/null
++++ llvm/test/tools/llvm-exegesis/X86/print-assembled-snippet.s
+@@ -0,0 +1,32 @@
++# Check that "assembled_snippet" is fetched correctly from object file.
++# Feel free to update the snippet in this test if the code generated by the
++# snippet repetitor was changed intentionally and it is still fetched correctly.
++
++# RUN: llvm-exegesis --mtriple=x86_64-linux-gnu --mcpu=x86-64 --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-LINUX
++
++# RUN: llvm-exegesis --mtriple=x86_64-windows-gnu --mcpu=x86-64 --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-WINDOWS-GNU
++
++# RUN: llvm-exegesis --mtriple=x86_64-windows-msvc --mcpu=x86-64 --benchmark-phase=prepare-and-assemble-snippet \
++# RUN: --snippets-file=%s --mode=latency --repetition-mode=duplicate \
++# RUN: | FileCheck %s --check-prefix=CHECK-WINDOWS-MSVC
++
++# LLVM-EXEGESIS-DEFREG RDI 0
++# LLVM-EXEGESIS-DEFREG RSI 0
++# LLVM-EXEGESIS-DEFREG RAX 0
++leaq (%rdi,%rsi), %rax
++
++# CHECK-LINUX: cpu_name: x86-64
++# CHECK-LINUX: llvm_triple: x86_64-unknown-linux-gnu
++# CHECK-LINUX: assembled_snippet: 48BF000000000000000048BE000000000000000048B80000000000000000488D0437488D0437488D0437488D0437C3{{$}}
++
++# CHECK-WINDOWS-GNU: cpu_name: x86-64
++# CHECK-WINDOWS-GNU: llvm_triple: x86_64-unknown-windows-gnu
++# CHECK-WINDOWS-GNU: assembled_snippet: 565748BF000000000000000048BE000000000000000048B80000000000000000488D0437488D0437488D0437488D04375F5EC3{{$}}
++
++# CHECK-WINDOWS-MSVC: cpu_name: x86-64
++# CHECK-WINDOWS-MSVC: llvm_triple: x86_64-unknown-windows-msvc
++# CHECK-WINDOWS-MSVC: assembled_snippet: 565748BF000000000000000048BE000000000000000048B80000000000000000488D0437488D0437488D0437488D04375F5EC3{{$}}
+diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.cpp b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
+index 07465c71afc70..8e561f587cc2a 100644
+--- llvm/tools/llvm-exegesis/lib/Assembler.cpp
++++ llvm/tools/llvm-exegesis/lib/Assembler.cpp
+@@ -25,6 +25,7 @@
+ #include "llvm/MC/MCInstrInfo.h"
+ #include "llvm/Support/Alignment.h"
+ #include "llvm/Support/MemoryBuffer.h"
++#include "llvm/Support/raw_ostream.h"
+
+ namespace llvm {
+ namespace exegesis {
+@@ -323,5 +324,38 @@ ExecutableFunction::ExecutableFunction(
+ StringRef(reinterpret_cast<const char *>(FunctionAddress), CodeSize);
+ }
+
++Error getBenchmarkFunctionBytes(const StringRef InputData,
++ std::vector<uint8_t> &Bytes) {
++ const auto Holder = getObjectFromBuffer(InputData);
++ const auto *Obj = Holder.getBinary();
++ // See RuntimeDyldImpl::loadObjectImpl(Obj) for much more complete
++ // implementation.
++
++ // Find the only function in the object file.
++ SmallVector<object::SymbolRef, 1> Functions;
++ for (auto &Sym : Obj->symbols()) {
++ auto SymType = Sym.getType();
++ if (SymType && *SymType == object::SymbolRef::Type::ST_Function)
++ Functions.push_back(Sym);
++ }
++ if (Functions.size() != 1)
++ return make_error<Failure>("Exactly one function expected");
++
++ // Find the containing section - it is assumed to contain only this function.
++ auto SectionOrErr = Functions.front().getSection();
++ if (!SectionOrErr || *SectionOrErr == Obj->section_end())
++ return make_error<Failure>("Section not found");
++
++ auto Address = Functions.front().getAddress();
++ if (!Address || *Address != SectionOrErr.get()->getAddress())
++ return make_error<Failure>("Unexpected layout");
++
++ auto ContentsOrErr = SectionOrErr.get()->getContents();
++ if (!ContentsOrErr)
++ return ContentsOrErr.takeError();
++ Bytes.assign(ContentsOrErr->begin(), ContentsOrErr->end());
++ return Error::success();
++}
++
+ } // namespace exegesis
+ } // namespace llvm
+diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.h b/llvm/tools/llvm-exegesis/lib/Assembler.h
+index 2a83344b751e5..cd1e398e4a564 100644
+--- llvm/tools/llvm-exegesis/lib/Assembler.h
++++ llvm/tools/llvm-exegesis/lib/Assembler.h
+@@ -121,6 +121,10 @@ struct ExecutableFunction {
+ StringRef FunctionBytes;
+ };
+
++// Copies benchmark function's bytes from benchmark object.
++Error getBenchmarkFunctionBytes(const StringRef InputData,
++ std::vector<uint8_t> &Bytes);
++
+ // Creates a void(int8*) MachineFunction.
+ MachineFunction &createVoidVoidPtrMachineFunction(StringRef FunctionID,
+ Module *Module,
+diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+index e1df2940a9b7e..f934b8ec4c6cc 100644
+--- llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
++++ llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+@@ -177,10 +177,10 @@ BenchmarkRunner::getRunnableConfiguration(
+ LoopBodySizeForSnippet);
+ if (Error E = Snippet.takeError())
+ return std::move(E);
+- const ExecutableFunction EF(State.createTargetMachine(),
+- getObjectFromBuffer(*Snippet));
+- const auto FnBytes = EF.getFunctionBytes();
+- llvm::append_range(InstrBenchmark.AssembledSnippet, FnBytes);
++
++ if (auto Err = getBenchmarkFunctionBytes(*Snippet,
++ InstrBenchmark.AssembledSnippet))
++ return std::move(Err);
+ }
+
+ // Assemble NumRepetitions instructions repetitions of the snippet for