forked from OSchip/llvm-project
[lldb] [test/Register] Add read/write tests for x87 regs
Add a partial read/write tests for x87 FPU registers. This includes reading and writing ST registers, control registers and floating-point exception data registers (fop, fip, fdp). The tests assume the current (roughly incorrect) behavior of reporting the 'abridged' 8-bit ftag state as 16-bit ftag. They also assume Linux plugin behavior of reporting fip/fdp split into halves as (fiseg, fioff) and (foseg, fooff). Differential Revision: https://reviews.llvm.org/D88583
This commit is contained in:
parent
9821632056
commit
381bdc75ee
|
@ -0,0 +1,45 @@
|
|||
#include <cstdint>
|
||||
|
||||
struct alignas(16) float80_raw {
|
||||
uint64_t mantissa;
|
||||
uint16_t sign_exp;
|
||||
};
|
||||
|
||||
int main() {
|
||||
float80_raw st[] = {
|
||||
{0x8000000000000000, 0x4000}, // +2.0
|
||||
{0x3f00000000000000, 0x0000}, // 1.654785e-4932 (denormal)
|
||||
{0x0000000000000000, 0x0000}, // +0
|
||||
{0x0000000000000000, 0x8000}, // -0
|
||||
{0x8000000000000000, 0x7fff}, // +inf
|
||||
{0x8000000000000000, 0xffff}, // -inf
|
||||
{0xc000000000000000, 0xffff}, // nan
|
||||
// leave st7 empty to test tag word better
|
||||
};
|
||||
|
||||
// unmask divide-by-zero exception
|
||||
uint16_t cw = 0x037b;
|
||||
// used as single-precision float
|
||||
uint32_t zero = 0;
|
||||
|
||||
asm volatile(
|
||||
"finit\n\t"
|
||||
"fldcw %1\n\t"
|
||||
// load on stack in reverse order to make the result easier to read
|
||||
"fldt 0x60(%0)\n\t"
|
||||
"fldt 0x50(%0)\n\t"
|
||||
"fldt 0x40(%0)\n\t"
|
||||
"fldt 0x30(%0)\n\t"
|
||||
"fldt 0x20(%0)\n\t"
|
||||
"fldt 0x10(%0)\n\t"
|
||||
"fldt 0x00(%0)\n\t"
|
||||
// this should trigger a divide-by-zero
|
||||
"fdivs (%2)\n\t"
|
||||
"int3\n\t"
|
||||
:
|
||||
: "a"(st), "m"(cw), "b"(&zero)
|
||||
: "st"
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
struct alignas(16) float80_raw {
|
||||
uint8_t data[10];
|
||||
};
|
||||
|
||||
int main() {
|
||||
float80_raw st[8];
|
||||
uint16_t env[14];
|
||||
union alignas(16) {
|
||||
uint16_t i16[256];
|
||||
uint32_t i32[128];
|
||||
uint64_t i64[64];
|
||||
} fxsave;
|
||||
|
||||
asm volatile(
|
||||
"finit\n\t"
|
||||
"int3\n\t"
|
||||
#if defined(__x86_64__)
|
||||
"fxsave64 %2\n\t"
|
||||
#else
|
||||
"fxsave %2\n\t"
|
||||
#endif
|
||||
"fnstenv %1\n\t"
|
||||
"fnclex\n\t"
|
||||
"fstpt 0x00(%0)\n\t"
|
||||
"fstpt 0x10(%0)\n\t"
|
||||
"fstpt 0x20(%0)\n\t"
|
||||
"fstpt 0x30(%0)\n\t"
|
||||
"fstpt 0x40(%0)\n\t"
|
||||
"fstpt 0x50(%0)\n\t"
|
||||
"fstpt 0x60(%0)\n\t"
|
||||
"fstpt 0x70(%0)\n\t"
|
||||
:
|
||||
: "a"(st), "m"(env), "m"(fxsave)
|
||||
: "st"
|
||||
);
|
||||
|
||||
assert(env[0] == fxsave.i16[0]);
|
||||
assert(env[2] == fxsave.i16[1]);
|
||||
|
||||
printf("fctrl = 0x%04" PRIx16 "\n", env[0]);
|
||||
printf("fstat = 0x%04" PRIx16 "\n", env[2]);
|
||||
printf("ftag = 0x%04" PRIx16 "\n", env[4]);
|
||||
printf("fop = 0x%04" PRIx16 "\n", fxsave.i16[3]);
|
||||
#if defined(__x86_64__)
|
||||
printf("fip = 0x%016" PRIx64 "\n", fxsave.i64[1]);
|
||||
printf("fdp = 0x%016" PRIx64 "\n", fxsave.i64[2]);
|
||||
#else
|
||||
printf("fip = 0x%08" PRIx32 "\n", fxsave.i32[2]);
|
||||
printf("fcs = 0x%04" PRIx16 "\n", fxsave.i16[6]);
|
||||
printf("fdp = 0x%08" PRIx32 "\n", fxsave.i32[4]);
|
||||
printf("fds = 0x%04" PRIx16 "\n", fxsave.i16[10]);
|
||||
#endif
|
||||
printf("mxcsr = 0x%08" PRIx32 "\n", fxsave.i32[6]);
|
||||
printf("mxcsr_mask = 0x%08" PRIx32 "\n", fxsave.i32[7]);
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
printf("st%d = { ", i);
|
||||
for (int j = 0; j < sizeof(st->data); ++j)
|
||||
printf("0x%02" PRIx8 " ", st[i].data[j]);
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
# REQUIRES: native && target-x86_64
|
||||
# RUN: %clangxx_host %p/Inputs/x86-fp-write.cpp -o %t
|
||||
# RUN: %lldb -b -s %s %t | FileCheck %s
|
||||
process launch
|
||||
|
||||
register write fctrl 0x037b
|
||||
register write fstat 0x8884
|
||||
# note: this needs to enable all registers for writes to be effective
|
||||
# TODO: fix it to use proper ftag values instead of 'abridged'
|
||||
register write ftag 0x00ff
|
||||
register write fop 0x0033
|
||||
# the exact addresses do not matter, we want just to verify FXSAVE
|
||||
# note: fxrstor64 apparently truncates this to 48 bits, and sign extends
|
||||
# the highest bits, so let's keep the value safely below
|
||||
register write fiseg 0x00000567
|
||||
register write fioff 0x89abcdef
|
||||
register write foseg 0x00000a98
|
||||
register write fooff 0x76543210
|
||||
|
||||
register write st0 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40}"
|
||||
register write st1 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00}"
|
||||
register write st2 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
|
||||
register write st3 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80}"
|
||||
register write st4 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f}"
|
||||
register write st5 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff}"
|
||||
register write st6 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff}"
|
||||
register write st7 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
|
||||
|
||||
process continue
|
||||
|
||||
# CHECK: process continue
|
||||
# CHECK-DAG: fctrl = 0x037b
|
||||
# CHECK-DAG: fstat = 0x8884
|
||||
# CHECK-DAG: ftag = 0xa961
|
||||
# CHECK-DAG: fop = 0x0033
|
||||
# CHECK-DAG: fip = 0x0000056789abcdef
|
||||
# CHECK-DAG: fdp = 0x00000a9876543210
|
||||
|
||||
# CHECK-DAG: st0 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40 }
|
||||
# CHECK-DAG: st1 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00 }
|
||||
# CHECK-DAG: st2 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 }
|
||||
# CHECK-DAG: st3 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 }
|
||||
# CHECK-DAG: st4 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f }
|
||||
# CHECK-DAG: st5 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff }
|
||||
# CHECK-DAG: st6 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff }
|
||||
# CHECK-DAG: st7 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 }
|
||||
|
||||
# CHECK: Process {{[0-9]+}} exited with status = 0
|
|
@ -0,0 +1,36 @@
|
|||
# REQUIRES: native && (target-x86 || target-x86_64)
|
||||
# RUN: %clangxx_host -g %p/Inputs/x86-fp-read.cpp -o %t
|
||||
# RUN: %lldb -b -s %s %t | FileCheck %s
|
||||
process launch
|
||||
# CHECK: Process {{.*}} stopped
|
||||
|
||||
register read --all
|
||||
# CHECK-DAG: fctrl = 0x037b
|
||||
# CHECK-DAG: fstat = 0x8884
|
||||
# TODO: the following value is incorrect, it's a bug in the way
|
||||
# FXSAVE/XSAVE is interpreted; it should be 0xa963 once fixed
|
||||
# CHECK-DAG: ftag = 0x00fe
|
||||
# CHECK-DAG: fop = 0x0033
|
||||
|
||||
# CHECK-DAG: st0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40}
|
||||
# CHECK-DAG: st1 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00}
|
||||
# CHECK-DAG: st2 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
|
||||
# CHECK-DAG: st3 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80}
|
||||
# CHECK-DAG: st4 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f}
|
||||
# CHECK-DAG: st5 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff}
|
||||
# CHECK-DAG: st6 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff}
|
||||
# CHECK-DAG: st7 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
|
||||
|
||||
# fdiv (%rbx) gets encoded into 2 bytes, int3 into 1 byte
|
||||
print (void*)($pc-3)
|
||||
# CHECK: (void *) $0 = [[FDIV:0x[0-9a-f]*]]
|
||||
# TODO: we probably should not split it like this
|
||||
print (void*)($fiseg*0x100000000 + $fioff)
|
||||
# CHECK: (void *) $1 = [[FDIV]]
|
||||
print &zero
|
||||
# CHECK: (uint32_t *) $2 = [[ZERO:0x[0-9a-f]*]]
|
||||
print (uint32_t*)($foseg * 0x100000000 + $fooff)
|
||||
# CHECK: (uint32_t *) $3 = [[ZERO]]
|
||||
|
||||
process continue
|
||||
# CHECK: Process {{[0-9]+}} exited with status = 0
|
|
@ -0,0 +1,45 @@
|
|||
# REQUIRES: native && target-x86
|
||||
# RUN: %clangxx_host %p/Inputs/x86-fp-write.cpp -o %t
|
||||
# RUN: %lldb -b -s %s %t | FileCheck %s
|
||||
process launch
|
||||
|
||||
register write fctrl 0x037b
|
||||
register write fstat 0x8884
|
||||
# note: this needs to enable all registers for writes to be effective
|
||||
# TODO: fix it to use proper ftag values instead of 'abridged'
|
||||
register write ftag 0x00ff
|
||||
register write fop 0x0033
|
||||
# the exact addresses do not matter, we want just to verify FXSAVE
|
||||
# note: segment registers are not supported on all CPUs
|
||||
register write fioff 0x89abcdef
|
||||
register write fooff 0x76543210
|
||||
|
||||
register write st0 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40}"
|
||||
register write st1 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00}"
|
||||
register write st2 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
|
||||
register write st3 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80}"
|
||||
register write st4 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f}"
|
||||
register write st5 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff}"
|
||||
register write st6 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff}"
|
||||
register write st7 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}"
|
||||
|
||||
process continue
|
||||
|
||||
# CHECK: process continue
|
||||
# CHECK-DAG: fctrl = 0x037b
|
||||
# CHECK-DAG: fstat = 0x8884
|
||||
# CHECK-DAG: ftag = 0xa961
|
||||
# CHECK-DAG: fop = 0x0033
|
||||
# CHECK-DAG: fip = 0x89abcdef
|
||||
# CHECK-DAG: fdp = 0x76543210
|
||||
|
||||
# CHECK-DAG: st0 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40 }
|
||||
# CHECK-DAG: st1 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00 }
|
||||
# CHECK-DAG: st2 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 }
|
||||
# CHECK-DAG: st3 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 }
|
||||
# CHECK-DAG: st4 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f }
|
||||
# CHECK-DAG: st5 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff }
|
||||
# CHECK-DAG: st6 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff }
|
||||
# CHECK-DAG: st7 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 }
|
||||
|
||||
# CHECK: Process {{[0-9]+}} exited with status = 0
|
Loading…
Reference in New Issue