i386_record_lea_modrm (ir);
}
break;
- case 0x14: /* VUNPCKL[PS|PD]. */
- case 0x15: /* VUNPCKH [PS|PD]. */
- i386_record_modrm (ir);
- record_full_arch_list_add_reg (ir->regcache,
- tdep->ymm0_regnum + ir->reg + vex_r * 8);
- break;
case 0x6e: /* VMOVD XMM, reg/mem */
/* This is moving from a regular register or memory region into an
XMM register. */
}
break;
- case 0x19: /* VBROADCASTSD. */
+ case 0x17: /* VEXTRACTPS. */
i386_record_modrm (ir);
record_full_arch_list_add_reg (ir->regcache,
- tdep->ymm0_regnum + ir->reg
- + 8 * vex_r);
+ ir->regmap[X86_RECORD_REAX_REGNUM
+ + ir->rm]);
+ break;
+
+ case 0x19: /* VBROADCASTSD and VEXTRACTF128. */
+ case 0x39: /* VEXTRACTI128. */
+ i386_record_modrm (ir);
+ /* vextract instructions use ModRM.R/M and VEX.B to address the
+ output register, while vbroadcast use ModRM.Reg and VEX.R.
+ They are differentiated through map_select. */
+ if (ir->map_select == 2)
+ record_full_arch_list_add_reg (ir->regcache,
+ tdep->ymm0_regnum + ir->reg
+ + 8 * vex_r);
+ else
+ record_full_arch_list_add_reg (ir->regcache,
+ tdep->ymm0_regnum + ir->rm
+ + 8 * ir->rex_b);
break;
- case 0x18: /* VBROADCASTSS. */
+ case 0x18: /* VBROADCASTSS and VINSERTI128. */
+ case 0x20: /* VPINSRB. */
+ case 0x21: /* VINSERTPS. */
+ case 0x22: /* VINSR[D|Q]. */
+ case 0x38: /* VINSERTF128. */
case 0x60: /* VPUNPCKLBW */
case 0x61: /* VPUNPCKLWD */
case 0x62: /* VPUNPCKLDQ */
case 0x69: /* VPUNPCKHWD */
case 0x6a: /* VPUNPCKHDQ */
case 0x6d: /* VPUNPCKHQDQ */
+ case 0xc4: /* VPINSRW. */
{
i386_record_modrm (ir);
int reg_offset = ir->reg + vex_r * 8;
}
break;
+ case 0x14: /* VPEXTRB and VUNPCKL[PS|PD]. */
+ case 0x15: /* VPEXTRW (to memory) and VUNPCKH [PS|PD]. */
+ case 0x16: /* VPEXTR[D|Q] and VPERMPS. */
+ {
+ i386_record_modrm (ir);
+ /* All vpextr instructions in this case use map_select == 3,
+ while vpermps and vunpck have map_select equal to 2 and 1,
+ respectively. The opcode 0xc5 is for vpextr, but uses
+ map_select == 1, but due to other inconsistencies with
+ the other vpextr instructions, it is in a separate case to
+ avoid making this even more of a mess. */
+ if (ir->map_select == 3)
+ {
+ if (ir->mod == 3)
+ {
+ /* ModRM.Mod being equal to 3 means this ModRM encodes
+ a register. */
+ record_full_arch_list_add_reg (ir->regcache,
+ ir->regmap[X86_RECORD_REAX_REGNUM
+ + ir->rm]);
+ }
+ else
+ {
+ /* Even though the test only generated ModRM.Mod == 0,
+ in theory all values != 3 are viable to encode a memory
+ address, so all of them are passed along. */
+ /* Size is mostly based on the opcode, except for
+ double/quadword difference. */
+ ir->ot = opcode - 0x14;
+ if (opcode == 0x16 && vex_w == 1)
+ ir->ot ++;
+ /* I'm not sure if this is the original use, but in here
+ rip_offset is used to indicate that the RIP pointer will
+ be 1 byte away from where the instruction expects it to
+ be, because the immediate will not have been read by the
+ time the address changed is calculated. */
+ ir->rip_offset = 1;
+ i386_record_lea_modrm (ir);
+ }
+ }
+ else
+ {
+ record_full_arch_list_add_reg (ir->regcache,
+ tdep->ymm0_regnum + ir->reg
+ + vex_r * 8);
+ }
+ break;
+ }
+ case 0xc5: /* VPEXTRW to register. */
+ i386_record_modrm (ir);
+ record_full_arch_list_add_reg (ir->regcache,
+ ir->regmap[X86_RECORD_REAX_REGNUM
+ + ir->reg]);
+ break;
+
case 0x74: /* VPCMPEQB */
case 0x75: /* VPCMPEQB */
case 0x76: /* VPCMPEQB */
case 0x06: /* VMPERM2F128. */
case 0x0c: /* VPERMILPS with register. */
case 0x0d: /* VPERMILPD with register. */
- case 0x16: /* VPERMPS. */
case 0x1a: /* VBROADCASTF128. */
case 0x36: /* VPERMD. */
case 0x40: /* VPMULLD */
return 0; /* end permute_test */
}
+int
+extract_insert_test ()
+{
+ /* start extract_insert_test. */
+ /* Using GDB, load these values onto registers for testing.
+ ymm0.v2_int128 = {0, 0}
+ ymm1.v16_int16 = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}
+ xmm2.uint128 = 0xcafe
+ ymm15.v2_int128 = {0x0, 0x0}
+ eax = 0
+ this way it's easy to confirm we're undoing things correctly. */
+
+ asm volatile ("vinserti128 $1, %xmm2, %ymm1, %ymm0");
+ asm volatile ("vinsertf128 $0, %xmm2, %ymm1, %ymm15");
+ asm volatile ("vextracti128 $1, %ymm1, %xmm0");
+ asm volatile ("vextractf128 $0, %ymm1, %xmm15");
+ asm volatile ("vinsertps $16, %xmm2, %xmm1, %xmm0");
+ asm volatile ("vextractps $0, %xmm2, %rax");
+
+ asm volatile ("vpextrb $5, %xmm1, %rax");
+ asm volatile ("vpextrb $4, %%xmm1, %0" : "=m" (global_buf1));
+ asm volatile ("vpextrd $3, %xmm1, %eax");
+ asm volatile ("vpextrd $2, %%xmm1, %0" : "=m" (global_buf1));
+ asm volatile ("vpextrq $1, %xmm1, %rax");
+ asm volatile ("vpextrq $0, %%xmm1, %0" : "=m" (global_buf1));
+
+ asm volatile ("vpinsrb $3, %rax, %xmm2, %xmm0");
+ asm volatile ("vpinsrw $2, %eax, %xmm2, %xmm15");
+ asm volatile ("vpinsrd $1, %eax, %xmm2, %xmm0");
+ asm volatile ("vpinsrq $0, %rax, %xmm2, %xmm15");
+
+ /* vpextrw has completely different mechanics to other vpextr
+ instructions, so separate them for ease of testing later. */
+ asm volatile ("vpextrw $1, %xmm1, %eax");
+ asm volatile ("vpextrw $1, %%xmm1, %0" : "=m" (global_buf1));
+
+ return 0; /* end extract_insert_test */
+}
+
/* This include is used to allocate the dynamic buffer and have
the pointers aligned to a 32-bit boundary, so we can test instructions
that require aligned memory. */
shift_test ();
shuffle_test ();
permute_test ();
+ extract_insert_test ();
return 0; /* end of main */
}
}
gdb_test "finish" "Run till exit from.*permute_test.*" \
"leaving permute"
+
+# Preparation and testing extract_insert instructions.
+gdb_test_no_output \
+ "set \$ymm0.v2_int128 = {0, 0}" "set ymm0 for extract_insert"
+gdb_test_no_output \
+ "set \$ymm1.v16_int16 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}" \
+ "set ymm1 for extract_insert"
+gdb_test_no_output "set \$xmm2.uint128 = 0xcafe" \
+ "set ymm2 for extract_insert"
+gdb_test_no_output "set \$ymm15.v2_int128 = {0,0}" "set ymm15 for extract_insert"
+gdb_test_no_output "set \$rax = 0" "set eax for extract_insert"
+
+if {[record_full_function "extract_insert"] == true} {
+ test_one_memory "vpextrw" "global_buf1" \
+ "\\\{0x1, 0x0, 0x2, 0x0, 0x3, 0x0, 0x4, 0x0, 0x18"
+ test_one_general_register "vpextrw" "rax" "0x8000700060005"
+
+ test_one_register "vpinsrq" "ymm15" \
+ "0x50000cafe, 0x0"
+ test_one_register "vpinsrd" "ymm0" \
+ "0x500cafe, 0x0"
+ test_one_register "vpinsrw" "ymm15" \
+ "0x80007000600050004000300020001, 0x0"
+ test_one_register "vpinsrb" "ymm0" \
+ "0x80007000600050000cafe00020001, 0x0"
+
+ test_one_memory "vpextrq" "global_buf1" \
+ "\\\{0x5, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18"
+ test_one_general_register "vpextrq" "rax" "0x80007"
+ test_one_memory "vpextrd" "global_buf1" \
+ "\\\{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18"
+ test_one_general_register "vpextrd" "rax" "0x0"
+ test_one_memory "vpextrb" "global_buf1" \
+ "\\\{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18"
+ test_one_general_register "vpextrb" "rax" "0xcafe"
+
+ test_one_general_register "vextractps" "eax" "0x0"
+ test_one_register "vinsertps" "ymm0" \
+ "0x10000f000e000d000c000b000a0009, 0x0"
+ test_one_register "vextractf128" "ymm15" \
+ "0xcafe, 0x10000f000e000d000c000b000a0009"
+ test_one_register "vextracti128" "ymm0" \
+ "0x80007000600050004000300020001, 0xcafe"
+ test_one_register "vinsertf128" "ymm15" \
+ "0x0, 0x0"
+ test_one_register "vinserti128" "ymm0" \
+ "0x0, 0x0"
+
+ gdb_test "record stop" "Process record is stopped.*" \
+ "delete history for extract_insert_test"
+} else {
+ untested "couldn't run extract_insert tests"
+}
+gdb_test "finish" "Run till exit from.*extract_insert_test.*" \
+ "leaving extract_insert"