diff --git a/llvm/test/tools/llvm-exegesis/X86/uops-FLDENVm.s b/llvm/test/tools/llvm-exegesis/X86/uops-FLDENVm.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-exegesis/X86/uops-FLDENVm.s @@ -0,0 +1,6 @@ +# RUN: llvm-exegesis -mode=uops -opcode-name=FLDENVm,FLDL2E -repetition-mode=duplicate | FileCheck %s + +CHECK: mode: uops +CHECK-NEXT: key: +CHECK-NEXT: instructions: +CHECK-NEXT: FLDENVm diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp --- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -71,10 +71,10 @@ SmallVector CounterNames; StringRef(Counters).split(CounterNames, '+'); char *const ScratchPtr = Scratch->ptr(); + const ExegesisTarget &ET = State.getExegesisTarget(); for (auto &CounterName : CounterNames) { CounterName = CounterName.trim(); - auto CounterOrError = - State.getExegesisTarget().createCounter(CounterName, State); + auto CounterOrError = ET.createCounter(CounterName, State); if (!CounterOrError) return CounterOrError.takeError(); @@ -93,6 +93,7 @@ .concat(std::to_string(Reserved))); Scratch->clear(); { + auto PS = ET.withPreservedState(); CrashRecoveryContext CRC; CrashRecoveryContext::Enable(); const bool Crashed = !CRC.RunSafely([this, Counter, ScratchPtr]() { @@ -101,6 +102,7 @@ Counter->stop(); }); CrashRecoveryContext::Disable(); + PS.reset(); if (Crashed) { std::string Msg = "snippet crashed while running"; #ifdef LLVM_ON_UNIX diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h --- a/llvm/tools/llvm-exegesis/lib/Target.h +++ b/llvm/tools/llvm-exegesis/lib/Target.h @@ -172,6 +172,16 @@ // counters are defined for this CPU). const PfmCountersInfo &getPfmCounters(StringRef CpuName) const; + // Saves the CPU state that needs to be preserved when running a benchmark, + // and returns and RAII object that restores the state on destruction. + // By default no state is preserved. + struct PreservedState { + virtual ~PreservedState(); + }; + virtual std::unique_ptr withPreservedState() const { + return std::make_unique(); + } + private: virtual bool matchesArch(Triple::ArchType Arch) const = 0; diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Target.cpp @@ -147,6 +147,8 @@ return *Found->PCI; } +ExegesisTarget::PreservedState::~PreservedState() {} // anchor. + namespace { // Default implementation. diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace llvm { namespace exegesis { @@ -594,6 +595,27 @@ namespace { +class X86PreservedState : public ExegesisTarget::PreservedState { + public: + X86PreservedState() { + _fxsave64(FPState); + } + + ~X86PreservedState() { + // Restoring the X87 state does not flush pending exceptions, make sure + // these exceptions are flushed now. +#if defined(_MSC_VER) + _clearfp(); +#elif defined(__GNUC__) + asm volatile("fwait"); +#endif + _fxrstor64(FPState); + } + + private: + alignas(16) char FPState[512]; +}; + class ExegesisX86Target : public ExegesisTarget { public: ExegesisX86Target() : ExegesisTarget(X86CpuPfmCounters) {} @@ -691,6 +713,10 @@ #endif } + std::unique_ptr withPreservedState() const override { + return std::make_unique(); + } + static const unsigned kUnavailableRegisters[4]; };