gdb/record: add support to vzeroupper instruction

This commit adds recording support for the AVX instruction vzeroupper,
which zeroes the high bits of ymm registers 0..15.  In the programmer's
manual, it is explicitly states that ymm registers 16..31 won't be
affected if present, so we only need to record the first 16 registers.

We record ymm_h registers since only the higher bits are touched, and
that reduces the memory footprint of the instruction.

This instruction is tested differently as we want to confirm we're only
saving the relevant registers, and we want to ensure we're saving
all of them, so it makes use of "maint print record-instruction" to see
exactly what was recorded.

Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
Guinevere Larsen 2024-07-28 09:51:11 -03:00
parent 5bf288d5a8
commit 77f6ff4461
3 changed files with 73 additions and 0 deletions

View File

@ -4964,6 +4964,23 @@ i386_record_vex (struct i386_record_s *ir, uint8_t vex_w, uint8_t vex_r,
}
break;
case 0x77:/* VZEROUPPER */
{
int num_regs = tdep->num_ymm_regs;
/* This instruction only works on ymm0..15, even if 16..31 are
available. */
if (num_regs > 16)
num_regs = 16;
for (int i = 0; i < num_regs; i++)
{
/* We only need to record ymm_h, because the low bits
are not touched. */
record_full_arch_list_add_reg (ir->regcache,
tdep->ymm0h_regnum + i);
}
break;
}
default:
gdb_printf (gdb_stderr,
_("Process record does not support VEX instruction 0x%02x "

View File

@ -192,6 +192,24 @@ vpbroadcast_test ()
return 0; /* end vpbroadcast_test */
}
int
vzeroupper_test ()
{
/* start vzeroupper_test. */
/* Using GDB, load this value onto the register, for ease of testing.
ymm0.v2_int128 = {0x0, 0x12345}
ymm1.v2_int128 = {0x1f1e1d1c1b1a1918, 0x0}
ymm2.v2_int128 = {0x0, 0xbeef}
ymm15.v2_int128 = {0x0, 0xcafeface}
this way it's easy to confirm we're undoing things correctly. */
asm volatile ("vzeroupper");
/* We have a return statement to deal with
epilogue in different compilers. */
return 0; /* end vzeroupper_test */
}
int
main ()
{
@ -211,5 +229,6 @@ main ()
vmov_test ();
vpunpck_test ();
vpbroadcast_test ();
vzeroupper_test ();
return 0; /* end of main */
}

View File

@ -294,3 +294,40 @@ if {[record_full_function "vpbroadcast"] == true} {
gdb_test "finish" "Run till exit from.*vpbroadcast_test.*" \
"leaving vpbroadcast"
# Preparation and testing of vzeroupper
gdb_test_no_output "set \$ymm0.v2_int128 = {0x0, 0x12345}" "set ymm0 for vzeroupper"
gdb_test_no_output "set \$ymm1.v2_int128 = {0x1f1e1d1c1b1a1918, 0x0}" \
"set ymm1 for vzeroupper"
gdb_test_no_output "set \$ymm2.v2_int128 = {0x0, 0xbeef}" "set ymm2 for vzeroupper"
gdb_test_no_output "set \$ymm15.v2_int128 = {0x0, 0xcafeface}" "set ymm15 for vpbroadcast"
if {[record_full_function "vzeroupper"] == true} {
# Since vzeroupper needs to save 8 or 16 registers, let's check what was
# actually recorded, instead of just undoing an instruction. Only
# really check the values of egisters 0, 1, 2 and 15 because those are
# the only ones we're setting.
gdb_test "maint print record-instruction" \
[multi_line "Register ymm0h changed: 74565" \
"Register ymm1h changed: 0" \
"Register ymm2h changed: 48879" \
"Register ymm3h changed: ${decimal}" \
"Register ymm4h changed: ${decimal}" \
"Register ymm5h changed: ${decimal}" \
"Register ymm6h changed: ${decimal}" \
"Register ymm7h changed: ${decimal}" \
"Register ymm8h changed: ${decimal}" \
"Register ymm9h changed: ${decimal}" \
"Register ymm10h changed: ${decimal}" \
"Register ymm11h changed: ${decimal}" \
"Register ymm12h changed: ${decimal}" \
"Register ymm13h changed: ${decimal}" \
"Register ymm14h changed: ${decimal}" \
"Register ymm15h changed: 3405707982" \
"Register rip changed: \[^\r\n\]+" ] \
"verify vzeroupper recording"
} else {
untested "couldn't run vzeroupper tests"
}
gdb_test "finish" "Run till exit from.*vzeroupper_test.*" \
"leaving vzeroupper"