From 9b3be033a29d90ed499f2b1101fa3dfe032c23ee Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Sun, 20 Dec 2015 17:47:16 -0500 Subject: [PATCH] Made it so that the test cases exercise the instruction with the flags zeroed and with the flags set. --- CMakeLists.txt | 6 +--- scripts/optimize_bitcode.sh | 4 +-- tests/X86/PrintSaveState.cpp | 16 +++++++-- tests/X86/Run.cpp | 65 ++++++++++++++++++++++++++++++------ tests/X86/SaveState.S | 8 +++++ tests/X86/Tests.S | 1 + 6 files changed, 80 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15d2d988..89bf7969 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,11 +10,7 @@ set(CMAKE_CXX_COMPILER "${MCSEMA_DIR}/third_party/bin/clang++") set(CMAKE_ASM_COMPILER "${MCSEMA_DIR}/third_party/bin/clang") # Find LLVM. -set(LLVM_INSTALL_PREFIX "${MCSEMA_DIR}/third_party") -set(LLVM_CMAKE_DIR "${LLVM_INSTALL_PREFIX}/share/llvm/cmake") -set(LLVM_LIBRARY_DIR "${LLVM_INSTALL_PREFIX}/lib") -list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") -#find_package(LLVM 3.7.0 EXACT REQUIRED Config) +list(INSERT CMAKE_MODULE_PATH 0 "${MCSEMA_DIR}/third_party/share/llvm/cmake") include(LLVMConfig) include(AddLLVM) diff --git a/scripts/optimize_bitcode.sh b/scripts/optimize_bitcode.sh index e2a39b5f..56ebcea5 100755 --- a/scripts/optimize_bitcode.sh +++ b/scripts/optimize_bitcode.sh @@ -35,7 +35,7 @@ $DIR/third_party/bin/opt -O3 -o=$1.opt2.bc $1.opt1.bc || { } mv $1.opt2.bc $2 -rm $1.opt1.bc -rm $1.opt0.bc +#rm $1.opt1.bc +#rm $1.opt0.bc exit 0 diff --git a/tests/X86/PrintSaveState.cpp b/tests/X86/PrintSaveState.cpp index 0ab9d647..a8979b75 100644 --- a/tests/X86/PrintSaveState.cpp +++ b/tests/X86/PrintSaveState.cpp @@ -34,7 +34,14 @@ int main(void) { // clobbered by the `PUSHFQ`. printf("lea RSP, [RSP - 8]\n"); printf("pop QWORD PTR [RIP + SYMBOL(gStackSaveSlot)]\n"); + + // Before the testcase this will initialize the flags, and after the test + // case this will record the flags. + printf("#ifdef AFTER_TEST_CASE\n"); printf("pushfq\n"); + printf("#else\n"); + printf("push QWORD PTR [RIP + STATE_PTR + %lu]\n", offsetof(State, rflag)); + printf("#endif\n"); printf("bt QWORD PTR [RSP], 0\n"); printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.cf)); @@ -57,9 +64,14 @@ int main(void) { printf("bt QWORD PTR [RSP], 11\n"); printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.of)); - // Restore the flags, then restore whatever was previously clobbered by - // `PUSHFQ`. + // Before the native test case this will set the flags from `gFlags`, but + // after the test case this will safe the flags to the `rflag` field. + printf("#ifdef AFTER_TEST_CASE\n"); + printf("pop QWORD PTR [RIP + STATE_PTR + %lu]\n", offsetof(State, rflag)); + printf("#else\n"); printf("popfq\n"); + printf("#endif\n"); + printf("push QWORD PTR [RIP + SYMBOL(gStackSaveSlot)]\n"); printf("lea RSP, [RSP + 8]\n"); diff --git a/tests/X86/Run.cpp b/tests/X86/Run.cpp index 91bce944..d90b6a6b 100644 --- a/tests/X86/Run.cpp +++ b/tests/X86/Run.cpp @@ -28,6 +28,9 @@ struct alignas(128) Stack { static Stack gLiftedStack; static Stack gNativeStack; +static Flags gRflagsOff; +static Flags gRflagsOn; + static const auto gStackBase = reinterpret_cast(&gLiftedStack); static const auto gStackLimit = gStackBase + sizeof(Stack); @@ -195,12 +198,31 @@ static void CopyXMMRegsIntoFPU(State *state) { static std::vector gTests; +static void InitFlags(void) { + asm("pushfq; pushfq; pop %0; pop %1;" : : "m"(gRflagsOn), "m"(gRflagsOff)); + gRflagsOn.cf = true; + gRflagsOn.pf = true; + gRflagsOn.af = true; + gRflagsOn.zf = true; + gRflagsOn.sf = true; + gRflagsOn.df = true; + gRflagsOn.of = true; + + gRflagsOff.cf = false; + gRflagsOff.pf = false; + gRflagsOff.af = false; + gRflagsOff.zf = false; + gRflagsOff.sf = false; + gRflagsOff.df = false; + gRflagsOff.of = false; +} + } // namespace class InstrTest : public ::testing::TestWithParam {}; -TEST_P(InstrTest, SemanticsMatchNative) { - auto info = GetParam(); +static void RunWithFlags(const test::TestInfo *info, Flags flags, + const char *desc) { auto test_name = reinterpret_cast(info->test_name); auto lifted_func = reinterpret_cast(info->lifted_func); @@ -211,6 +233,10 @@ TEST_P(InstrTest, SemanticsMatchNative) { auto lifted_state = reinterpret_cast(&gStateLifted); auto native_state = reinterpret_cast(&gStateNative); + // This will be used to initialize the native flags state before executing + // the native test. + lifted_state->rflag = flags; + // This will execute on `gStack`. The mechanism behind this is that the // stack pointer is swapped with `gStackSwitcher`. The idea here is that // we want to run the native and lifted testcases on the same stack so that @@ -241,16 +267,24 @@ TEST_P(InstrTest, SemanticsMatchNative) { CopyXMMRegsIntoFPU(lifted_state); - std::cerr << "Testing instruction: " << test_name << std::endl; - std::cerr << "Instruction features:"; - if (test::kFeatureMMX & info->features) std::cerr << " MMX"; - if (test::kFeatureSSE & info->features) std::cerr << " SSE"; - if (test::kFeatureAVX & info->features) std::cerr << " AVX"; - if (test::kFeatureAVX512 & info->features) std::cerr << " AVX512"; - if (test::kFeature64BitOnly & info->features) std::cerr << " (64-bit only)"; - if (test::kFeature32BitOnly & info->features) std::cerr << " (32-bit only)"; + // Copy the aflags state back into the rflags state. + lifted_state->rflag.cf = lifted_state->aflag.cf; + lifted_state->rflag.pf = lifted_state->aflag.pf; + lifted_state->rflag.af = lifted_state->aflag.af; + lifted_state->rflag.zf = lifted_state->aflag.zf; + lifted_state->rflag.sf = lifted_state->aflag.sf; + lifted_state->rflag.df = lifted_state->aflag.df; + lifted_state->rflag.of = lifted_state->aflag.of; + + std::cerr << "Testing instruction: " << test_name << ": " << desc; + if (test::kFeatureMMX & info->features) std::cerr << ", MMX"; + if (test::kFeatureSSE & info->features) std::cerr << ", SSE"; + if (test::kFeatureAVX & info->features) std::cerr << ", AVX"; + if (test::kFeatureAVX512 & info->features) std::cerr << ", AVX512"; + if (test::kFeature64BitOnly & info->features) std::cerr << ", 64-bit only"; + if (test::kFeature32BitOnly & info->features) std::cerr << ", 32-bit only"; if (!((test::kFeature32BitOnly | test::kFeature64BitOnly) & info->features)) { - std::cerr << " (32-bit, 64-bit compat)"; + std::cerr << " 32-bit (64-bit compat"; } std::cerr << std::endl; @@ -259,6 +293,13 @@ TEST_P(InstrTest, SemanticsMatchNative) { EXPECT_TRUE(!memcmp(&gLiftedStack, &gNativeStack, sizeof(Stack))); } + +TEST_P(InstrTest, SemanticsMatchNative) { + auto info = GetParam(); + RunWithFlags(info, gRflagsOn, "aflags on"); + RunWithFlags(info, gRflagsOff, "aflags off"); +} + INSTANTIATE_TEST_CASE_P( GeneralInstrTest, InstrTest, @@ -266,6 +307,8 @@ INSTANTIATE_TEST_CASE_P( int main(int argc, char **argv) { + InitFlags(); + // Populate the tests vector. for (auto i = 0U; ; ++i) { const auto &test = test::__x86_test_table_begin[i]; diff --git a/tests/X86/SaveState.S b/tests/X86/SaveState.S index d749e3f8..c3f13955 100644 --- a/tests/X86/SaveState.S +++ b/tests/X86/SaveState.S @@ -7,7 +7,11 @@ fxsave [RIP + STATE_PTR + 0] #endif lea RSP, [RSP - 8] pop QWORD PTR [RIP + SYMBOL(gStackSaveSlot)] +#ifdef AFTER_TEST_CASE pushfq +#else +push QWORD PTR [RIP + STATE_PTR + 2568] +#endif bt QWORD PTR [RSP], 0 adc BYTE PTR [RIP + STATE_PTR + 2560], 0 bt QWORD PTR [RSP], 2 @@ -22,7 +26,11 @@ bt QWORD PTR [RSP], 10 adc BYTE PTR [RIP + STATE_PTR + 2565], 0 bt QWORD PTR [RSP], 11 adc BYTE PTR [RIP + STATE_PTR + 2566], 0 +#ifdef AFTER_TEST_CASE +pop QWORD PTR [RIP + STATE_PTR + 2568] +#else popfq +#endif push QWORD PTR [RIP + SYMBOL(gStackSaveSlot)] lea RSP, [RSP + 8] mov [RIP + STATE_PTR + 2593], AH diff --git a/tests/X86/Tests.S b/tests/X86/Tests.S index 3d432dfb..78079272 100644 --- a/tests/X86/Tests.S +++ b/tests/X86/Tests.S @@ -197,6 +197,7 @@ SYMBOL(InvokeTestCase): SYMBOL(__x86_save_state_after): .cfi_startproc # define STATE_PTR SYMBOL(gStateNative) +# define AFTER_TEST_CASE # include "tests/X86/SaveState.S" xchg rsp, [RIP + SYMBOL(gStackSwitcher)] /* Return to the normal stack. */ ret