Made it so that the test cases exercise the instruction with the flags zeroed and with the flags set.

This commit is contained in:
Peter Goodman
2015-12-20 17:47:16 -05:00
parent 5b955b358d
commit 9b3be033a2
6 changed files with 80 additions and 20 deletions
+1 -5
View File
@@ -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)
+2 -2
View File
@@ -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
+14 -2
View File
@@ -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");
+54 -11
View File
@@ -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<uintptr_t>(&gLiftedStack);
static const auto gStackLimit = gStackBase + sizeof(Stack);
@@ -195,12 +198,31 @@ static void CopyXMMRegsIntoFPU(State *state) {
static std::vector<const test::TestInfo *> 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<const test::TestInfo *> {};
TEST_P(InstrTest, SemanticsMatchNative) {
auto info = GetParam();
static void RunWithFlags(const test::TestInfo *info, Flags flags,
const char *desc) {
auto test_name = reinterpret_cast<const char *>(info->test_name);
auto lifted_func = reinterpret_cast<LiftedFunc>(info->lifted_func);
@@ -211,6 +233,10 @@ TEST_P(InstrTest, SemanticsMatchNative) {
auto lifted_state = reinterpret_cast<State *>(&gStateLifted);
auto native_state = reinterpret_cast<State *>(&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];
+8
View File
@@ -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
+1
View File
@@ -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