You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
1
|
2
|
3
|
4
(3) |
5
(1) |
6
|
|
7
|
8
(10) |
9
(5) |
10
(1) |
11
(2) |
12
|
13
|
|
14
|
15
(3) |
16
|
17
|
18
(6) |
19
|
20
|
|
21
|
22
(3) |
23
|
24
|
25
(2) |
26
|
27
|
|
28
|
29
|
30
|
|
|
|
|
|
From: Carl L. <ce...@us...> - 2020-06-18 23:19:05
|
Julian:
FYI, looks like the second and fourth patches exceeded the mail limit
of 100KB. The patches are waiting for a moderator review to release
them to the mailing list. We will have to watch the size a bit more
carefully in the future. Sorry about that.
Carl Love
>
|
|
From: Carl L. <ce...@us...> - 2020-06-18 19:42:20
|
Julian:
The following patch adds the testsuite support for the instructions
added in patch 3. It includes a lot of the underlying support that
will be used in future patches to test the instructions that will be
added later.
Please let me know if you have comments. Thanks.
Carl
------------------------------------------------
Initial ISA 3.1 instruction tests
Add base ISA 3.1 test support for the prefix version of
the addi and load and store instructions.
---
VEX/priv/main_main.c | 2 +-
configure.ac | 22 +-
none/tests/ppc64/Makefile.am | 16 +-
none/tests/ppc64/isa_3_1_helpers.h | 2274 +++++++++++++++++++
none/tests/ppc64/isa_3_1_register_defines.h | 55 +
none/tests/ppc64/test_isa_3_1_RT.c | 516 +++++
none/tests/ppc64/test_isa_3_1_RT.stdout.exp | 148 ++
none/tests/ppc64/test_isa_3_1_RT.vgtest | 2 +
none/tests/ppc64/test_isa_3_1_XT.c | 488 ++++
none/tests/ppc64/test_isa_3_1_XT.stdout.exp | 119 +
none/tests/ppc64/test_isa_3_1_XT.vgtest | 2 +
tests/check_ppc64_auxv_cap | 4 +-
12 files changed, 3644 insertions(+), 4 deletions(-)
create mode 100644 none/tests/ppc64/isa_3_1_helpers.h
create mode 100644 none/tests/ppc64/isa_3_1_register_defines.h
create mode 100644 none/tests/ppc64/test_isa_3_1_RT.c
create mode 100644 none/tests/ppc64/test_isa_3_1_RT.stdout.exp
create mode 100644 none/tests/ppc64/test_isa_3_1_RT.vgtest
create mode 100644 none/tests/ppc64/test_isa_3_1_XT.c
create mode 100644 none/tests/ppc64/test_isa_3_1_XT.stdout.exp
create mode 100644 none/tests/ppc64/test_isa_3_1_XT.vgtest
diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c
index a8fb14eb0..568d2659d 100644
--- a/VEX/priv/main_main.c
+++ b/VEX/priv/main_main.c
@@ -1683,7 +1683,7 @@ static const HChar* show_hwcaps_ppc32 ( UInt hwcaps )
{ VEX_HWCAPS_PPC32_DFP, "DFP" },
{ VEX_HWCAPS_PPC32_ISA2_07, "ISA2_07" },
{ VEX_HWCAPS_PPC32_ISA3_0, "ISA3_0" },
- { VEX_HWCAPS_PPC32_ISA3_1, "ISA3_1" },
+ /* ISA 3.1 is not supported in 32-bit mode */
};
/* Allocate a large enough buffer */
static HChar buf[sizeof prefix +
diff --git a/configure.ac b/configure.ac
index 49f2ba83d..1e50c575e 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1455,7 +1455,9 @@ AC_HWCAP_CONTAINS_FLAG([arch_2_05],[HWCAP_HAS_ISA_2_05])
AC_HWCAP_CONTAINS_FLAG([arch_2_06],[HWCAP_HAS_ISA_2_06])
AC_HWCAP_CONTAINS_FLAG([arch_2_07],[HWCAP_HAS_ISA_2_07])
AC_HWCAP_CONTAINS_FLAG([arch_3_00],[HWCAP_HAS_ISA_3_00])
+AC_HWCAP_CONTAINS_FLAG([arch_3_01],[HWCAP_HAS_ISA_3_1])
AC_HWCAP_CONTAINS_FLAG([htm],[HWCAP_HAS_HTM])
+AC_HWCAP_CONTAINS_FLAG([mma],[HWCAP_HAS_MMA])
# ISA Levels
AM_CONDITIONAL(HAS_ISA_2_05, [test x$HWCAP_HAS_ISA_2_05 = xyes])
@@ -1624,7 +1626,7 @@ AM_CONDITIONAL(SUPPORTS_HTM, test x$ac_compiler_supports_htm = xyes \
-a x$ac_compiler_sees_htm_builtins = xyes \
-a x$HWCAP_HAS_HTM = xyes )
-# isa 3.0 checking
+# isa 3.0 checking. (actually 3.0 or newer)
AC_MSG_CHECKING([that assembler knows ISA 3.00 ])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@@ -1638,9 +1640,27 @@ ac_asm_have_isa_3_00=no
AC_MSG_RESULT([no])
])
+# isa 3.01 checking
+AC_MSG_CHECKING([that assembler knows ISA 3.1 ])
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+]], [[
+ __asm__ __volatile__("brh 1,2 ");
+]])], [
+ac_asm_have_isa_3_1=yes
+AC_MSG_RESULT([yes])
+], [
+ac_asm_have_isa_3_1=no
+AC_MSG_RESULT([no])
+])
+
+
AM_CONDITIONAL(HAS_ISA_3_00, [test x$ac_asm_have_isa_3_00 = xyes \
-a x$HWCAP_HAS_ISA_3_00 = xyes])
+AM_CONDITIONAL(HAS_ISA_3_1, [test x$ac_asm_have_isa_3_1 = xyes \
+ -a x$HWCAP_HAS_ISA_3_1 = xyes])
+
# Check for pthread_create@GLIBC2.0
AC_MSG_CHECKING([for pthread_create@GLIBC2.0()])
diff --git a/none/tests/ppc64/Makefile.am b/none/tests/ppc64/Makefile.am
index 9bc0d0a76..106ff7276 100644
--- a/none/tests/ppc64/Makefile.am
+++ b/none/tests/ppc64/Makefile.am
@@ -50,7 +50,9 @@ EXTRA_DIST = \
test_isa_3_0_other.stderr.exp \
test_isa_3_0_other.stdout.exp-LE test_isa_3_0_other.vgtest \
subnormal_test.stderr.exp subnormal_test.stdout.exp \
- subnormal_test.vgtest
+ subnormal_test.vgtest \
+ test_isa_3_1_RT.stdout.exp test_isa_3_1_XT.stdout.exp \
+ test_isa_3_1_RT.vgtest test_isa_3_1_XT.vgtest
check_PROGRAMS = \
allexec \
@@ -60,6 +62,7 @@ check_PROGRAMS = \
test_isa_2_07_part1 test_isa_2_07_part2 \
test_isa_3_0 \
subnormal_test \
+ test_isa_3_1_RT test_isa_3_1_XT \
test_tm test_touch_tm ldst_multiple data-cache-instructions \
power6_mf_gpr std_reg_imm \
twi_tdi tw_td power6_bcmp
@@ -128,6 +131,14 @@ BUILD_FLAGS_ISA_3_00 =
ISA_3_00_FLAG =
endif
+if HAS_ISA_3_1
+BUILD_FLAGS_ISA_3_1 = -mcpu=future
+ISA_3_1_FLAG = -DHAS_ISA_3_1
+else
+BUILD_FLAGS_ISA_3_1 =
+ISA_3_1_FLAG =
+endif
+
test_isa_2_06_part1_CFLAGS = $(AM_CFLAGS) -Winline -Wall -O -g -mregnames $(VSX_FLAG) \
@FLAG_M64@ $(ALTIVEC_FLAG) $(BUILD_FLAG_VSX)
@@ -161,6 +172,9 @@ test_touch_tm_CFLAGS = $(AM_CFLAGS) -Winline -Wall -O -g -mregnames $(HTM_FLAG)
test_isa_3_0_CFLAGS = $(AM_CFLAGS) -Winline -Wall -O -g -mregnames $(HTM_FLAG) $(ISA_3_00_FLAG) \
@FLAG_M64@ $(BUILD_FLAGS_ISA_3_00)
+test_isa_3_1_CFLAGS = $(AM_CFLAGS) -Winline -Wall -O -g -mregnames $(ISA_3_1_FLAG) \
+ @FLAG_M64@ $(BUILD_FLAGS_ISA_3_1)
+
subnormal_test_CFLAGS = $(AM_CFLAGS) -Winline -Wall -O -g -mregnames $(VSX_FLAG) $(ISA_2_06_FLAG) \
@FLAG_M64@ $(ALTIVEC_FLAG) $(BUILD_FLAG_VSX) $(BUILD_FLAGS_ISA_2_06)
diff --git a/none/tests/ppc64/isa_3_1_helpers.h b/none/tests/ppc64/isa_3_1_helpers.h
new file mode 100644
index 000000000..d6f2f9878
--- /dev/null
+++ b/none/tests/ppc64/isa_3_1_helpers.h
@@ -0,0 +1,2274 @@
+
+/* Temporarily set the ISA_3_1 indicator. This should be
+ set for the platform via the configuration steps. */
+#define HAS_ISA_3_1
+
+#include <stdbool.h>
+
+#include "isa_3_1_register_defines.h"
+
+/* dcmx is a bit field of size 7. */
+unsigned long dcmx;
+#define dcmx_iters 7;
+
+vector unsigned long long vec_xa;
+vector unsigned long long vec_xb;
+vector unsigned long long vec_xc;
+vector unsigned long long vec_xs;
+vector unsigned long long vec_xt;
+
+/* Iterator controls.
+ These are adjusted as appropriate for the tests
+ being exercised. See set_up_iterators() below. */
+unsigned long a_iters, b_iters, c_iters, m_iters;
+unsigned long a_inc, b_inc, c_inc, m_inc;
+unsigned long vrai, vrbi, vrci, vrmi;
+unsigned long a_limit=0xffff,b_limit=0xffff,c_limit=0xffff;
+
+static vector unsigned long long vrt, vra, vrb, vrc;
+vector unsigned long long vrm;
+
+/* Debug: Set these to allow skipping of test subsets that
+ have nonzero vrm or mc values. */
+unsigned long prefix_override=0;
+unsigned long vrm_override=0;
+unsigned long mc_override=0;
+unsigned long enable_setjmp=0;
+unsigned long dump_tables=0;
+#define CHECK_OVERRIDES { \
+ if (vrm_override && vrmi > 0) continue; \
+ if (prefix_override && strncmp("p", instruction_name, 1) == 0) { \
+ if (verbose) printf("Skipping prefix insn test %s\n",instruction_name); \
+ continue; \
+ } \
+}
+
+/* Helpers to manage when our output fields require special handling.
+ - some parts of the output fields are Undefined.
+ - some parts of the output field contain *estimated* data that needs to be
+ truncated when presented.
+ - some parts of the output need to be interpreted as INF or NAN.
+ */
+#define DOUBLE_EST_MASK 0b10000000
+#define SINGLE_EST_MASK 0b01000000
+
+// Double precision indicators.
+#define DP0 0b00100000
+#define DP1 0b00010000
+#define DOUBLE_MASK 0b00110000
+
+// Single precision indicators.
+#define SP0 0b00001000
+#define SP1 0b00000100
+#define SP2 0b00000010
+#define SP3 0b00000001
+#define SINGLE_MASK 0b00001111
+
+// bfloat16 indicators.
+#define B16_MASK 0b1111111100000000
+#define B16_0 0b1000000000000000
+#define B16_1 0b0100000000000000
+#define B16_2 0b0010000000000000
+#define B16_3 0b0001000000000000
+#define B16_4 0b0000100000000000
+#define B16_5 0b0000010000000000
+#define B16_6 0b0000001000000000
+#define B16_7 0b0000000100000000
+
+
+/* ******************************* */
+/* Instruction Form indicators. */
+/* As part of the instruction testing process, pull apart the provided
+ form field, and identify the parameters that are in use. These are
+ subsequently used to control the inputs provided to the instruction
+ being tested. */
+
+bool has_ra, has_rb, has_rc, has_rs, has_rt;
+bool has_rtp, has_rsp;
+bool has_vra, has_vrb, has_vrc, has_vrm, has_vrt;
+bool has_xa, has_xb, has_xc, has_xs, has_xt;
+bool has_xap;
+bool uses_xc_as_blend_mask;
+bool has_xsp, has_xtp;
+bool has_frb, has_frbp; // frb* uses same regs as frsp.
+bool has_frs, has_frsp;
+bool has_frt, has_frtp;
+bool uses_CRBIT,uses_RC,uses_MC;
+bool uses_cr;
+bool is_divide_or_modulo;
+bool is_insert_double;
+bool is_testlsb;
+
+/* Input parameter related. */
+bool has_rs_as_value_source;
+bool has_dcmx;
+unsigned long is_clear_or_insert_insns;
+unsigned long is_mtvsr_insn;
+unsigned long is_cmp_insn;
+bool has_ra_target;
+bool uses_dfp128_input;
+bool uses_dfp128_output;
+
+/* Accumulator related. */
+bool uses_acc;
+bool uses_acc_src;
+bool uses_acc_dest;
+bool uses_acc_vsrs;
+
+/* Buffer related. */
+bool uses_buffer;
+bool uses_load_buffer, uses_store_buffer, uses_any_buffer;
+bool uses_quad;
+
+/* Indicator for estimate instructions containing output fields that
+ should not be hex-dumped. */
+unsigned long output_mask;
+bool instruction_is_sp, instruction_is_sp_estimate;
+bool instruction_is_dp, instruction_is_dp_estimate;
+bool instruction_is_b16;
+
+static unsigned long long min(unsigned long long a, unsigned long long b) {
+ if ( a < b )
+ return a;
+ return b;
+}
+
+/* Parse the 'form' field to mark and identify arguments to the instruction. */
+static void identify_form_components(const char *instruction_name,
+ const char *cur_form) {
+ has_ra = (
+ (strstr(cur_form,",RA")!=NULL) ||
+ (strstr(cur_form,"(RA)")!=NULL) );
+ has_ra_target=(strncmp(cur_form,"RA,",3)==0);
+ has_rb=strstr(cur_form,",RB")!=NULL;
+ has_rc=strstr(cur_form,",RC")!=NULL;
+ has_rs=((strstr(cur_form,",RS")!=NULL) ||
+ (strncmp(cur_form,"RS",2)==0));
+ has_rsp=(
+ (strncmp(cur_form,"RSp",3)==0));
+ has_rt=(strncmp(cur_form,"RT",2)==0);
+ has_rtp=(strncmp(cur_form,"RTp",3)==0);
+
+ has_vra=strstr(cur_form,"VRA")!=NULL;
+ has_vrb=strstr(cur_form,"VRB")!=NULL;
+ has_vrc=strstr(cur_form,"VRC")!=NULL;
+ has_vrm=strstr(cur_form,"VRM")!=NULL;
+ has_vrt=(strncmp(cur_form,"VRT",3)==0);
+
+ has_frb=strstr(cur_form,"FRB")!=NULL;
+ has_frbp=strstr(cur_form,"FRBp")!=NULL;
+ has_frs=strstr(cur_form,"FRS")!=NULL;
+ has_frsp=strstr(cur_form,"FRSp")!=NULL;
+ has_frt=strstr(cur_form,"FRT")!=NULL;
+ has_frtp=strstr(cur_form,"FRTp")!=NULL;
+
+ has_xa=strstr(cur_form,",XA")!=NULL;
+ has_xap=strstr(cur_form,",XAp")!=NULL;
+ has_xb=strstr(cur_form,",XB")!=NULL;
+ has_xc=strstr(cur_form,",XC")!=NULL;
+ has_xs=(strncmp(cur_form,"XS",2)==0);
+ has_xsp=(strncmp(cur_form,"XSp",3)==0);
+ has_xt=(strncmp(cur_form,"XT",2)==0);
+ has_xtp=(strncmp(cur_form,"XTp",3)==0);
+
+ uses_acc_src=(strstr(cur_form,"AS")!=NULL);
+ uses_acc_dest=(strstr(cur_form,"AT")!=NULL);
+/* This (xxm*acc) is a special case where the acc_src is used, but we
+ need to read the associated _vsrs on the way out. */
+ uses_acc_vsrs=(
+ (strstr(instruction_name,"xxmfacc")!=NULL) ||
+ (strstr(instruction_name,"xxmtacc")!=NULL) );
+ uses_acc=uses_acc_src || uses_acc_dest || uses_acc_vsrs;
+
+ uses_dfp128_input=(
+ (strncmp(instruction_name,"dctf",4)==0));
+ uses_dfp128_output=(
+ (strncmp(instruction_name,"dcff",4)==0));
+ is_divide_or_modulo=(
+ (strncmp(instruction_name,"vdiv",4)==0) ||
+ (strncmp(instruction_name,"pmvdiv",6)==0) ||
+ (strncmp(instruction_name,"vmod",4)==0) ||
+ (strncmp(instruction_name,"pmvmod",6)==0) );
+ is_insert_double=(
+ (strncmp(instruction_name,"vinsd",5)==0) );
+ is_testlsb=(
+ (strncmp(instruction_name,"xvtlsbb",7)==0) );
+ uses_xc_as_blend_mask=(
+ (strncmp(instruction_name,"xxblend",7)==0) );
+ has_dcmx=strstr(cur_form,"DCMX")!=NULL;
+ uses_CRBIT=(
+ (strncmp(cur_form,"BF",2)==0) ||
+ (strstr(cur_form,",BI")!=0));
+ uses_RC=(
+ (strstr(instruction_name,".")!=NULL ));
+ uses_MC=(
+ (strstr(instruction_name,",MC")!=NULL ));
+ uses_cr=(
+ (strstr(instruction_name,"setbcr")!=0) ||
+ (strstr(instruction_name,"setnbcr")!=0));
+ uses_load_buffer=(
+ (strncmp(instruction_name,"ld",2)==0) ||
+ (strncmp(instruction_name,"lq",2)==0) ||
+ (strncmp(instruction_name,"plq",3)==0) ||
+ (strncmp(instruction_name,"plx",3)==0) ||
+ (strncmp(instruction_name,"pmlx",4)==0) ||
+ (strncmp(instruction_name,"lxv",3)==0) ||
+ ((strncmp(instruction_name,"lxva",4)==0) &&
+/* lxvkq loads special values into a VSX vector, so though this looks like
+ a load, it does not actually load a value from a buffer. */
+ (strncmp(instruction_name,"lxvkq",5)!=0)) );
+ uses_store_buffer=(
+ (strncmp(instruction_name,"pmst",4)==0) ||
+ (strncmp(instruction_name,"pst",3)==0) ||
+ (strncmp(instruction_name,"st",2)==0));
+ uses_any_buffer=(strstr(cur_form,"(RA)")!=NULL);
+ uses_buffer=uses_any_buffer||uses_load_buffer||uses_store_buffer;
+
+ uses_quad = (uses_buffer && (strstr(instruction_name,"q")!=NULL));
+
+ has_rs_as_value_source=(
+ (strcmp(cur_form,"RA,RS,RB")==0) ||
+ (strcmp(cur_form,"RA,RS")==0) );
+
+ is_clear_or_insert_insns=(
+ (strncmp(instruction_name,"vclr",4)==0) ||
+ (strncmp(instruction_name,"vins",4)==0) );
+
+ /* This is used by a helper function to control the CR field output when
+ the instruction is a compare, versus when it is a bitfield check. */
+ is_cmp_insn=((strstr(cur_form,"cmp")!=NULL));
+
+ /* Special handling if we are testing a mtvsr insn. */
+ is_mtvsr_insn=((strncmp(instruction_name,"mtvsr",5)==0));
+
+ /* If the instruction output needs to be something other than a hex dump,
+ a mask will have been defined as part of the test_list_t structure.
+ This includes instructions that return estimated values, as well as
+ those that return NAN results which contain sign bits that need to be
+ filtered out. */
+ output_mask = ( current_test.mask );
+ instruction_is_dp = ( current_test.mask & DOUBLE_MASK );
+ instruction_is_dp_estimate = ( current_test.mask & DOUBLE_EST_MASK );
+ instruction_is_sp = ( current_test.mask & SINGLE_MASK );
+ instruction_is_sp_estimate = ( current_test.mask & SINGLE_EST_MASK );
+ instruction_is_b16 = ( current_test.mask & B16_MASK );
+}
+
+static void display_form_components(char * cur_form) {
+ printf (" %s\n",cur_form);
+ printf("Instruction form elements: ");
+ if (has_ra) printf("ra ");
+ if (has_rb) printf("rb ");
+ if (has_rc) printf("rc ");
+ if (has_rs) printf("rs ");
+ if (has_rsp) printf("rsp ");
+ if (has_rt) printf("rt ");
+ if (has_rtp) printf("rtp ");
+ if (has_vra) printf("vra ");
+ if (has_vrb) printf("vrb ");
+ if (has_vrc) printf("vrc ");
+ if (has_vrm) printf("vrm ");
+ if (has_vrt) printf("vrt ");
+
+ if (has_frb) printf("frb ");
+ if (has_frbp) printf("frbp ");
+ if (has_frs) printf("frs ");
+ if (has_frsp) printf("frsp ");
+ if (has_frt) printf("frt ");
+ if (has_frtp) printf("frtp ");
+ if (has_xa) printf("xa ");
+ if (has_xap) printf("xap ");
+ if (has_xb) printf("xb ");
+ if (has_xc) printf("xc ");
+ if (has_xs) printf("xs ");
+ if (has_xsp) printf("xsp ");
+ if (has_xt) printf("xt ");
+ if (has_xtp) printf("xtp ");
+ if (uses_acc_src) printf("AS ");
+ if (uses_acc_dest) printf("AT ");
+ printf("\n");
+ if (uses_dfp128_input)
+ printf ("uses dfp128 input.\n");
+ if (uses_dfp128_output)
+ printf ("uses dfp128 output.\n");
+ if (has_ra_target)
+ printf ("ra is a target register.\n");
+ if (has_rs_as_value_source)
+ printf ("rs is a value source.\n");
+ if (uses_xc_as_blend_mask)
+ printf ("uses xc as a blend mask.\n");
+ if (is_clear_or_insert_insns)
+ printf ("is a clear or insert insn.\n");
+ if (is_insert_double)
+ printf ("is an insert doubleword.\n");
+ if (is_testlsb)
+ printf ("tests lsb.\n");
+ if (uses_buffer)
+ printf ("uses_buffer: (l:%d s:%d ?:%d)\n",
+ uses_load_buffer, uses_store_buffer, uses_any_buffer);
+ if (uses_quad)
+ printf ("is a quad load or store.\n");
+ if (is_cmp_insn)
+ printf ("is a compare instruction.\n");
+ if (uses_CRBIT)
+ printf ("instruction references a CR.\n");
+ if (uses_cr)
+ printf ("instruction reads CR bits.\n");
+ if (uses_MC)
+ printf ("Instruction uses MC.\n");
+ if (uses_RC)
+ printf ("Instruction uses Record Bit (cr6).\n");
+ if (uses_acc)
+ printf ("Instruction uses ACC: (src:%d,dst:%d,vsrs:%d).\n",
+ uses_acc_src, uses_acc_dest, uses_acc_vsrs);
+ if (output_mask) { printf ("Instruction results are masked: ");
+ printf("(%lx) ",output_mask);
+ printf ("%s ",instruction_is_sp?"SP ":"");
+ printf ("%s ",instruction_is_sp_estimate?"SP Estimate ":"");
+ printf ("%s ",instruction_is_dp?"DP ":"");
+ printf ("%s ",instruction_is_dp_estimate?"DP Estimate ":"");
+ printf ("%s ",instruction_is_b16?"bfloat16 ":"");
+ }
+ printf ("\n");
+}
+
+#define DEADBEEF 0x1111111111111111UL
+
+long long mask64[] = { 0x0, 0x00000000ffffffff, 0xffffffff55555555,
+ 0x5555aaaaaaaa5555, 0xaaaa00000000aaaa };
+#define MASK64SIZE 5
+unsigned long long vrm_mask[] = { 0x0,0x8000000000000000,
+ 0x8000000000000000, 0x0 };
+#define VRMMASK_SIZE 4
+
+unsigned long post_test; // helper to suppress some output.
+
+#define debug_printf(X) if (verbose>0) printf(X);
+#define debug_show_labels (verbose>0)
+#define debug_show_iters (verbose>1)
+#define debug_show_raw_values (verbose>2)
+#define debug_show_all_regs (verbose>5)
+#define debug_show_tables (verbose>6)
+
+/* ************************************ */
+/* Helpers for displaying FP/DP values.
+
+Not a Numbers (NaNs): These are values that have the maximum biased exponent
+ and a nonzero mantissa (fraction). If the high-order
+ bit of the fraction field is 0 then the NaN is a
+ Signaling NaN, otherwise it is a Quiet NaN. */
+
+// Union to help handle referencing hex/float/double values.
+union rosetta_t {
+ unsigned long long ull;
+ unsigned long long ullp[2];
+ float flt;
+ float fltp[2];
+ uint16_t uint16s[4];
+ double dbl;
+};
+
+static void generic_print_float_as_hex(float f) {
+ union rosetta_t stone;
+ stone.ullp[0]=stone.ullp[1]=0; //init
+ stone.flt=f;
+ printf(" %016llx",stone.ull);
+}
+
+static void generic_print_ull_as_float(unsigned long long ull) {
+ union rosetta_t stone;
+ stone.ullp[0]=stone.ullp[1]=0; //init
+ stone.ull=ull;
+ printf(" %f",stone.flt);
+}
+
+static void generic_print_ull_as_double(unsigned long long ull) {
+ union rosetta_t stone;
+ stone.ullp[0]=stone.ullp[1]=0; //init
+ stone.ull=ull;
+ printf(" %e",stone.dbl);
+}
+
+static void generic_print_double_as_hex(double d) {
+ union rosetta_t stone;
+ stone.ullp[0]=stone.ullp[1]=0; //init
+ stone.dbl=d;
+ printf(" %016llx",stone.ull);
+}
+
+// SP in a 32-bit field.
+#define SP_SIGNBIT_MASK 0x80000000
+#define SP_EXPONENT_MASK 0x7f800000
+#define SP_FRACTION_MASK 0x007fffff
+
+// DP (64-bit).
+#define DP_SIGNBIT_MASK 0x8000000000000000UL
+#define DP_EXPONENT_MASK 0x7ff0000000000000UL
+#define DP_FRACTION_MASK 0x000fffffffffffffUL
+
+// B16 bfloat16.
+#define BF16_SIGNBIT_MASK 0x8000
+#define BF16_EXPONENT_MASK 0x7f80
+#define BF16_FRACTION_MASK 0x007f
+
+/*
+ - NAN and Zero values need the sign bit display suppressed. (See comments
+ in jm-insns.c line 7203).
+ - Some instructions return estimated values, which are calculated
+ to a different level of precision within valgrind. Those
+ instructions need their outputs limited to a specific number of
+ digits as seen below. */
+
+// NAN - Maximum biased exponent and a nonzero mantissa (fraction).
+#define PRINT_SP_NAN printf(" NaN");
+// DEN - Exp==0 and Frac != 0
+#define PRINT_SP_PLUS_DEN printf(" +Den");
+#define PRINT_SP_MINUS_DEN printf(" -Den");
+// INF - Maximum biased exponent and a zero mantissa.
+#define PRINT_SP_INF printf(" Inf");
+#define PRINT_SP_PLUS_INF printf(" +Inf");
+#define PRINT_SP_MINUS_INF printf(" -Inf");
+#define PRINT_SP_FLOAT(x) printf("%13.05e", x);
+#define PRINT_SP_FLOAT_EST(x) printf("%13.03e", x);
+#define PRINT_SP_FLOAT_PLUS_ZERO printf(" +Zero");
+#define PRINT_SP_FLOAT_MINUS_ZERO printf(" -Zero");
+
+/* Print a SINGLE (16 bit) SP value out of the left part of a 32-bit field. */
+static void special_print_sp_value(uint32_t value) {
+ int signbit;
+ int exponent;
+ unsigned long long fraction;
+ union rosetta_t stone;
+
+ stone.ull = value;
+ signbit = value & SP_SIGNBIT_MASK;
+ exponent= (value & SP_EXPONENT_MASK);
+ fraction= value & SP_FRACTION_MASK;
+
+ if (debug_show_raw_values) {
+ printf("\nsp_debug: v:%08x s: %d %3x %8llx %f ,",
+ value, signbit?1:0, exponent, fraction, stone.flt);
+ }
+ if (exponent == SP_EXPONENT_MASK && fraction == 0 ) {
+ if (signbit)
+ PRINT_SP_MINUS_INF
+ else
+ PRINT_SP_PLUS_INF
+ } else if (exponent == SP_EXPONENT_MASK && fraction != 0 ) {
+ PRINT_SP_NAN
+ } else if (exponent == 0 && fraction == 0 ) {
+ if (signbit)
+ PRINT_SP_FLOAT_MINUS_ZERO
+ else
+ PRINT_SP_FLOAT_PLUS_ZERO
+ } else if (exponent == 0 && fraction != 0 ) {
+ if (signbit)
+ PRINT_SP_MINUS_DEN
+ else
+ PRINT_SP_PLUS_DEN
+ } else if (instruction_is_sp_estimate) {
+ PRINT_SP_FLOAT_EST(stone.flt);
+ } else {
+ PRINT_SP_FLOAT(stone.flt);
+ }
+}
+
+static void dissect_sp_value(unsigned long long foo) {
+ if (debug_show_raw_values) {
+ printf("RAW sp::%4llx ",foo);
+ printf(" [s:");
+ printf("%x",(foo & SP_SIGNBIT_MASK)>0);
+ printf(" e:");
+ printf("%4llx",foo & SP_EXPONENT_MASK);
+ printf(" f:");
+ printf("%4llx",foo & SP_FRACTION_MASK);
+ printf("] ");
+ }
+ special_print_sp_value(foo);
+ printf(" ");
+}
+
+/* Print one DP values out of our vec_ field. */
+#define PRINT_DP_NAN printf(" NaN");
+#define PRINT_DP_MINUS_DEN printf(" -Den");
+#define PRINT_DP_PLUS_DEN printf(" +Den");
+#define PRINT_DP_MINUS_INF printf(" -Inf");
+#define PRINT_DP_PLUS_INF printf(" +InF");
+#define PRINT_DP_FLOAT(x) printf(" %15.08e", x);
+#define PRINT_DP_FLOAT_EST(x) printf(" %15.02e", x);
+#define PRINT_DP_FLOAT_PLUS_ZERO printf(" +Zero");
+#define PRINT_DP_FLOAT_MINUS_ZERO printf(" -Zero");
+#define PRINT_DP_FLOAT_ZERO printf(" 0.000000e+000");
+static void special_print_dp_value(unsigned long long value) {
+ unsigned long long signbit;
+ unsigned long long exponent;
+ unsigned long long fraction;
+ union rosetta_t stone;
+
+ stone.ull = value;
+ signbit = ((value & DP_SIGNBIT_MASK)>0);
+ exponent= (value & DP_EXPONENT_MASK); // >> double_exponent_shift;
+ fraction= value & DP_FRACTION_MASK;
+ if (verbose>2)
+ printf("\ndb_debug: %16llx s:%d %3llx %8llx %llx ,",
+ value, signbit?1:0, exponent, fraction, stone.ull);
+ if (exponent == DP_EXPONENT_MASK /* MAX */ && fraction == 0 ) {
+ if (signbit)
+ PRINT_DP_MINUS_INF
+ else
+ PRINT_DP_PLUS_INF
+ } else if (exponent == DP_EXPONENT_MASK && fraction != 0 ) {
+ PRINT_DP_NAN
+ } else if (exponent == 0 && fraction == 0 ) {
+ if (signbit)
+ PRINT_DP_FLOAT_MINUS_ZERO
+ else
+ PRINT_DP_FLOAT_PLUS_ZERO
+ } else if (exponent == 0 && fraction != 0 ) {
+ if (signbit)
+ PRINT_DP_MINUS_DEN
+ else
+ PRINT_DP_PLUS_DEN
+ } else if (instruction_is_dp_estimate) {
+ PRINT_DP_FLOAT_EST(stone.dbl);
+ } else {
+ PRINT_DP_FLOAT(stone.dbl);
+ }
+}
+
+static void dissect_dp_value(unsigned long long foo) {
+ if (debug_show_raw_values) {
+ printf("RAW dp::%llx",(foo));
+ printf(" [sign:");
+ printf("%x ",((foo & DP_SIGNBIT_MASK)>0));
+ printf(" expbits:");
+ printf("%3llx",(foo & DP_EXPONENT_MASK)/* >> double_exponent_shift*/);
+ printf(" frac:");
+ printf("%16llx",foo & DP_FRACTION_MASK);
+ printf("] ");
+ }
+ special_print_dp_value(foo);
+ printf(" ");
+}
+
+// NAN - Maximum biased exponent and a nonzero mantissa (fraction).
+// printf(" [undef]"
+#define PRINT_BF16_NAN printf(" NaN");
+// DEN - Exp==0 and Frac != 0
+#define PRINT_BF16_PLUS_DEN printf(" +Den");
+#define PRINT_BF16_MINUS_DEN printf(" -Den");
+// INF - Maximum biased exponent and a zero mantissa.
+#define PRINT_BF16_INF printf(" Inf");
+#define PRINT_BF16_PLUS_INF printf(" +Inf");
+#define PRINT_BF16_MINUS_INF printf(" -Inf");
+#define PRINT_BF16_FLOAT(x) printf(" 0x%04x",x);
+#define PRINT_BF16_FLOAT_PLUS_ZERO printf(" +Zero");
+#define PRINT_BF16_FLOAT_MINUS_ZERO printf(" -Zero");
+
+/* print a single bfloat16 value. */
+static void special_print_bf16_value(uint16_t value) {
+ int signbit;
+ int exponent;
+ unsigned long long fraction;
+ union rosetta_t stone;
+ signbit = value & BF16_SIGNBIT_MASK;
+ exponent = (value & BF16_EXPONENT_MASK);
+ fraction = (value & BF16_FRACTION_MASK);
+ stone.ull = value;
+ if (debug_show_raw_values) {
+ printf("\nbf16_debug: v:%08x s: %d %3x %8llx %f ,",
+ value, signbit?1:0, exponent, fraction, stone.flt);
+ } else if (verbose > 0) {
+ printf(" v:%08x",value);
+ }
+ if (exponent == BF16_EXPONENT_MASK && fraction == 0 ) {
+ if (signbit)
+ PRINT_BF16_MINUS_INF
+ else
+ PRINT_BF16_PLUS_INF
+ } else if (exponent == BF16_EXPONENT_MASK && fraction != 0 ) {
+ PRINT_BF16_NAN
+ } else if (exponent == 0 && fraction == 0 ) {
+ if (signbit)
+ PRINT_BF16_FLOAT_MINUS_ZERO
+ else
+ PRINT_BF16_FLOAT_PLUS_ZERO
+ } else if (exponent == 0 && fraction != 0 ) {
+ if (signbit)
+ PRINT_BF16_MINUS_DEN
+ else
+ PRINT_BF16_PLUS_DEN
+ } else
+ PRINT_BF16_FLOAT(value);
+}
+
+/* ******************** */
+/* Accumulator related. */
+/* Note that our tests to set and clear the acc both read and write
+ from and to the associated VSRs, so some tests may be somewhat
+ self-fulfilling. */
+extern unsigned long setup_only;
+static void push_vsrs_to_acc() {
+ if (!setup_only)
+ __asm__ __volatile__ ("xxmtacc 4 "); // $ACCNUM
+}
+
+static void push_acc_to_vsrs() {
+ if (!setup_only)
+ __asm__ __volatile__ ("xxmfacc 4 "); // $ACCNUM
+}
+
+static void print_accumulator() {
+ if (uses_acc || debug_show_all_regs) {
+ push_acc_to_vsrs();
+ if (debug_show_labels) printf(" Acc[]:");
+ if (instruction_is_sp) {
+ printf(" (");
+ if ( TEST_ACC0[0] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC0[0]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC0[0]));
+ }
+ if ( TEST_ACC0[1] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC0[1]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC0[1]));
+ }
+ if ( TEST_ACC1[0] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC1[0]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC1[0]));
+ }
+ if ( TEST_ACC1[1] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC1[1]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC1[1]));
+ }
+ if ( TEST_ACC2[0] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC2[0]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC2[0]));
+ }
+ if ( TEST_ACC2[1] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC2[1]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC2[1]));
+ }
+ if ( TEST_ACC3[0] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC3[0]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC3[0]));
+ }
+ if ( TEST_ACC3[1] == DEADBEEF ) printf(" * "); else {
+ special_print_sp_value(0xffffffff & (TEST_ACC3[1]>>32));
+ special_print_sp_value(0xffffffff & (TEST_ACC3[1]));
+ }
+ printf(")");
+ } else if (instruction_is_dp) {
+ printf(" {");
+ if ( TEST_ACC0[0] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC0[0]));
+ if ( TEST_ACC0[1] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC0[1]));
+ if ( TEST_ACC1[0] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC1[0]));
+ if ( TEST_ACC1[1] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC1[1]));
+ if ( TEST_ACC2[0] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC2[0]));
+ if ( TEST_ACC2[1] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC2[1]));
+ if ( TEST_ACC3[0] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC3[0]));
+ if ( TEST_ACC3[1] == DEADBEEF ) printf(" * "); else
+ special_print_dp_value((TEST_ACC3[1]));
+ printf("}");
+ } else {
+ printf(" [");
+ if ( TEST_ACC0[0] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC0[0]);
+ if ( TEST_ACC0[1] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC0[1]);
+ if ( TEST_ACC1[0] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC1[0]);
+ if ( TEST_ACC1[1] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC1[1]);
+ if ( TEST_ACC2[0] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC2[0]);
+ if ( TEST_ACC2[1] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC2[1]);
+ if ( TEST_ACC3[0] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC3[0]);
+ if ( TEST_ACC3[1] == DEADBEEF ) printf(" * "); else
+ printf("%lx ",TEST_ACC3[1]);
+ printf("]");
+ }
+ }
+}
+
+/* *********** */
+/* CR helpers. */
+
+#define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
+
+#define SET_CR(_arg) \
+ __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
+
+#define SET_CR0_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x80,%0 " : : "b" (_arg):"cr0");
+#define SET_CR1_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x40,%0 " : : "b" (_arg):"cr1");
+#define SET_CR2_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x20,%0 " : : "b" (_arg):"cr2");
+#define SET_CR3_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x10,%0 " : : "b" (_arg):"cr3");
+#define SET_CR4_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x08,%0 " : : "r" (_arg):"cr4");
+#define SET_CR5_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x04,%0 " : : "r" (_arg):"cr5");
+#define SET_CR6_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x02,%0 " : : "r" (_arg):"cr6");
+#define SET_CR7_FIELD(_arg) __asm__ __volatile__ ("mtocrf 0x01,%0 " : : "r" (_arg):"cr7");
+
+#define SET_XER(_arg) __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
+#define GET_CR(_lval) __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) )
+#define GET_XER(_lval) __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
+#define SET_CR_ZERO SET_CR(0)
+
+/* ************** */
+/* FPSCR helpers. */
+#define SET_FPSCR_ZERO \
+ do { \
+ double _d = 0.0; \
+ __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
+ } while (0);
+
+#define GET_FPSCR(_arg) \
+ __asm__ __volatile__ ("mffs %0" : "=f"(_arg) );
+
+/* The bit definitions for the FPSCR are as follows.
+Bit(s) Description
+0:31 Reserved
+32 Floating-Point Exception Summary (FX)
+33 Floating-Point Enabled Exception Summary (FEX)
+34 Floating-Point Invalid Operation Exception Summary (VX)
+35 Floating-Point Overflow Exception (OX)
+36 Floating-Point Underflow Exception (UX)
+37 Floating-Point Zero Divide Exception (ZX)
+38 Floating-Point Inexact Exception (XX)
+39 Floating-Point Invalid Operation Exception (SNaN) (VXSNAN)
+40 Floating-Point Invalid Operation Exception (∞ - ∞) (VXISI)
+41 Floating-Point Invalid Operation Exception (∞ ÷ ∞) (VXIDI)
+42 Floating-Point Invalid Operation Exception (0 ÷ 0) (VXZDZ)
+43 Floating-Point Invalid Operation Exception (∞ × 0) (VXIMZ)
+44 Floating-Point Invalid Operation Exception (Invalid Compare) (VXVC)
+45 Floating-Point Fraction Rounded (FR)
+46 Floating-Point Fraction Inexact (FI)
+47:51 Floating-Point Result Flags (FPRF)
+47 Floating-Point Result Class Descriptor (C)
+48:51 Floating-Point Condition Code (FPCC)
+ 48 Floating-Point Less Than or Negative (FL or <)
+ 49 Floating-Point Greater Than or Positive (FG or >)
+ 50 Floating-Point Equal or Zero (FE or =)
+ 51 Floating-Point Unordered or NaN (FU or ?)
+52 Reserved
+53 Floating-Point Invalid Operation Exception (Software-Defined Condition) (VXSOFT)
+54 Floating-Point Invalid Operation Exception (Invalid Square Root) (VXSQRT)
+55 Floating-Point Invalid Operation Exception (Invalid Integer Convert) (VXCVI)
+56 Floating-Point Invalid Operation Exception Enable (VE)
+57 Floating-Point Overflow Exception Enable (OE)
+58 Floating-Point Underflow Exception Enable (UE)
+59 Floating-Point Zero Divide Exception Enable (ZE)
+60 Floating-Point Inexact Exception Enable (XE)
+61 Floating-Point Non-IEEE Mode (NI)
+62:63 Floating-Point Rounding Control (RN)
+ 00 Round to Nearest
+ 01 Round toward Zero
+ 10 Round toward +Infinity
+ 11 Round toward -Infinity
+*/
+/* Valgrind currently tracks the rounding mode, C and FPCC fields
+ of the FPSCR. Additional checking in the testcase is not
+ necessary or beneficial. */
+
+#define FPCC_C_BIT (0x1 << (63-47))
+#define FPCC_FL_BIT (0x1 << (63-48))
+#define FPCC_FG_BIT (0x1 << (63-49))
+#define FPCC_FE_BIT (0x1 << (63-50))
+#define FPCC_FU_BIT (0x1 << (63-51))
+#define FPCC_FPRF_MASK FPCC_C_BIT|FPCC_FL_BIT|FPCC_FG_BIT|FPCC_FE_BIT|FPCC_FU_BIT
+
+#define FPSCR_RN_BIT62 (0x1 << (63-62))
+#define FPSCR_RN_BIT63 (0x1 << (63-63))
+
+#define CRFIELD_BIT0 0x8
+#define CRFIELD_BIT1 0x4
+#define CRFIELD_BIT2 0x2
+#define CRFIELD_BIT3 0x1
+
+/* Display the condition register bits. */
+static inline int cr_overflow_set(unsigned this_cr) {
+ return (this_cr & CRFIELD_BIT3);
+}
+
+static inline int cr_zero_set(unsigned this_cr) {
+ return (this_cr & CRFIELD_BIT2);
+}
+
+static inline int cr_positive_set(unsigned this_cr) {
+ return (this_cr & CRFIELD_BIT1);
+}
+
+static inline int cr_negative_set(unsigned this_cr) {
+ return (this_cr & CRFIELD_BIT0);
+}
+
+/* This function (__dissect_cr) takes a bitfield directly. */
+inline static void __dissect_cr(unsigned this_cr) {
+ extern unsigned long is_cmp_insn;
+ printf("[");
+ if (cr_negative_set(this_cr))
+ printf("%s", is_cmp_insn ? "(LT) 0x1=Negative 0b1 " : "1");
+ else
+ printf("%s", verbose ? "0" : "0");
+
+ if (cr_positive_set(this_cr))
+ printf("%s", is_cmp_insn ? "(GT) 0x2=Positive fg_flag(zero/inf/denorm) " : "1");
+ else
+ printf("%s", verbose ? "0" : "0");
+
+ if (cr_zero_set(this_cr))
+ printf("%s", is_cmp_insn ? "(EQ) 0x4=Zero fe_flag(zero/nan/inf/neg/e_b<-970" : "1");
+ else
+ printf("%s", verbose ? "0" : "0");
+
+ if (cr_overflow_set(this_cr))
+ printf("%s", is_cmp_insn ? "(SO) 0x8=Overflow 0b0" : "1");
+ else
+ printf("%s", verbose ? "0" : "0");
+ printf("]");
+}
+
+/* Extract one CR field */
+static int extract_cr_rn(unsigned long chosen_cr,unsigned long rn) {
+ unsigned int masked_cr;
+ unsigned long shifted_value;
+ shifted_value = chosen_cr >> ( ( (7 - rn) * 4 ) );
+ masked_cr = shifted_value & 0xf;
+ return masked_cr;
+}
+
+/* Display one CR field */
+static void dissect_cr_rn(unsigned long chosen_cr, unsigned long rn) {
+ unsigned int masked_cr;
+ if (debug_show_labels) printf(" RC/CR(%ld):",rn );
+ masked_cr = extract_cr_rn(chosen_cr, rn);
+ printf("%ld:",rn);
+ __dissect_cr(masked_cr);
+}
+
+static char * fpscr_strings[] = {
+" 0-RSVD", " 1-RSVD", " 2-RSVD", " 3-RSVD", " 4-RSVD", " 5-RSVD", " 6-RSVD",
+" 7-RSVD", " 8-RSVD", " 9-RSVD", "10-RSVD", "11-RSVD", "12-RSVD", "13-RSVD",
+"14-RSVD", "15-RSVD", "16-RSVD", "17-RSVD", "18-RSVD", "19-RSVD", "20-RSVD",
+"21-RSVD", "22-RSVD", "23-RSVD", "24-RSVD", "25-RSVD", "26-RSVD", "27-RSVD",
+"28-RSVD", "29-DRN0", "30-DRN1", "31-DRN2",
+/* 32 */ "FX", "FEX", "VX",
+/* 35 */ "OX", "UX", "ZX", "XX", "VXSNAN",
+/* 40 */ "VXISI (inf-inf)", "VXIDI (inf/inf)", "VXZDZ (0/0)",
+/* 43 */ "VXIMZ (inf*0)", "VXVC",
+/* 45 */ "FR", "FI",
+/* 47 */ "FPRF-C", "FPCC-FL", "FPCC-FG",
+/* 50 */ "FPCC-FE", "FPCC-FU",
+/* 52 */ "52-RSVD", "FXSOFT", "VXSQRT",
+/* 55 */ "VXCVI", "VE", "OE", "UE", "ZE",
+/* 60 */ "XE", "NI", "RN-bit62", "RN-bit63"
+};
+/* Display the fpscr bits that are valid under valgrind.
+ * Valgrind tracks the C (FPSCR[47]), FPCC (FPSCR[48:51)
+ * DRN (FPSCR[29:31]) and RN (FPSCR[62:63]).
+ */
+static void dissect_fpscr_valgrind(unsigned long local_fpscr) {
+ int i;
+ long mybit;
+
+ /* Print DRN fields */
+ for (i = 29; i < 32; i++) {
+ mybit = 1LL << (63 - i);
+ if (mybit & local_fpscr) {
+ printf(" %s",fpscr_strings[i]);
+ }
+ }
+
+ /* Print C and FPCC fields */
+ for (i = 47; i < 52; i++) {
+ mybit = 1LL << (63 - i);
+ if (mybit & local_fpscr) {
+ printf(" %s",fpscr_strings[i]);
+ }
+ }
+
+ /* Print RN field */
+ for (i = 62; i < 64; i++) {
+ mybit = 1LL << (63 - i);
+ if (mybit & local_fpscr) {
+ printf(" %s",fpscr_strings[i]);
+ }
+ }
+}
+
+/*
+ * This prints the entire FPSCR field. This is only called under higher
+ * verbosities, as valgrind does not track most of these bits.
+ */
+static void dissect_fpscr_raw(unsigned long local_fpscr) {
+/* Due to the additional involved logic, the rounding mode (RN) bits 61-62
+ * are handled within dissect_fpscr_rounding_mode(). */
+ int i;
+ long mybit;
+
+ for (i = 0; i < 61; i++) {
+ /* also note that the bit numbering is backwards. */
+ mybit = 1LL << (63 - i);
+ if (mybit & local_fpscr) {
+ printf(" %s", fpscr_strings[i]);
+ }
+ }
+}
+
+static void dissect_fpscr(unsigned long local_fpscr) {
+ if (verbose > 2) {
+ printf(" [[ fpscr:%lx ]] ", local_fpscr);
+ dissect_fpscr_raw(local_fpscr);
+ } else {
+ dissect_fpscr_valgrind(local_fpscr);
+ }
+}
+
+
+/* *************** */
+/* Buffer Helpers.
+Define both a base and a reference buffer. When printing results, only print
+the values when there is a difference between the two. */
+#define BUFFER_SIZE 12
+/* Note: Watch the alignment of the buffer, some loads/stores may require
+stronger alignments. */
+__attribute__ ((aligned(16))) unsigned long long buffer[2*BUFFER_SIZE];
+__attribute__ ((aligned(16))) unsigned long long reference_buffer[2*BUFFER_SIZE];
+unsigned long changed_index[2*BUFFER_SIZE];
+static void initialize_buffer(int t)
+{
+ int x;
+ for (x = 0; x < BUFFER_SIZE; x++)
+ /* We don't want each of the 32-bit chunks to be identical since loads
+ * of a byte from the wrong 32-bit chuck may be difficult to spot.
+ * Load these up with values that are also interesting if SP/DP, etc.
+ */
+ switch((t+x)%BUFFER_SIZE) {
+ case 0: buffer[x] = 0x3fe00094e0007359; break; // sp
+ case 1: buffer[x] = 0x7ff7020304057607; break; // nan
+ case 2: buffer[x] = 0x7ff0000000007000; break; // inf
+ case 3: buffer[x] = 0x7f0000007f007000; break; // sp pair.
+ case 4: buffer[x] = 0x5a05a05a05a07a05; break;
+ case 5: buffer[x] = 0x0102030405067708; break;
+ case 6: buffer[x] = 0xfedcba9876547210; break;
+ case 7: buffer[x] = 0x0123456789ab7def; break;
+ case 8: buffer[x] = 0xffeeddccbbaa7988; break;
+ default: buffer[x] = 0x1112111211127112*(x-8); break;
+ }
+ for (x = 0; x < BUFFER_SIZE; x++)
+ reference_buffer[x]=buffer[x];
+}
+
+/* Buffer printing helper. This only displays the contents if they have
+ changed with respect to the reference buffer, or if running under
+ high verbosity. */
+static void dump_changed_buffer(unsigned long range) {
+ int x;
+ int buffer_changed=0;
+
+ for (x = 0; (x < BUFFER_SIZE) && (x<range) ; x++) {
+ changed_index[x]=0;
+ if (buffer[x] != reference_buffer[x]) {
+ buffer_changed=1;
+ changed_index[x]=1;
+ if (verbose>2)
+ printf(" {idx %d %016llx %016llx}", x,
+ reference_buffer[x] , buffer[x] );
+ }
+ }
+ if (verbose>2 || buffer_changed) {
+ printf(" [");
+ for (x = 0; x < BUFFER_SIZE && (x<range); x++) {
+ if (x) printf(" ");
+ if (verbose>0)
+ printf("%s%016llx", changed_index[x]==1?"*":" ",buffer[x] );
+ if (changed_index[x]) {
+ if (instruction_is_sp) {
+ printf(" (");
+ special_print_sp_value(0xffffffff & buffer[x] >> 32 );
+ printf(" ");
+ special_print_sp_value(0xffffffff & buffer[x]);
+ printf(") ");
+ } else if (instruction_is_dp) {
+ printf(" {");
+ special_print_dp_value(buffer[x]);
+ printf("} ");
+ }
+ printf("%016llx",buffer[x]);
+ } else printf(" - ");
+ }
+ printf("]");
+ }
+}
+
+static void dump_raw_buffer() {
+ int x;
+ printf("buffer:[");
+ for (x = 0; x < BUFFER_SIZE ; x++) {
+ if (x%4==0) printf("(%d)",x);
+ printf("%016llx ",buffer[x]);
+ }
+ printf("]");
+}
+
+static void dump_small_buffer(void) {
+ dump_changed_buffer(8);
+}
+
+static void dump_large_buffer(void) {
+ dump_changed_buffer(8);
+}
+
+static void dump_buffer() {
+if (verbose>1) printf(" buffer:");
+ if (uses_quad) {
+ dump_large_buffer();
+ } else {
+ dump_small_buffer();
+ }
+}
+
+static inline void print_undefined() {
+if (verbose>1)
+ printf(" [Undef]");
+else
+ printf(" ");
+}
+
+/* print the input 64-bit vector as 32-bit SP lumps. */
+static void print_vec_as_sp(unsigned long long ull64) {
+ printf(" %08llx", ull64 >> 32 );
+ printf(" %08llx", ull64 & 0xffff );
+}
+
+/*------------------------------------------------------------------*/
+/* Decimal Floating Point (DFP) helper functions */
+/*------------------------------------------------------------------*/
+#define NOT( x ) ( ( ( x ) == 0) ? 1 : 0)
+#define GET( x, y ) ( ( ( x ) & ( 0x1UL << ( y ) ) ) >> ( y ) )
+#define PUT( x, y ) ( ( x )<< ( y ) )
+
+static unsigned long dpb_to_bcd( unsigned long chunk )
+{
+ int a, b, c, d, e, f, g, h, i, j, k, m;
+ int p, q, r, s, t, u, v, w, x, y;
+ unsigned long value;
+
+ /* convert 10 bit densely packed BCD to BCD */
+ p = GET( chunk, 9 );
+ q = GET( chunk, 8 );
+ r = GET( chunk, 7 );
+ s = GET( chunk, 6 );
+ t = GET( chunk, 5 );
+ u = GET( chunk, 4 );
+ v = GET( chunk, 3 );
+ w = GET( chunk, 2 );
+ x = GET( chunk, 1 );
+ y = GET( chunk, 0 );
+
+ /* The BCD bit values are given by the following boolean equations.*/
+ a = ( NOT(s) & v & w ) | ( t & v & w & s ) | ( v & w & NOT(x) );
+ b = ( p & s & x & NOT(t) ) | ( p & NOT(w) ) | ( p & NOT(v) );
+ c = ( q & s & x & NOT(t) ) | ( q & NOT(w) ) | ( q & NOT(v) );
+ d = r;
+ e = ( v & NOT(w) & x ) | ( s & v & w & x ) | ( NOT(t) & v & x & w );
+ f = ( p & t & v & w & x & NOT(s) ) | ( s & NOT(x) & v ) | ( s & NOT(v) );
+ g = ( q & t & w & v & x & NOT(s) ) | ( t & NOT(x) & v ) | ( t & NOT(v) );
+ h = u;
+ i = ( t & v & w & x ) | ( s & v & w & x ) | ( v & NOT(w) & NOT(x) );
+ j = ( p & NOT(s) & NOT(t) & w & v ) | ( s & v & NOT(w) & x )
+ | ( p & w & NOT(x) & v ) | ( w & NOT(v) );
+ k = ( q & NOT(s) & NOT(t) & v & w ) | ( t & v & NOT(w) & x )
+ | ( q & v & w & NOT(x) ) | ( x & NOT(v) );
+ m = y;
+
+ value = PUT(a, 11) | PUT(b, 10) | PUT(c, 9) | PUT(d, 8) | PUT(e, 7)
+ | PUT(f, 6) | PUT(g, 5) | PUT(h, 4) | PUT(i, 3) | PUT(j, 2)
+ | PUT(k, 1) | PUT(m, 0);
+ return value;
+}
+#undef NOT
+#undef GET
+#undef PUT
+
+/* get_declet(). Return a 10-bit declet, beginning at the 'start'
+ * offset.
+ *
+ * | dword1 | dword0 |
+ * | 0 63|64 127|
+ */
+#define TEN_BITS 0x03ffULL
+
+static inline int get_declet(int start, uint64_t dword1, uint64_t dword0) {
+ unsigned long local_declet;
+ unsigned int dword0_shift;
+ unsigned int dword1_shift;
+
+ dword1_shift = 63 - (start + 9);
+ dword0_shift = 127 - (start + 9);
+
+ if (verbose>5) printf("\n%s (%d) %016lx %016lx",
+ __FUNCTION__, start, dword1, dword0);
+
+ if ((start + 9) < 63) { /* fully within dword1 */
+ local_declet = (dword1 >> dword1_shift) & TEN_BITS;
+
+ } else if (start >= 65) {/* fully within dword0 */
+ local_declet = (dword0 >> dword0_shift) & TEN_BITS;
+
+ } else { /* straddling the two dwords*/
+ unsigned long mask_dword0;
+ unsigned long mask_dword1;
+
+ mask_dword1 = TEN_BITS >> (64 - dword0_shift);
+ mask_dword0 = TEN_BITS << (dword0_shift);
+ local_declet =
+ ((dword1 & mask_dword1) << (64-dword0_shift)) +
+ ((dword0 & mask_dword0) >> dword0_shift);
+ }
+ return local_declet;
+}
+
+static int get_bcd_digit_from_dpd(int start, uint64_t dword1,
+ uint64_t dword0) {
+ long bcd_digit;
+ long declet;
+
+ declet = get_declet(start, dword1, dword0);
+ bcd_digit = dpb_to_bcd(declet);
+ return bcd_digit;
+}
+
+/* For DFP finite numbers, the combination field (G field) is a
+ * combination of the exponent and the LMD (Left Most Digit) of the
+ * significand. The fields are encoded/decoded as described in the
+ * table here.
+ * 00 01 10 -< Exponent bits.
+ * 0: 00000 01000 10000
+ * ...
+ * 7: 00111 01111 10111
+ * 8: 11000 11010 11100
+ * 9: 11001 11011 11101 (encoded special field).
+ * |
+ * ^ LMD value.
+*/
+#define DFP_GFIELD_MASK 0x7c00000000000000UL
+#define DFP_GFIELD_SHIFT 58
+//The exponent bias value is 101 for DFP Short, 398
+//for DFP Long, and 6176 for DFP Extended.
+#define DFP128_EXPONENT_BIAS 6176
+#define DFP64_EXPONENT_BIAS 398
+
+static unsigned int special_field_LMD(uint64_t dword1) {
+ unsigned long g_field_specials;
+ int left_two_bits;
+ int right_three_bits;
+
+ g_field_specials = (dword1 & DFP_GFIELD_MASK) >> DFP_GFIELD_SHIFT;
+ left_two_bits = (g_field_specials & 0x18) >> 3;
+ right_three_bits = g_field_specials & 0x07;
+
+ /* The LMD result maps directly to the right_three_bits value as
+ * long as the left two bits are 0b00,0b01,0b10. So a compare
+ * against 3 is sufficient to determine if we can return the right
+ * three bits directly. (LMD values 0..7).
+ */
+ if (left_two_bits < 3) {
+ return (right_three_bits);
+ }
+
+ /* LMD values of 8 or 9 require a bit of swizzle, but a check of
+ * the right-most bit is sufficient to determine whether LMD value
+ * is 8 or 9.
+ */
+ if (right_three_bits & 0x1)
+ return 9;
+ else
+ return 8;
+}
+
+/* Returns the exponent bits, as decoded from the G field. */
+static inline int special_field_exponent_bits(unsigned long dword1) {
+ unsigned long g_field_specials;
+ int left_two_bits;
+ int right_three_bits;
+
+ g_field_specials = (dword1 & DFP_GFIELD_MASK) >> DFP_GFIELD_SHIFT;
+ left_two_bits = (g_field_specials & 0x18) >> 3;
+ right_three_bits = g_field_specials & 0x07;
+
+ /* The special field exponent bits maps directly to the left_two_bits
+ * value as long as the left two bits are 0b00,0b01,0b10. So a compare
+ * against 3 is sufficient for those values.
+ */
+ if (left_two_bits < 3) {
+ return (left_two_bits);
+ }
+
+ switch(right_three_bits) {
+ case 0:
+ case 1: return 0x0;
+ case 2:
+ case 3: return 0x1;
+ case 4:
+ case 5: return 0x2;
+ case 6: /* Infinity */ return 0x0;
+ case 7: /* NaN */ return 0x0;
+ }
+ return -1; /* should never hit this */
+}
+
+/* The 'exponent left' shift is for moving the leftmost two bits
+ * of the exponent down to where they can be easily merged with the
+ * rest of the exponent.
+ */
+#define DFP128_EXPONENT_RIGHT_MASK 0x03ffc00000000000
+#define DFP64_EXPONENT_RIGHT_MASK 0x03fc000000000000
+#define DFP128_EXPONENT_RIGHT_MASK_SHIFT 46
+#define DFP64_EXPONENT_RIGHT_MASK_SHIFT 50
+#define DFP128_EXPONENT_LEFT_SHIFT 12
+#define DFP64_EXPONENT_LEFT_SHIFT 8
+
+#define DFP_NAN 0x1f
+#define DFP_INF 0x1e
+#define DFP_SIGNALING_NAN_BIT 0x0200000000000000
+
+/* return the dfp exponent from the leading dword. */
+static inline signed long dfp128_exponent(unsigned long dword1) {
+ unsigned long exponent_left;
+ unsigned long exponent_right;
+ unsigned long biased_exponent;
+ signed long exponent;
+
+ exponent_left = special_field_exponent_bits(dword1);
+ exponent_right = (dword1 & DFP128_EXPONENT_RIGHT_MASK);
+ biased_exponent = (exponent_left << DFP128_EXPONENT_LEFT_SHIFT) +
+ (exponent_right >> DFP128_EXPONENT_RIGHT_MASK_SHIFT);
+
+ /* Unbias the exponent. */
+ exponent = biased_exponent - DFP128_EXPONENT_BIAS;
+ return exponent;
+}
+
+/* Interpret the paired 64-bit values as a extended (quad) 128 bit DFP.
+ *
+ * | Significand | Combination Field/ | |
+ * | sign bit | Encoded Exponent | remainder of significand |
+ * |0 |1 17|18 127|
+ * ^ (bit0) Significand sign bit.
+ * ^ (bit 1:17) Combination field. Contains high bits of
+ * exponent (encoded), LMD of significand (encoded),
+ * and the remainder of the exponent. First five bits
+ * will indicate special cases NAN or INF.
+ * ^ (bit 18:127) Remainder of the
+ * significand.
+ */
+
+#define DFP128_COMBINATION_MASK 0x7fffc
+#define DFP64_COMBINATION_MASK 0x7ffc
+#define DFP128_COMBINATION_SHIFT 46
+#define DFP64_COMBINATION_SHIFT 50
+#define DFP_SPECIAL_SYMBOLS_MASK 0x1f
+#define DFP_SPECIAL_SYMBOLS_SHIFT 58
+
+#define DFP_NAN 0x1f
+#define DFP_INF 0x1e
+#define DFP_SIGNALING_NAN_BIT 0x0200000000000000
+
+#define DFP128_T_START 18
+
+static inline void dissect_dfp128_float(uint64_t dword1, uint64_t dword0) {
+ long signbit;
+ signed long exponent;
+ unsigned long gfield_special_symbols;
+ unsigned long lmd_digit;
+ unsigned long bcd_digits[13];
+ int i;
+ int silent=0; // suppress leading zeros from the output.
+
+ if (debug_show_raw_values) printf("DFP128R:%016lx,%016lx", dword1, dword0);
+
+ signbit = (dword1 >> 63);
+
+ if (signbit) printf(" -");
+ else printf(" ");
+
+ gfield_special_symbols =
+ ((dword1 >> DFP_SPECIAL_SYMBOLS_SHIFT) & DFP_SPECIAL_SYMBOLS_MASK);
+
+ switch (gfield_special_symbols) {
+ case DFP_INF:
+ printf( "inf ");
+ break;
+
+ case DFP_NAN:
+ if (dword1 & DFP_SIGNALING_NAN_BIT)
+ printf("SNaN ");
+ else
+ printf("QNaN ");
+ break;
+
+ default:
+ // printf( "Finite ");
+ exponent = dfp128_exponent(dword1);
+ // printf("Exponent: %d Bias: %d ",exponent, DFP128_EXPONENT_BIAS );
+
+ lmd_digit = special_field_LMD(dword1);
+ for (i = 0; i < 11; i++) {
+ bcd_digits[i] = get_bcd_digit_from_dpd((DFP128_T_START
+ + 10 * i), dword1, dword0);
+ }
+ if (lmd_digit) {
+ silent++;
+ printf("%01lx", lmd_digit);
+ } else {
+ printf(" ");
+ }
+ for (i = 0; i < 11; i++) {
+ if (bcd_digits[i] || silent ) {
+ silent++;
+ printf("%01lx", bcd_digits[i]);
+ } else {
+ /* always print at least the last zero */
+ if (i == 10)
+ printf("0");
+ else
+ printf(" ");
+ }
+ }
+ printf(" * 10^");
+ printf("%ld", exponent);
+ }
+}
+
+static void print_vsr(int vsr_to_print) {
+unsigned long long blob1,blob2;
+switch (vsr_to_print) {
+ case 26:
+ __asm__ __volatile__ ("mfvsrd %0,26":"=r" (blob1));
+ __asm__ __volatile__ ("mfvsrld %0,26":"=r" (blob2));
+ break;
+ case 27:
+ __asm__ __volatile__ ("mfvsrd %0,27":"=r" (blob1));
+ __asm__ __volatile__ ("mfvsrld %0,27":"=r" (blob2));
+ break;
+ case 28:
+ __asm__ __volatile__ ("mfvsrd %0,28":"=r" (blob1));
+ __asm__ __volatile__ ("mfvsrld %0,28":"=r" (blob2));
+ break;
+ case 29:
+ __asm__ __volatile__ ("mfvsrd %0,29":"=r" (blob1));
+ __asm__ __volatile__ ("mfvsrld %0,29":"=r" (blob2));
+ break;
+ default:
+ printf("Add entry for VSR %d to %s in %s.\n",vsr_to_print,__FUNCTION__,__FILE__);
+ }
+if (debug_show_labels)
+ printf(" VSR(%d):",vsr_to_print);
+printf(" %llx,%llx ",blob1,blob2);
+}
+
+
+static void print_frt() {
+ unsigned long long value1,value3;
+ if (has_frt || debug_show_all_regs ) {
+ if (debug_show_labels) printf(" frt%s:",has_frtp?"p":"" );
+ /* If the result is a dfp128 value, the dfp128 value is contained
+ in the frt,frtp values which are split across a pair of VSRs.
+ . */
+ if (uses_dfp128_output) {
+ if (verbose) print_vsr(28);
+ if (verbose) print_vsr(29);
+ value1 = get_vsrhd_vs28();
+ value3 = get_vsrhd_vs29();
+ dissect_dfp128_float(value1,value3);
+ } else {
+ if (debug_show_raw_values) generic_print_float_as_hex(frt);
+ printf(" %e",frt);
+ if (has_frtp) {
+ if (debug_show_raw_values) generic_print_float_as_hex(frtp);
+ printf(" %e",frtp);
+ }
+ }
+ }
+}
+
+/* implementation detail.. FRS and FRB use the same set of regs. */
+static void print_frs_or_frb() {
+ unsigned long long vsrvalue1,vsrvalue3;
+ if (debug_show_labels) {
+ if (has_frs) printf(" frs%s:",has_frsp?"p":"" );
+ if (has_frb) printf(" frb%s:",has_frbp?"p":"" );
+ }
+ if (uses_dfp128_input) {
+ if (verbose) print_vsr(26);
+ if (verbose) print_vsr(27);
+ vsrvalue1 = get_vsrhd_vs26();
+ vsrvalue3 = get_vsrhd_vs27();
+ dissect_dfp128_float(vsrvalue1,vsrvalue3);
+ } else if (instruction_is_dp) {
+ generic_print_double_as_hex(frsb);
+ generic_print_double_as_hex(frsbp);
+ } else if (instruction_is_sp) {
+ generic_print_float_as_hex(frsb);
+ generic_print_float_as_hex(frsbp);
+ } else {
+ printf(" %18.8e", frsb);
+ printf(" %18.8e", frsbp);
+ }
+}
+
+static void print_ra() {
+ if (debug_show_labels) printf(" ra:");
+ /* special case for when ra == &buffer. */
+ if ((void *)ra == &buffer )
+ printf(" (&buffer)");
+ else if ((void *)ra != &buffer || debug_show_raw_values) {
+ printf(" %lx", ra);
+ }
+}
+
+static void print_rb() {
+ if (debug_show_labels) printf(" rb:");
+ if ((void *)rb == &buffer)
+ printf(" (&buffer)");
+ else
+ printf(" %lx", rb);
+}
+
+static void print_rc() {
+ if (debug_show_labels) printf(" rc:");
+ printf(" %lx", rc);
+}
+
+static void print_rs() {
+ if (debug_show_labels) printf(" rs:");
+ printf(" %lx", rs);
+ if (has_rsp) {
+ if (debug_show_labels) printf(" rsp:");
+ printf(" %lx",rsp);
+ }
+}
+
+static void print_rt() {
+ if (debug_show_labels) printf(" rt%s:",has_rtp?"p":"");
+ printf(" %16lx",rt);
+ if (has_rtp) {
+ printf(" %16lx",rtp);
+ }
+}
+
+static void print_vra() {
+ if (debug_show_labels) printf(" vra:");
+ printf(" %016lx,%016lx", vra[0], vra[1]);
+}
+
+static void print_vrb() {
+ if (debug_show_labels) printf(" vrb:");
+ printf(" %016lx,%016lx", vrb[0], vrb[1]);
+}
+
+static void print_vrc() {
+ if (debug_show_labels) printf(" vrc:");
+ printf(" %016lx,%016lx", vrc[0], vrc[1]);
+}
+
+/* for VRM, don't print leading zeros for better visibility of diffs */
+static void print_vrm() {
+ if (debug_show_labels) printf(" vrm:");
+ printf(" %16lx,%16lx", vrm[0],vrm[1]);
+}
+
+static void print_vrt() {
+ if (debug_show_labels) printf(" vrt:");
+ if (debug_show_raw_values || (output_mask && uses_load_buffer )) {
+ printf(" %16lx,",vrt[1]);
+ printf( "%016lx",vrt[0]);
+ }
+ if (!post_test) return;
+ if (!output_mask) {
+ printf(" %16lx,",vrt[1]);
+ printf("%016lx",vrt[0]);
+ } else {
+ /* there is a mask requiring special handling. */
+ if (instruction_is_dp) {
+ if (output_mask&DP0)
+ special_print_dp_value(vrt[1]);
+ if (output_mask&DP1)
+ special_print_dp_value(vrt[0]);
+ }
+ if (instruction_is_sp) {
+ if (output_mask&SP0)
+ special_print_sp_value(0xffffffff&vrt[1]>>32);
+ if (output_mask&SP1)
+ special_print_sp_value(0xffffffff&vrt[1]);
+ if (output_mask&SP2)
+ special_print_sp_value(0xffffffff&vrt[0]>>32);
+ if (output_mask&SP3)
+ special_print_sp_value(0xffffffff&vrt[0]);
+ }
+ }
+}
+
+static void print_xa_or_xc() {
+ if (has_xa) {
+ if (debug_show_labels) printf(" vec_xa:");
+ printf(" %016lx,", vec_xa[0] );
+ printf("%016lx", vec_xa[1] );
+ }
+ if (has_xc | has_xap) { // Note that xap is shared with xc.
+ if (debug_show_labels) printf(" vec_x%s",has_xc?"c":"ap");
+ printf(" %016lx,", vec_xc[0] );
+ printf("%016lx", vec_xc[1] );
+ }
+}
+
+static void print_xb() {
+ if (debug_show_labels) printf(" vec_xb:");
+ if (instruction_is_sp_estimate) {
+ print_vec_as_sp(vec_xb[0]);
+ printf(",");
+ print_vec_as_sp(vec_xb[1]);
+ } else {
+ printf(" %016lx,", vec_xb[0] );
+ printf("%016lx", vec_xb[1] );
+ }
+}
+
+static void print_xs() {
+ if (debug_show_labels) printf(" vec_xs:");
+ printf(" %016lx,", vec_xs[0] );
+ printf("%016lx", vec_xs[1] );
+}
+
+//fixme - consolidate this with print_xt variation.
+static void print_xtp() {
+if (debug_show_labels) printf(" vec_xtp:" );
+ printf(" %16lx",XTp0[0]);
+ printf(" %16lx",XTp0[1]);
+ printf(" %16lx",XTp1[0]);
+ printf(" %16lx",XTp1[1]);
+}
+
+static void print_xsp() {
+ // Xsp uses the same pair of regs as xtp does.
+ print_xtp();
+}
+
+static void print_xt() {
+if (debug_show_labels) printf(" vec_xt:" );
+ if (debug_show_raw_values) {
+ printf(" %16lx",vec_xt[0]);
+ printf(" %16lx",vec_xt[1]);
+ }
+ // Don't print the xt value unless we are post-instruction test.
+ if (!post_test) return;
+ if (!output_mask ) {
+ if (vec_xt[0]==(unsigned long)&buffer) printf(" (&buffer) ");
+ else printf(" %16lx",vec_xt[0]);
+ if (vec_xt[1]==(unsigned long)&buffer) printf(" (&buffer) ");
+ else printf(" %16lx",vec_xt[1]);
+ if (has_xtp) {
+ printf(" %16lx",XTp0[0]);
+ printf(" %16lx",XTp0[1]);
+ printf(" %16lx",XTp1[0]);
+ printf(" %16lx",XTp1[1]);
+ }
+ } else {
+ /* there is a mask requiring special handling. */
+ if (instruction_is_dp) {
+ if (output_mask&0b100000)
+ special_print_dp_value(vec_xt[0]);
+ if (output_mask&0b010000)
+ special_print_dp_value(vec_xt[1]);
+ }
+ if (instruction_is_sp) {
+ if (output_mask&0b1000)
+ special_print_sp_value(0xffffffff&vec_xt[0]>>32);
+ else print_undefined();
+ if (output_mask&0b0100)
+ special_print_sp_value(0xffffffff&vec_xt[0]);
+ else print_undefined();
+ if (output_mask&0b0010)
+ special_print_sp_value(0xffffffff&vec_xt[1]>>32);
+ else print_undefined();
+ if (output_mask&0b0001)
+ special_print_sp_value(0xffffffff&vec_xt[1]);
+ else print_undefined();
+ }
+ if (instruction_is_b16) {
+ if (output_mask&B16_0) special_print_bf16_value(0xffffff&(vec_xt[0]>>48)); else print_undefined();
+ if (output_mask&B16_1) special_print_bf16_value(0xffffff&(vec_xt[0]>>32)); else print_undefined();
+ if (output_mask&B16_2) special_print_bf16_value(0xffffff&(vec_xt[0]>>16)); else print_undefined();
+ if (output_mask&B16_3) special_print_bf16_value(0xffffff&(vec_xt[0] )); else print_undefined();
+ if (output_mask&B16_4) special_print_bf16_value(0xffffff&(vec_xt[1]>> 48)); else print_undefined();
+ if (output_mask&B16_5) special_print_bf16_value(0xffffff&(vec_xt[1]>> 32)); else print_undefined();
+ if (ou...
[truncated message content] |
|
From: Carl L. <ce...@us...> - 2020-06-18 19:42:12
|
Julian:
This patch adds support for prefix versions of the existing addi and a
number of load/store instructions. The prefixed versions of the
existing instructions have expanded immediate values and some
additional functionality like PC based load and store.
The existing instruction support exists in a number of functions in
VEX/priv/guest_ppc_toIR.c for example function foo(). I created a new
function foo_prefix() to handle the instructions that have prefixed
versions. I moved the existing word support from function foo() to
foo_prefix() and then added the additional prefix functionality for the
various instructions. This was done for ease of implementation as
there is a lot of overlap in the support for word and prefix versions
of a given instruction. There is also some new prefix functionality
that is common to all prefix instructions. It also helps reduce the
size of some of the existing functions. Some of them have gotten
rather large.
Please let me know if you have comments. Thanks.
Carl Love
------------------------------------
Add prefixed support for the following word instructions.
addi Add Immediate
lbz Load Byte & Zero
ld Load Doubleword
lfd Load Floating Double
lfs Load Floating Single
lha Load Halfword Algebraic
lhz Load Halfword & Zero
lq Load Quadword
lwa Load Word Algebraic
lwz Load Word & Zero
lxsd Load VSX Scalar Doubleword
lxssp Load VSX Scalar Single-Precision
lxv Load VSX Vector
stb Store Byte
std Store Doubleword
stfd Store Floating Double
stfs Store Floating Single
sth Store Halfword
stq Store Quadword
stw Store Word
stxsd Store VSX Scalar Doubleword
stxssp Store VSX Scalar Single-Precision
stxv Store VSX Vector
---
VEX/priv/guest_ppc_toIR.c | 1581 ++++++++++++++++++++++++++++---------
1 file changed, 1215 insertions(+), 366 deletions(-)
diff --git a/VEX/priv/guest_ppc_toIR.c b/VEX/priv/guest_ppc_toIR.c
index 98653b396..7924b876c 100644
--- a/VEX/priv/guest_ppc_toIR.c
+++ b/VEX/priv/guest_ppc_toIR.c
@@ -372,6 +372,11 @@ static UInt ifieldOPClo8 ( UInt instr) {
return IFIELD( instr, 1, 8 );
}
+/* Extract 4-bit secondary opcode, instr[5:1] */
+static UInt ifieldOPClo4 ( UInt instr) {
+ return IFIELD( instr, 0, 4 );
+}
+
/* Extract 5-bit secondary opcode, instr[5:1] */
static UInt ifieldOPClo5 ( UInt instr) {
return IFIELD( instr, 1, 5 );
@@ -387,6 +392,15 @@ static UChar ifieldRegDS( UInt instr ) {
return toUChar( IFIELD( instr, 21, 5 ) );
}
+/* Extract XTp (destination register) field, instr[25:22, 21] */
+static UChar ifieldRegXTp ( UInt instr )
+{
+ UChar TX = toUChar (IFIELD (instr, 21, 1));
+ UChar Tp = toUChar (IFIELD (instr, 22, 4));
+ /* XTp = 32 * TX + 2* Tp; Only even values of XTp can be encoded. */
+ return (TX << 5) | (Tp << 1);
+}
+
/* Extract XT (destination register) field, instr[0,25:21] */
static UChar ifieldRegXT ( UInt instr )
{
@@ -3052,6 +3066,12 @@ static void set_XER_OV_OV32_ADDEX ( IRType ty, IRExpr* res,
/*-----------------------------------------------------------*/
/*--- Prefix instruction helpers ---*/
/*-----------------------------------------------------------*/
+#define DFORM_IMMASK 0xffffffff
+#define DSFORM_IMMASK 0xfffffffc
+#define DQFORM_IMMASK 0xfffffff0
+
+#define ISA_3_1_PREFIX_CHECK if (prefixInstr) {if (!allow_isa_3_1) goto decode_noIsa3_1;}
+
#define ENABLE_PREFIX_CHECK 1
#if ENABLE_PREFIX_CHECK
@@ -3075,6 +3095,50 @@ static void set_XER_OV_OV32_ADDEX ( IRType ty, IRExpr* res,
#define pType2 2 /* Modified Load/Store Instructions */
#define pType3 3 /* Modified Register-to-Register Instructions */
+/* Extract unsigned from prefix instr[17:0] */
+static UInt ifieldUIMM18 ( UInt instr ) {
+ return instr & 0x3FFFF;
+}
+
+static ULong extend_s_34to64 ( UInt x )
+{
+ return (ULong)((((Long)x) << 30) >> 30);
+}
+
+static UChar PrefixType( UInt instr ) {
+ return toUChar( IFIELD( instr, 24, 2 ) );
+}
+
+static UChar ifieldR( UInt instr ) {
+ return toUChar( IFIELD( instr, 20, 1 ) );
+}
+
+/* Sign extend imm34 -> IRExpr* */
+static IRExpr* mkSzExtendS34 ( UInt imm64 )
+{
+ return ( mkU64(extend_s_34to64(imm64)));
+}
+
+/* Prefix instsruction effective address calc: (rA + simm) */
+static IRExpr* ea_rA_simm34 ( UInt rA, UInt simm34 )
+{
+ vassert(rA < 32);
+ vassert(mode64);
+ return binop(Iop_Add64, getIReg(rA), mkSzExtendS34(simm34));
+}
+
+/* Standard prefix instruction effective address calc: (rA|0) + simm16 */
+static IRExpr* ea_rAor0_simm34 ( UInt rA, UInt simm34 )
+{
+ vassert(rA < 32);
+ vassert(mode64);
+ if (rA == 0) {
+ return mkSzExtendS34(simm34);
+ } else {
+ return ea_rA_simm34( rA, simm34 );
+ }
+}
+
static int prefix_instruction ( UInt instr )
{
/* Format of first 4 bytes of prefix instruction
@@ -3086,6 +3150,44 @@ static int prefix_instruction ( UInt instr )
return False;
}
+/* standard offset calculation, check prefix type */
+static IRExpr* calculate_prefix_EA ( UInt prefixInstr, UInt suffixInstr,
+ UChar rA_addr, UInt ptype,
+ UInt immediate_mask,
+ UInt *immediate_val,
+ UInt *R )
+{
+ IRType ty = Ity_I64;
+ UInt d0 = ifieldUIMM18(prefixInstr); // Will be zero for word inst
+ UInt d1 = ifieldUIMM16(suffixInstr) & immediate_mask;
+ UInt D = CONCAT( d0, d1, 16 );
+ Bool prefix = prefix_instruction( prefixInstr );
+ IRTemp tmp = newTemp(ty);
+
+ if ( !prefix ) {
+ *immediate_val = extend_s_16to32( d1 );
+ assign( tmp, ea_rAor0_simm( rA_addr, d1 ) );
+
+ } else {
+ vassert( ty == Ity_I64 ); // prefix instructions must be 64-bit
+ vassert( (ptype == pType0) || (ptype == pType2) );
+ *R = ifieldR( prefixInstr );
+ *immediate_val = extend_s_32to64( D );
+ assign( tmp, ea_rAor0_simm34( rA_addr, D ) );
+ }
+
+ /* Get the EA */
+ if ( *R == 0 )
+ return mkexpr ( tmp );
+
+ /* Add immediate value from instruction to the current instruction
+ address. guest_CIA_curr_instr is pointing at the prefix, use address
+ of the instruction prefix. */
+ return binop( Iop_Add64,
+ mkexpr ( tmp ),
+ mkU64( guest_CIA_curr_instr ) );
+}
+
/*------------------------------------------------------------*/
/*--- Read/write to guest-state --- */
/*------------------------------------------------------------*/
@@ -5267,6 +5369,77 @@ static Bool dis_int_mult_add ( UInt prefixInstr, UInt theInstr )
return True;
}
+static Bool dis_int_arith_prefix ( UInt prefixInstr, UInt theInstr )
+{
+
+ UChar opc1 = ifieldOPC(theInstr);
+ UChar rT_addr = ifieldRegDS(theInstr);
+ UChar rA_addr = ifieldRegA(theInstr);
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRTemp rA = newTemp(ty);
+ IRTemp rT = newTemp(ty);
+ IRTemp tmp = newTemp(ty);
+ IRTemp value = newTemp(ty);
+ UInt si0 = ifieldUIMM18(prefixInstr);
+ UInt si1 = ifieldUIMM16(theInstr); // AKA, SI
+ UInt ptype = PrefixType(prefixInstr);
+ Long simm16 = extend_s_16to64(si1);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt R = 0; // must be zero for word instruction
+
+ if ( !prefix ) {
+ assign( value, mkSzExtendS16( ty, si1 ));
+
+ } else {
+ vassert( ty == Ity_I64 ); // prefix instructions must be 64-bit
+ vassert( ptype == pType2 );
+
+ R = ifieldR(prefixInstr);
+ assign( value, mkSzExtendS34( CONCAT( si0, si1, 16 )));
+ }
+
+ assign( rA, getIReg(rA_addr) );
+
+ switch (opc1) {
+ /* D-Form */
+
+ case 0x0E: // addi (Add Immediate, PPC32 p350)
+ // li rD,val == addi rD,0,val
+ // la disp(rA) == addi rD,rA,disp
+
+ if ( rA_addr == 0 ) {
+ pDIP(prefix, "li r%u,%d", rT_addr, (Int)simm16);
+ DIPn(prefix);
+ assign( tmp, mkexpr( value ) );
+
+ } else {
+ pDIP(prefix, "addi r%u,r%u,%d", rT_addr, rA_addr, (Int)simm16);
+ DIPp(prefix, ",%u", R);
+ assign( tmp, binop( mkSzOp(ty, Iop_Add8), mkexpr( rA ), mkexpr( value ) ) );
+ }
+
+ if ( R == 0 )
+ assign( rT, mkexpr( tmp ) );
+ else
+ /* Add immediate value from instruction to the current instruction addr.
+ guest_CIA_curr_instr is pointing at the prefix, use address of the
+ instruction prefix. */
+ assign( rT, binop( Iop_Add64,
+ mkU64( mkSzAddr( Ity_I64, guest_CIA_curr_instr ) ),
+ mkexpr( tmp ) ) );
+
+ break;
+
+ default:
+ vex_printf("dis_int_arith_prefix(ppc)(opc1)\n");
+ return False;
+ }
+
+ putIReg( rT_addr, mkexpr(rT) );
+
+ return True;
+}
+
static Bool dis_int_arith ( UInt prefixInstr, UInt theInstr )
{
/* D-Form, XO-Form */
@@ -7434,6 +7607,225 @@ static Bool dis_int_rot ( UInt prefixInstr, UInt theInstr )
/*
Integer Load Instructions
*/
+static Bool dis_int_load_ds_form_prefix ( UInt prefixInstr,
+ UInt theInstr )
+{
+ /* DS-Form Prefixed versions */
+ UChar opc1 = ifieldOPC(theInstr);
+ UChar rT_addr = ifieldRegDS(theInstr);
+ UChar rA_addr = ifieldRegA(theInstr);
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ UChar b0 = ifieldBIT0(theInstr);
+ UChar b1 = ifieldBIT1(theInstr);
+ IRTemp EA = newTemp(ty);
+ UInt ptype = PrefixType(prefixInstr);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt immediate_val = 0;
+ UInt R = 0;
+
+ /* Some of these instructions have different encodings for their word
+ versions and their prefix versions. */
+
+ if (opc1 == 0x29) { //plwa
+ pDIP(prefix, "lwa r%u,%u(r%u)", rT_addr, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr, rA_addr,
+ ptype, DSFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ putIReg( rT_addr,
+ unop(Iop_32Sto64, load( Ity_I32, mkexpr( EA ) ) ) );
+ return True;
+
+ } else if (opc1 == 0x39) { // pld
+ pDIP(prefix, "ld r%u,%u(r%u)", rT_addr, immediate_val, rA_addr);
+ DIPn(prefix);
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DSFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ putIReg( rT_addr, load( Ity_I64, mkexpr( EA ) ) );
+ return True;
+
+ } else if (opc1 == 0x3A) {
+ /* Word version DS Form - 64bit Loads. In each case EA will have been
+ formed with the lowest 2 bits masked off the immediate offset. */
+ UInt uimm16 = ifieldUIMM16(theInstr);
+ Int simm16 = extend_s_16to32(uimm16);
+
+ simm16 = simm16 & 0xFFFFFFFC;
+ assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
+
+ switch ((b1<<1) | b0) {
+ case 0x0: // ld (Load DWord, PPC64 p472)
+ pDIP(prefix, "ld r%u,%u(r%u)", rT_addr, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+ putIReg( rT_addr, load( Ity_I64, mkexpr( EA ) ) );
+ break;
+
+ case 0x1: // ldu (Load DWord, Update, PPC64 p474)
+ /* There is no prefixed version of these instructions. */
+ if (rA_addr == 0 || rA_addr == rT_addr) {
+ vex_printf("dis_int_load(ppc)(ldu,rA_addr|rT_addr)\n");
+ return False;
+ }
+ DIP("ldu r%u,%u(r%u)\n", rT_addr, immediate_val, rA_addr);
+
+ putIReg( rT_addr, load( Ity_I64, mkexpr( EA ) ) );
+ putIReg( rA_addr, mkexpr( EA ) );
+ break;
+
+ case 0x2: // lwa (Load Word Alg, PPC64 p499)
+ pDIP(prefix, "lwa r%u,%u(r%u)", rT_addr, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+
+ putIReg( rT_addr,
+ unop(Iop_32Sto64, load( Ity_I32, mkexpr( EA ) ) ) );
+ break;
+
+ default:
+ vex_printf("dis_int_load_ds_form_prefix(ppc)(0x3A, opc2)\n");
+ return False;
+ }
+ return True;
+ }
+ return False;
+}
+
+static Bool dis_int_load_prefix ( UInt prefixInstr, UInt theInstr )
+{
+ /* D-Form, X-Form, Prefixed versions */
+ UChar opc1 = ifieldOPC(theInstr);
+ UChar rT_addr = ifieldRegDS(theInstr);
+ UChar rA_addr = ifieldRegA(theInstr);
+
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRTemp EA = newTemp(ty);
+ UInt ptype = PrefixType(prefixInstr);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt size = 0;
+ UInt immediate_val = 0;
+ UInt R = 0;
+ IRExpr* val;
+
+ if (opc1 == 0x22) {
+ // byte loads
+ size = Ity_I8;
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ } else if (( opc1 == 0x28 ) || ( opc1 == 0x2A )) {
+ // half word loads lwz, plwz, lha, plha
+ size = Ity_I16;
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ } else if (opc1 == 0x20 ) {
+ // word load
+ size = Ity_I32;
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ } else if (opc1 == 0x38 ) { // lq, plq
+ // word load
+ size = Ity_I64;
+
+ if (!prefix)
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DQFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ else
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DFORM_IMMASK,
+ &immediate_val, &R ) );
+ }
+
+ val = load( size, mkexpr( EA ) );
+
+ /* Store the load value in the destination and print the instruction
+ details. */
+ switch (opc1) {
+ case 0x20: // lwz (Load W & Zero, PPC32 p460)
+ pDIP( prefix, "lwz r%u,%u(r%u)", rT_addr, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+
+ putIReg( rT_addr, mkWidenFrom32(ty, val, False) );
+ break;
+
+ case 0x22: // lbz (Load B & Zero, PPC32 p433)
+ pDIP( prefix, "lbz r%u,%u(r%u)", rT_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+
+ putIReg( rT_addr, mkWidenFrom8( ty, val, False ) );
+ break;
+
+ case 0x28: // lhz (Load HW & Zero, PPC32 p450)
+ pDIP( prefix, "lhz r%u,%u(r%u)", rT_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+
+ putIReg( rT_addr, mkWidenFrom16( ty, val, False ) );
+ break;
+
+ case 0x2A: // lha (Load HW Alg, PPC32 p445)
+ pDIP( prefix, "lha r%u,%u(r%u)", rT_addr, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+ putIReg( rT_addr, mkWidenFrom16(ty, val, True) );
+ break;
+
+ case 0x38: { // lq, plq
+ IRTemp high = newTemp(ty);
+ IRTemp low = newTemp(ty);
+ /* DQ Form - 128bit Loads. Lowest bits [1:0] are the PT field. */
+ pDIP(prefix, "lq r%u,%u(r%u)", rT_addr, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+ /* NOTE: there are some changes to XER[41:42] that have not been
+ * implemented.
+ */
+ //trap if EA misaligned on 16 byte address
+ if (mode64) {
+ if (host_endness == VexEndnessBE) {
+ assign(high, load(ty, mkexpr( EA ) ) );
+ assign(low, load(ty, binop( Iop_Add64,
+ mkexpr( EA ),
+ mkU64( 8 ) ) ) );
+ } else {
+ assign(low, load(ty, mkexpr( EA ) ) );
+ assign(high, load(ty, binop( Iop_Add64,
+ mkexpr( EA ),
+ mkU64( 8 ) ) ) );
+ }
+ } else {
+ assign(high, load(ty, binop( Iop_Add32,
+ mkexpr( EA ),
+ mkU32( 4 ) ) ) );
+ assign(low, load(ty, binop( Iop_Add32,
+ mkexpr( EA ),
+ mkU32( 12 ) ) ) );
+ }
+
+ /* Note, the load order for lq is the same for BE and LE. However,
+ plq does an endian aware load. */
+ if (prefix &&( host_endness == VexEndnessLE )) {
+ putIReg( rT_addr, mkexpr( low) );
+ putIReg( rT_addr+1, mkexpr( high) );
+ } else {
+ putIReg( rT_addr, mkexpr( high) );
+ putIReg( rT_addr+1, mkexpr( low) );
+ }
+ break;
+ }
+
+ default:
+ vex_printf("dis_int_load_prefix(ppc)(opc1)\n");
+ return False;
+ }
+ return True;
+}
+
static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
{
/* D-Form, X-Form, DS-Form */
@@ -7443,7 +7835,6 @@ static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
UInt uimm16 = ifieldUIMM16(theInstr);
UChar rB_addr = ifieldRegB(theInstr);
UInt opc2 = ifieldOPClo10(theInstr);
- UChar b1 = ifieldBIT1(theInstr);
UChar b0 = ifieldBIT0(theInstr);
Int simm16 = extend_s_16to32(uimm16);
@@ -7463,23 +7854,12 @@ static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
simm16 = simm16 & 0xFFFFFFF0;
assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
break;
- case 0x3A: // immediate offset: 64bit: ld/ldu/lwa: mask off
- // lowest 2 bits of immediate before forming EA
- simm16 = simm16 & 0xFFFFFFFC;
- assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
- break;
default: // immediate offset
assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
break;
}
switch (opc1) {
- case 0x22: // lbz (Load B & Zero, PPC32 p433)
- DIP("lbz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
- val = load(Ity_I8, mkexpr(EA));
- putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
- break;
-
case 0x23: // lbzu (Load B & Zero, Update, PPC32 p434)
if (rA_addr == 0 || rA_addr == rD_addr) {
vex_printf("dis_int_load(ppc)(lbzu,rA_addr|rD_addr)\n");
@@ -7491,12 +7871,6 @@ static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
putIReg( rA_addr, mkexpr(EA) );
break;
- case 0x2A: // lha (Load HW Alg, PPC32 p445)
- DIP("lha r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
- val = load(Ity_I16, mkexpr(EA));
- putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
- break;
-
case 0x2B: // lhau (Load HW Alg, Update, PPC32 p446)
if (rA_addr == 0 || rA_addr == rD_addr) {
vex_printf("dis_int_load(ppc)(lhau,rA_addr|rD_addr)\n");
@@ -7508,12 +7882,6 @@ static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
putIReg( rA_addr, mkexpr(EA) );
break;
- case 0x28: // lhz (Load HW & Zero, PPC32 p450)
- DIP("lhz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
- val = load(Ity_I16, mkexpr(EA));
- putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
- break;
-
case 0x29: // lhzu (Load HW & and Zero, Update, PPC32 p451)
if (rA_addr == 0 || rA_addr == rD_addr) {
vex_printf("dis_int_load(ppc)(lhzu,rA_addr|rD_addr)\n");
@@ -7525,12 +7893,6 @@ static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
putIReg( rA_addr, mkexpr(EA) );
break;
- case 0x20: // lwz (Load W & Zero, PPC32 p460)
- DIP("lwz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
- val = load(Ity_I32, mkexpr(EA));
- putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
- break;
-
case 0x21: // lwzu (Load W & Zero, Update, PPC32 p461))
if (rA_addr == 0 || rA_addr == rD_addr) {
vex_printf("dis_int_load(ppc)(lwzu,rA_addr|rD_addr)\n");
@@ -7658,71 +8020,6 @@ static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
}
break;
- /* DS Form - 64bit Loads. In each case EA will have been formed
- with the lowest 2 bits masked off the immediate offset. */
- case 0x3A:
- switch ((b1<<1) | b0) {
- case 0x0: // ld (Load DWord, PPC64 p472)
- DIP("ld r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
- putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
- break;
-
- case 0x1: // ldu (Load DWord, Update, PPC64 p474)
- if (rA_addr == 0 || rA_addr == rD_addr) {
- vex_printf("dis_int_load(ppc)(ldu,rA_addr|rD_addr)\n");
- return False;
- }
- DIP("ldu r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
- putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
- putIReg( rA_addr, mkexpr(EA) );
- break;
-
- case 0x2: // lwa (Load Word Alg, PPC64 p499)
- DIP("lwa r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
- putIReg( rD_addr,
- unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
- break;
-
- default:
- vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
- return False;
- }
- break;
-
- case 0x38: {
- IRTemp high = newTemp(ty);
- IRTemp low = newTemp(ty);
- /* DQ Form - 128bit Loads. Lowest bits [1:0] are the PT field. */
- DIP("lq r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
- /* NOTE: there are some changes to XER[41:42] that have not been
- * implemented.
- */
- // trap if EA misaligned on 16 byte address
- if (mode64) {
- if (host_endness == VexEndnessBE) {
- assign(high, load(ty, mkexpr( EA ) ) );
- assign(low, load(ty, binop( Iop_Add64,
- mkexpr( EA ),
- mkU64( 8 ) ) ) );
- } else {
- assign(low, load(ty, mkexpr( EA ) ) );
- assign(high, load(ty, binop( Iop_Add64,
- mkexpr( EA ),
- mkU64( 8 ) ) ) );
- }
- } else {
- assign(high, load(ty, binop( Iop_Add32,
- mkexpr( EA ),
- mkU32( 4 ) ) ) );
- assign(low, load(ty, binop( Iop_Add32,
- mkexpr( EA ),
- mkU32( 12 ) ) ) );
- }
- gen_SIGBUS_if_misaligned( EA, 16 );
- putIReg( rD_addr, mkexpr( high) );
- putIReg( rD_addr+1, mkexpr( low) );
- break;
- }
default:
vex_printf("dis_int_load(ppc)(opc1)\n");
return False;
@@ -7735,24 +8032,190 @@ static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
/*
Integer Store Instructions
*/
-static Bool dis_int_store ( UInt prefixInstr, UInt theInstr, const VexAbiInfo* vbi )
+static Bool dis_int_store_ds_prefix ( UInt prefixInstr,
+ UInt theInstr, const VexAbiInfo* vbi)
{
- /* D-Form, X-Form, DS-Form */
UChar opc1 = ifieldOPC(theInstr);
UInt rS_addr = ifieldRegDS(theInstr);
UInt rA_addr = ifieldRegA(theInstr);
- UInt uimm16 = ifieldUIMM16(theInstr);
- UInt rB_addr = ifieldRegB(theInstr);
- UInt opc2 = ifieldOPClo10(theInstr);
- UChar b1 = ifieldBIT1(theInstr);
UChar b0 = ifieldBIT0(theInstr);
-
+ UChar b1 = ifieldBIT1(theInstr);
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRTemp rS = newTemp(ty);
+ IRTemp EA = newTemp(ty);
+ UInt ptype = PrefixType(prefixInstr);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt R = 0; // must be zero for word instruction
+ UInt immediate_val = 0;
+ Int simm16 = extend_s_16to32(ifieldUIMM16(theInstr));
+
+ if (opc1 == 0x3C) {
+ // force opc2 to 2 to map pstq to stq inst
+ b0 = 0;
+ b1 = 1;
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr, rA_addr,
+ ptype, DSFORM_IMMASK,
+ &immediate_val, &R ) );
+ } else if (opc1 == 0x3D) {
+ // force opc2 to 0 to map pstd to std inst
+ b0 = 0;
+ b1 = 0;
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr, rA_addr,
+ ptype, DSFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ } else if ( opc1 == 0x3 ) {
+
+ assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
+
+ } else if ( opc1 == 0x3E ) {
+ // lowest 2 bits of immediate before forming EA
+ immediate_val = simm16 & 0xFFFFFFFC;
+ assign( EA, ea_rAor0_simm( rA_addr, immediate_val ) );
+
+ } else {
+ return False;
+ }
+
+ assign( rS, getIReg(rS_addr) );
+
+ /* DS Form - 64bit Stores. In each case EA will have been formed
+ with the lowest 2 bits masked off the immediate offset. */
+ switch ((b1<<1) | b0) {
+ case 0x0: // std (Store DWord, PPC64 p580)
+ if (!mode64)
+ return False;
+
+ pDIP( prefix,"std r%u,%u(r%u)", rS_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ store( mkexpr(EA), mkexpr(rS) );
+ break;
+
+ case 0x1: // stdu (Store DWord, Update, PPC64 p583)
+ /* Note this instruction is handled here but it isn't actually a
+ prefix instruction. Just makes the parsing easier to handle it
+ here. */
+ if (!mode64)
+ return False;
+
+ DIP("stdu r%u,%u(r%u)\n", rS_addr, immediate_val, rA_addr);
+ putIReg( rA_addr, mkexpr(EA) );
+ store( mkexpr(EA), mkexpr(rS) );
+ break;
+
+ case 0x2: // stq, pstq (Store QuadWord, Update, PPC64 p583)
+ {
+ IRTemp EA_hi = newTemp(ty);
+ IRTemp EA_lo = newTemp(ty);
+
+ pDIP( prefix, "stq r%u,%u(r%u)", rS_addr, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+
+ if (mode64) {
+ if (host_endness == VexEndnessBE) {
+
+ /* upper 64-bits */
+ assign( EA_hi, ea_rAor0_simm( rA_addr, immediate_val ) );
+
+ /* lower 64-bits */
+ assign( EA_lo, ea_rAor0_simm( rA_addr, immediate_val+8 ) );
+ } else {
+ /* upper 64-bits */
+ assign( EA_hi, ea_rAor0_simm( rA_addr, immediate_val+8 ) );
+
+ /* lower 64-bits */
+ assign( EA_lo, ea_rAor0_simm( rA_addr, immediate_val ) );
+ }
+ } else {
+ /* upper half of upper 64-bits */
+ assign( EA_hi, ea_rAor0_simm( rA_addr, immediate_val+4 ) );
+
+ /* lower half of upper 64-bits */
+ assign( EA_lo, ea_rAor0_simm( rA_addr, immediate_val+12 ) );
+ }
+
+ /* Note, the store order for stq instruction is the same for BE
+ and LE. The store order for the pstq instruction is endian aware
+ store. */
+ if (prefix &&( host_endness == VexEndnessLE )) {
+ // LE and pstq
+ store( mkexpr(EA_hi), getIReg( rS_addr+1 ) );
+ store( mkexpr(EA_lo), mkexpr(rS) );
+ } else {
+ store( mkexpr(EA_hi), mkexpr(rS) );
+ store( mkexpr(EA_lo), getIReg( rS_addr+1 ) );
+ }
+ break;
+ }
+ default:
+ vex_printf("dis_int_store_ds_prefix(ppc)(opc1)\n");
+ return False;
+ }
+ return True;
+}
+
+static Bool dis_int_store_prefix ( UInt prefixInstr,
+ UInt theInstr, const VexAbiInfo* vbi)
+{
+ UChar opc1 = ifieldOPC(theInstr);
+ UInt rS_addr = ifieldRegDS(theInstr);
+ UInt rA_addr = ifieldRegA(theInstr);
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRTemp rS = newTemp(ty);
+ IRTemp EA = newTemp(ty);
+ UInt ptype = PrefixType(prefixInstr);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt immediate_val = 0;
+ UInt R = 0; // must be zero for word instruction
+
+ assign( rS, getIReg(rS_addr) );
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr, rA_addr,
+ ptype, DFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ switch (opc1) {
+ case 0x24: // stw (Store W, PPC32 p530)
+ pDIP( prefix, "stw r%u,%u(r%u)\n", rS_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
+ break;
+
+ case 0x26: // stb (Store B, PPC32 p509)
+ pDIP( prefix, "stb r%u,%u(r%u)", rS_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
+ break;
+
+ case 0x2C: // sth (Store HW, PPC32 p522)
+ pDIP( prefix, "sth r%u,%u(r%u)", rS_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
+ break;
+
+ default:
+ vex_printf("dis_int_store_prefix(ppc)(opc1)\n");
+ return False;
+ }
+ return True;
+}
+
+static Bool dis_int_store ( UInt prefixInstr, UInt theInstr, const VexAbiInfo* vbi )
+{
+ /* D-Form, X-Form, DS-Form */
+ UChar opc1 = ifieldOPC(theInstr);
+ UInt rS_addr = ifieldRegDS(theInstr);
+ UInt rA_addr = ifieldRegA(theInstr);
+ UInt uimm16 = ifieldUIMM16(theInstr);
+ UInt rB_addr = ifieldRegB(theInstr);
+ UInt opc2 = ifieldOPClo10(theInstr);
+ UChar b0 = ifieldBIT0(theInstr);
+
Int simm16 = extend_s_16to32(uimm16);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp rS = newTemp(ty);
IRTemp rB = newTemp(ty);
IRTemp EA = newTemp(ty);
-
+
/* There is no prefixed version of these instructions. */
PREFIX_CHECK
@@ -7763,9 +8226,7 @@ static Bool dis_int_store ( UInt prefixInstr, UInt theInstr, const VexAbiInfo* v
case 0x1F: // register offset
assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
break;
- case 0x3E: // immediate offset: 64bit: std/stdu/stq: mask off
- // lowest 2 bits of immediate before forming EA
- simm16 = simm16 & 0xFFFFFFFC;
+
/* fallthrough */
default: // immediate offset
assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
@@ -7773,11 +8234,6 @@ static Bool dis_int_store ( UInt prefixInstr, UInt theInstr, const VexAbiInfo* v
}
switch (opc1) {
- case 0x26: // stb (Store B, PPC32 p509)
- DIP("stb r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
- store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
- break;
-
case 0x27: // stbu (Store B, Update, PPC32 p510)
if (rA_addr == 0 ) {
vex_printf("dis_int_store(ppc)(stbu,rA_addr)\n");
@@ -7788,11 +8244,6 @@ static Bool dis_int_store ( UInt prefixInstr, UInt theInstr, const VexAbiInfo* v
store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
break;
- case 0x2C: // sth (Store HW, PPC32 p522)
- DIP("sth r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
- store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
- break;
-
case 0x2D: // sthu (Store HW, Update, PPC32 p524)
if (rA_addr == 0) {
vex_printf("dis_int_store(ppc)(sthu,rA_addr)\n");
@@ -7894,64 +8345,6 @@ static Bool dis_int_store ( UInt prefixInstr, UInt theInstr, const VexAbiInfo* v
}
break;
- /* DS Form - 64bit Stores. In each case EA will have been formed
- with the lowest 2 bits masked off the immediate offset. */
- case 0x3E:
- switch ((b1<<1) | b0) {
- case 0x0: // std (Store DWord, PPC64 p580)
- if (!mode64)
- return False;
-
- DIP("std r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
- store( mkexpr(EA), mkexpr(rS) );
- break;
-
- case 0x1: // stdu (Store DWord, Update, PPC64 p583)
- if (!mode64)
- return False;
-
- DIP("stdu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
- putIReg( rA_addr, mkexpr(EA) );
- store( mkexpr(EA), mkexpr(rS) );
- break;
-
- case 0x2: { // stq (Store QuadWord, Update, PPC64 p583)
- IRTemp EA_hi = newTemp(ty);
- IRTemp EA_lo = newTemp(ty);
- DIP("stq r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
-
- if (mode64) {
- if (host_endness == VexEndnessBE) {
-
- /* upper 64-bits */
- assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
-
- /* lower 64-bits */
- assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+8 ) );
- } else {
- /* upper 64-bits */
- assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+8 ) );
-
- /* lower 64-bits */
- assign( EA_lo, ea_rAor0_simm( rA_addr, simm16 ) );
- }
- } else {
- /* upper half of upper 64-bits */
- assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+4 ) );
-
- /* lower half of upper 64-bits */
- assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+12 ) );
- }
- store( mkexpr(EA_hi), mkexpr(rS) );
- store( mkexpr(EA_lo), getIReg( rS_addr+1 ) );
- break;
- }
- default:
- vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
- return False;
- }
- break;
-
default:
vex_printf("dis_int_store(ppc)(opc1)\n");
return False;
@@ -10476,6 +10869,47 @@ static IRExpr * Complement_non_NaN( IRExpr * value, IRExpr * nan_mask )
/*
Floating Point Load Instructions
*/
+static Bool dis_fp_load_prefix ( UInt prefixInstr, UInt theInstr )
+{
+ /* X-Form, D-Form */
+ UChar opc1 = ifieldOPC(theInstr);
+ UChar frT_addr = ifieldRegDS(theInstr);
+ UChar rA_addr = ifieldRegA(theInstr);
+
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRTemp EA = newTemp(ty);
+ IRTemp rA = newTemp(ty);
+ UInt ptype = PrefixType(prefixInstr);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt R = 0; // must be zero for word instruction
+ UInt immediate_val = 0;
+
+ assign( rA, getIReg(rA_addr) );
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr, rA_addr,
+ ptype, DFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ switch (opc1) {
+ case 0x30: // lfs (Load Float Single, PPC32 p441)
+ pDIP( prefix, "lfs fr%u,%u(r%u)\n", frT_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ putFReg( frT_addr,
+ unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
+ break;
+
+ case 0x32: // lfd (Load Float Double, PPC32 p437)
+ pDIP( prefix, "lfd fr%u,%u(r%u)\n", frT_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ putFReg( frT_addr, load(Ity_F64, mkexpr(EA)) );
+ break;
+
+ default:
+ vex_printf("dis_fp_load_prefix(ppc)(opc1)\n");
+ return False;
+ }
+ return True;
+}
+
static Bool dis_fp_load ( UInt prefixInstr, UInt theInstr )
{
/* X-Form, D-Form */
@@ -10617,6 +11051,57 @@ static Bool dis_fp_load ( UInt prefixInstr, UInt theInstr )
/*
Floating Point Store Instructions
*/
+static Bool dis_fp_store_prefix ( UInt prefixInstr, UInt theInstr )
+{
+ /* X-Form, D-Form */
+ UChar opc1 = ifieldOPC(theInstr);
+ UChar frS_addr = ifieldRegDS(theInstr);
+ UChar rA_addr = ifieldRegA(theInstr);
+
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRTemp frS = newTemp(Ity_F64);
+ IRTemp EA = newTemp(ty);
+ IRTemp rA = newTemp(ty);
+ UInt ptype = PrefixType(prefixInstr);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt R = 0; // must be zero for word instruction
+ UInt immediate_val = 0;
+
+ assign( frS, getFReg( frS_addr ) );
+ assign( rA, getIReg( rA_addr ) );
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr, rA_addr,
+ ptype, DFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ /* These are straightforward from a status bits perspective: no
+ funny status or CR bits affected. For single precision stores,
+ the values are truncated and denormalised (not rounded) to turn
+ them into single precision values. */
+
+ switch (opc1) {
+
+ case 0x34: // stfs (Store Float Single, PPC32 p518)
+ pDIP( prefix, "stfs fr%u,%u(r%u)\n", frS_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ /* Use Iop_TruncF64asF32 to truncate and possible denormalise
+ the value to be stored in the correct way, without any
+ rounding. */
+ store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
+ break;
+
+ case 0x36: // stfd (Store Float Double, PPC32 p513)
+ pDIP( prefix, "stfd fr%u,%u(r%u)", frS_addr, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ store( mkexpr(EA), mkexpr(frS) );
+ break;
+
+ default:
+ vex_printf("dis_fp_store_prefix(ppc)(opc1)\n");
+ return False;
+ }
+ return True;
+}
+
static Bool dis_fp_store ( UInt prefixInstr, UInt theInstr )
{
/* X-Form, D-Form */
@@ -10648,16 +11133,6 @@ static Bool dis_fp_store ( UInt prefixInstr, UInt theInstr )
them into single precision values. */
switch (opc1) {
-
- case 0x34: // stfs (Store Float Single, PPC32 p518)
- DIP("stfs fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
- assign( EA, ea_rAor0_simm(rA_addr, simm16) );
- /* Use Iop_TruncF64asF32 to truncate and possible denormalise
- the value to be stored in the correct way, without any
- rounding. */
- store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
- break;
-
case 0x35: // stfsu (Store Float Single, Update, PPC32 p519)
if (rA_addr == 0)
return False;
@@ -10667,13 +11142,6 @@ static Bool dis_fp_store ( UInt prefixInstr, UInt theInstr )
store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
putIReg( rA_addr, mkexpr(EA) );
break;
-
- case 0x36: // stfd (Store Float Double, PPC32 p513)
- DIP("stfd fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
- assign( EA, ea_rAor0_simm(rA_addr, simm16) );
- store( mkexpr(EA), mkexpr(frS) );
- break;
-
case 0x37: // stfdu (Store Float Double, Update, PPC32 p514)
if (rA_addr == 0)
return False;
@@ -11719,6 +12187,7 @@ static Bool dis_fp_round ( UInt prefixInstr, UInt theInstr )
assign( frD, unop( Iop_F32toF64, binop( Iop_I64UtoF32, rm, mkexpr( r_tmp64 ) ) ) );
goto putFR;
}
+ return True;
}
@@ -11858,29 +12327,318 @@ static Bool dis_fp_round ( UInt prefixInstr, UInt theInstr )
));
break;
- default:
- vex_printf("dis_fp_round(ppc)(opc2)\n");
- return False;
- }
-putFR:
- putFReg( frD_addr, mkexpr(frD) );
+ default:
+ vex_printf("dis_fp_round(ppc)(opc2)\n");
+ return False;
+ }
+putFR:
+ putFReg( frD_addr, mkexpr(frD) );
+
+ if (set_FPRF) {
+ // XXX XXX XXX FIXME
+ // set FPRF from frD
+ }
+
+ if (flag_rC && clear_CR1) {
+ putCR321( 1, mkU8(0) );
+ putCR0( 1, mkU8(0) );
+ }
+
+ return True;
+}
+
+/*
+ Floating Point Pair Instructions
+*/
+static Bool dis_fp_pair_prefix ( UInt prefixInstr, UInt theInstr )
+{
+ /* X-Form/DS-Form */
+ UChar opc1 = ifieldOPC(theInstr);
+ UChar rA_addr = ifieldRegA(theInstr);
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRTemp EA = newTemp(ty);
+ IRTemp EA_16 = newTemp(ty);
+ UInt ptype = PrefixType(prefixInstr);
+ Bool prefix = prefix_instruction( prefixInstr );
+ UInt R = 0;
+ UInt immediate_val = 0;
+ UInt opc2;
+
+ switch (opc1) {
+ case 0x6:
+ {
+ UChar XTp = ifieldRegXTp(theInstr);
+ opc2 = ifieldOPClo4(theInstr);
+
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DQFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ switch (opc2) {
+
+ case 0:
+ {
+ /* Endian aware load */
+ pDIP( prefix, "lxvp %u,%u(%u)\n", XTp, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+
+ if (prefix && (R == 1) ) {
+ vex_printf("Illegal instruction R = 1; plxvp %u,%u(%u)\n",
+ XTp, immediate_val, rA_addr );
+ return False;
+ }
+
+ // address of next 128bits
+ assign( EA_16, binop( Iop_Add64, mkU64( 16), mkexpr( EA ) ) );
+ if (host_endness == VexEndnessLE) {
+ putVSReg( XTp, load( Ity_V128, mkexpr( EA ) ) );
+ putVSReg( XTp+1, load( Ity_V128, mkexpr( EA_16 ) ) );
+ } else {
+ putVSReg( XTp+1, load( Ity_V128, mkexpr( EA ) ) );
+ putVSReg( XTp, load( Ity_V128, mkexpr( EA_16 ) ) );
+ }
+ break;
+ }
+
+ case 1:
+ {
+ IRTemp EA_8 = newTemp(ty);
+ IRTemp EA_24 = newTemp(ty);
+ /* Endian aware store */
+ pDIP( prefix, "stxvp %u,%u(%u)\n", XTp, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+
+ if ( prefix && ( R == 1 ) ) {
+ vex_printf("Illegal instruction R = 1; pstxvp %u,%u(%u)\n",
+ XTp, immediate_val, rA_addr );
+ return False;
+ }
+
+ // address of next 128bits
+ assign( EA_8, binop( Iop_Add64, mkU64( 8 ), mkexpr( EA ) ) );
+ assign( EA_16, binop( Iop_Add64, mkU64( 16 ), mkexpr( EA ) ) );
+ assign( EA_24, binop( Iop_Add64, mkU64( 24 ), mkexpr( EA ) ) );
+
+ if (host_endness == VexEndnessBE) {
+ store( mkexpr( EA ), unop( Iop_V128to64, getVSReg( XTp ) ) );
+ store( mkexpr( EA_8 ), unop( Iop_V128HIto64, getVSReg( XTp ) ) );
+ store( mkexpr( EA_16 ), unop( Iop_V128to64, getVSReg( XTp+1 ) ) );
+ store( mkexpr( EA_24 ), unop( Iop_V128HIto64, getVSReg( XTp+1 ) ) );
+ } else {
+ store( mkexpr( EA ), unop( Iop_V128to64, getVSReg( XTp+1 ) ) );
+ store( mkexpr( EA_8 ), unop( Iop_V128HIto64, getVSReg( XTp+1 ) ) );
+ store( mkexpr( EA_16 ), unop( Iop_V128to64, getVSReg( XTp ) ) );
+ store( mkexpr( EA_24 ), unop( Iop_V128HIto64, getVSReg( XTp ) ) );
+ }
+ break;
+ }
+
+ default:
+ vex_printf("dis_fp_pair_prefix\n");
+ return False;
+ }
+ return True;
+ }
+ break;
+
+ case 0x2A: // plxsd
+ case 0x2B: // plxssp
+ case 0x39: // lxsd, lxssp
+ {
+ UChar vRT = ifieldRegDS(theInstr);
+ opc2 = ifieldOPC0o2(theInstr);
+ if (opc1 == 0x2A)
+ opc2 = 0x2; // map plxsd to lxsd inst
+
+ if (opc1 == 0x2B)
+ opc2 = 0x3; // map plxssp to lxssp inst
+
+ /* The word version uses the DS-form. */
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr, rA_addr,
+ ptype, DSFORM_IMMASK,
+ &immediate_val, &R ) );
+
+ switch(opc2) {
+ case 0x2: // lxsd (Load VSX Scalar Doubleword)
+ pDIP( prefix, "lxsd v%u,%u(r%u)\n", vRT, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+
+ putVSReg( vRT+32, binop( Iop_64HLtoV128,
+ load( Ity_I64, mkexpr( EA ) ),
+ mkU64( 0 ) ) );
+ return True;
+
+ case 0x3: // lxssp (Load VSX Scalar Single from memory,
+ // store as double in register)
+ pDIP( prefix, "lxssp v%u,%u(r%u)\n", vRT, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+
+ putVSReg( vRT+32,
+ binop( Iop_64HLtoV128,
+ unop( Iop_ReinterpF64asI64,
+ unop( Iop_F32toF64,
+ unop( Iop_ReinterpI32asF32,
+ load( Ity_I32, mkexpr( EA ) )
+ ) ) ),
+ mkU64( 0 ) ) );
+ return True;
+
+ default:
+ vex_printf("dis_fp_pair_prefix(ppc) : DS-form wrong opc2\n");
+ return False;
+ }
+ break;
+ }
+
+ case 0x2E: // pstxsd
+ case 0x2F: // pstxssp
+ case 0x3d: // lxv, stxv, stxsd, stxssp, pstd
+ case 0x32: // plxv (TX=0)
+ case 0x33: // plxv (TX=1)
+ case 0x36: // pstxv
+ {
+ UChar vRS = ifieldRegDS(theInstr);
+ UInt TX = IFIELD( theInstr, 3, 1); // default TX or SX bit field
+
+ opc2 = IFIELD(theInstr, 0, 3);
+
+ if ((opc1 == 0x32) || (opc1 == 0x33)) {
+ TX = IFIELD( theInstr, 26, 1); // TX special case
+ opc2 = 1; // Force plxv to match lxv case
+ }
+ if (opc1 == 0x2E) opc2 = 2; // Map pstxsd inst to stxsd
+ if (opc1 == 0x2F) opc2 = 3; // Map pstxssp inst to stxssp
+ if (opc1 == 0x36) {
+ opc2 = 5; // Map pstxv inst to stxv
+ TX = IFIELD( theInstr, 26, 1); // Actually SX in the ISA
+ }
+ if ((opc2 == 0x1) || (opc2 == 0x5)) { // lxv, stxv, stxsd
+ UInt ea_off = 8;
+ IRTemp word[2];
+ IRExpr* irx_addr;
+ UInt T = IFIELD( theInstr, 21, 5); // T or S depending on inst
+
+ /* Effective address calculation */
+ if (opc1 == 0x3D) {
+ UInt uimm16 = ifieldUIMM16(theInstr);
+ Int simm16 = extend_s_16to32(uimm16);
+
+ simm16 = simm16 & DQFORM_IMMASK;
+ assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
+
+ } else {
+ assign( EA,
+ calculate_prefix_EA( prefixInstr, theInstr, rA_addr, ptype,
+ DFORM_IMMASK, &immediate_val, &R ) );
+ }
+
+ word[0] = newTemp(Ity_I64);
+ word[1] = newTemp(Ity_I64);
+
+ if ( opc2 == 1) {
+ // lxv (Load VSX Vector)
+ pDIP( prefix, "lxv v%u,%u(r%u)\n", vRS, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+ assign( word[0], load( Ity_I64, mkexpr( EA ) ) );
+
+ irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+ ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+
+ assign( word[1], load( Ity_I64, irx_addr ) );
+
+ if (host_endness == VexEndnessBE)
+ putVSReg( TX*32+T, binop( Iop_64HLtoV128,
+ mkexpr( word[0] ),
+ mkexpr( word[1] ) ) );
+ else
+ putVSReg( TX*32+T, binop( Iop_64HLtoV128,
+ mkexpr( word[1] ),
+ mkexpr( word[0] ) ) );
+ return True;
+
+ } else if ( opc2 == 5) {
+ // stxv (Store VSX Vector)
+ pDIP( prefix, "stxv v%u,%u(r%u)\n", vRS, immediate_val, rA_addr );
+ DIPp( prefix, ",%u", R );
+
+ if (host_endness == VexEndnessBE) {
+ store( mkexpr(EA), unop( Iop_V128HIto64,
+ getVSReg( TX*32+T ) ) );
+ irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+ ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+ store( irx_addr, unop( Iop_V128to64,
+ getVSReg( TX*32+T ) ) );
+ } else {
+ store( mkexpr(EA), unop( Iop_V128to64,
+ getVSReg( TX*32+T ) ) );
+ irx_addr
+ = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
+ ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+ store( irx_addr, unop( Iop_V128HIto64,
+ getVSReg( TX*32+T ) ) );
+ }
+ return True;
+
+ } else
+ return False;
+
+ break;
+
+ } else if ((opc2 & 0x3) == 0x2) {
+ // stxsd (Store VSX Scalar Doubleword)
+ pDIP(prefix, "stxsd v%u,%u(r%u)\n", vRS, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DSFORM_IMMASK,
+ &immediate_val, &R ) );
+ store( mkexpr(EA), unop( Iop_V128HIto64,
+ getVSReg( vRS+32 ) ) );
+ /* HW is clearing vector element 1. Don't see that in the ISA but
+ * matching the HW.
+ */
+ putVSReg( vRS+32, binop( Iop_64HLtoV128,
+ unop( Iop_V128HIto64,
+ getVSReg( vRS+32 ) ),
+ mkU64( 0 ) ) );
+ return True;
+
+ } else if ((opc2 & 0x3) == 0x3) {
+ // stxssp (Store VSX Scalar Single - store double precision
+ // value from register into memory in single precision format)
+ IRTemp high64 = newTemp(Ity_F64);
+ IRTemp val32 = newTemp(Ity_I32);
+
+ pDIP( prefix, "stxssp v%u,%u(r%u)\n", vRS, immediate_val, rA_addr);
+ DIPp( prefix, ",%u", R );
+
+ assign( EA, calculate_prefix_EA( prefixInstr, theInstr,
+ rA_addr, ptype, DSFORM_IMMASK,
+ &immediate_val, &R ) );
+ assign(high64, unop( Iop_ReinterpI64asF64,
+ unop( Iop_V128HIto64, getVSReg( vRS+32 ) ) ) );
+
+ assign(val32, unop( Iop_ReinterpF32asI32,
+ unop( Iop_TruncF64asF32,
+ mkexpr(high64) ) ) );
+ store( mkexpr(EA), mkexpr( val32 ) );
- if (set_FPRF) {
- // XXX XXX XXX FIXME
- // set FPRF from frD
- }
+ return True;
- if (flag_rC && clear_CR1) {
- putCR321( 1, mkU8(0) );
- putCR0( 1, mkU8(0) );
+ } else {
+ vex_printf("dis_fp_pair_prefix(ppc) : DS-form wrong opc2\n");
+ return False;
+ }
+ break;
}
- return True;
+ default:
+ vex_printf("dis_fp_pair_prefix(ppc)(instr)\n");
+ return False;
+ }
+ return False;
}
-/*
- Floating Point Pair Instructions
-*/
static Bool dis_fp_pair ( UInt prefixInstr, UInt theInstr )
{
/* X-Form/DS-Form */
@@ -11934,10 +12692,6 @@ static Bool dis_fp_pair ( UInt prefixInstr, UInt theInstr )
break;
case 0x39:
{
- UInt DS = IFIELD( theInstr, 2, 14);
- UChar vRT = ifieldRegDS(theInstr);
- IRTemp EA = newTemp( ty );
-
opc2 = ifieldOPC0o2(theInstr);
switch(opc2) {
@@ -11955,31 +12709,6 @@ static Bool dis_fp_pair ( UInt prefixInstr, UInt theInstr )
is_load = 1;
break;
- case 0x2: // lxsd (Load VSX Scalar Doubleword)
- DIP("lxsd v%u,%u(r%u)\n", vRT, DS, rA_addr);
-
- assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
-
- putVSReg( vRT+32, binop( Iop_64HLtoV128,
- load( Ity_I64, mkexpr( EA ) ),
- mkU64( 0 ) ) );
- return True;
-
- case 0x3: // lxssp (Load VSX Scalar Single from memory,
- // store as double in register)
- DIP("lxssp v%u,%u(r%u)\n", vRT, DS, rA_addr);
-
- assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
-
- putVSReg( vRT+32,
- binop( Iop_64HLtoV128,
- unop( Iop_ReinterpF64asI64,
- unop( Iop_F32toF64,
- unop( Iop_ReinterpI32asF32,
- load( Ity_I32, mkexpr( EA ) ) ) ) ),
- mkU64( 0 ) ) );
- return True;
-
default:
vex_printf("dis_fp_pair(ppc) : DS-form wrong opc2\n");
return False;
@@ -11988,10 +12717,6 @@ static Bool dis_fp_pair ( UInt prefixInstr, UInt theInstr )
}
case 0x3d:
{
- UInt DS = IFIELD( theInstr, 2, 14);
- UChar vRS = ifieldRegDS(theInstr);
- IRTemp EA = newTemp( ty );
-
opc2 = ifieldOPC0o2(theInstr);
switch(opc2) {
@@ -12009,104 +12734,6 @@ static Bool dis_fp_pair ( UInt prefixInstr, UInt theInstr )
assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
break;
- case 0x1:
- {
- UInt ea_off = 8;
- IRTemp word[2];
- IRExpr* irx_addr;
- UInt T = IFIELD( theInstr, 21, 5); // T or S depending on inst
- UInt TX = IFIELD( theInstr, 3, 1); // TX or SX field
-
- word[0] = newTemp(Ity_I64);
- word[1] = newTemp(Ity_I64);
- DS = IFIELD( theInstr, 4, 12); // DQ in the instruction definition
- assign( EA, ea_rAor0_simm( rA_addr, DS<<4 ) );
-
- if ( IFIELD( theInstr, 0, 3) == 1) {
- // lxv (Load VSX Vector)
- DIP("lxv v%u,%u(r%u)\n", vRS, DS, rA_addr);
-
- assign( word[0], load( Ity_I64, mkexpr( EA ) ) );
-
- irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
- ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
-
- assign( word[1], load( Ity_I64, irx_addr ) );
-
- if (host_endness == VexEndnessBE)
- putVSReg( TX*32+T, binop( Iop_64HLtoV128,
- mkexpr( word[0] ),
- mkexpr( word[1] ) ) );
- else
- putVSReg( TX*32+T, binop( Iop_64HLtoV128,
- mkexpr( word[1] ),
- mkexpr( word[0] ) ) );
- return True;
-
- } else if ( IFIELD( theInstr, 0, 3) == 5) {
- // stxv (Store VSX Vector)
- DIP("stxv v%u,%u(r%u)\n", vRS, DS, rA_addr);
-
- if (host_endness == VexEndnessBE) {
- store( mkexpr(EA), unop( Iop_V128HIto64,
- getVSReg( TX*32+T ) ) );
- irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
- ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
- store( irx_addr, unop( Iop_V128to64,
- getVSReg( TX*32+T ) ) );
- } else {
- store( mkexpr(EA), unop( Iop_V128to64,
- getVSReg( TX*32+T ) ) );
- irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
- ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
- store( irx_addr, unop( Iop_V128HIto64,
- getVSReg( TX*32+T ) ) );
- }
- return True;
-
- } else {
- vex_printf("dis_fp_pair vector load/store (ppc) : DS-form wrong opc2\n");
- return False;
- }
- break;
- }
- case 0x2:
- // stxsd (Store VSX Scalar Doubleword)
- DIP("stxsd v%u,%u(r%u)\n", vRS, DS, rA_addr);
-
- assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
-
- store( mkexpr(EA), unop( Iop_V128HIto64,
- getVSReg( vRS+32 ) ) );
- /* HW is clearing vector element 1. Don't see that in the ISA but
- * matching the HW.
- */
- putVSReg( vRS+32, binop( Iop_64HLtoV128,
- unop( Iop_V128HIto64,
- getVSReg( vRS+32 ) ),
- mkU64( 0 ) ) );
- return True;
-
- case 0x3:
- {
- // stxssp (Store VSX Scalar Single - store double precision
- // value from register into memory in single precision format)
- IRTemp high64 = newTemp(Ity_F64);
- IRTemp val32 = newTemp(Ity_I32);
-
- DIP("stxssp v%u,%u(r%u)\n", vRS, DS, rA_addr);
-
- assign( EA, ea_rAor0_simm( rA_addr, DS<<2 ) );
- assign(high64, unop( Iop_ReinterpI64asF64,
- unop( Iop_V128HIto64, getVSReg( vRS+32 ) ) ) );
-
- assign(val32, unop( Iop_ReinterpF32asI32,
- unop( Iop_TruncF64asF32,
- mkexpr(high64) ) ) );
- store( mkexpr(EA), mkexpr( val32 ) );
-
- return True;
- }
default:
vex_printf("dis_fp_pair(ppc) : DS-form wrong opc2\n");
return False;
@@ -29036,7 +29663,12 @@ DisResult disInstr_PPC_WRK (
switch (opc1) {
/* Integer Arithmetic Instructions */
- case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
+ case 0x0E: // addi
+ ISA_3_1_PREFIX_CHECK
+ if (dis_int_arith_prefix( prefixInstr, theInstr )) goto decode_success;
+ goto decode_failure;
+
+ case 0x0C: case 0x0D: // addic, addic.
case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
if (dis_int_arith( prefixInstr, theInstr )) goto decode_success;
goto decode_failure;
@@ -29048,10 +29680,15 @@ DisResult disInstr_PPC_WRK (
/* Integer Logical Instructions */
case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
- case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
+ case 0x1A: case 0x1B: // xori, xoris
if (dis_int_logic( prefixInstr, theInstr )) goto decode_success;
goto decode_failure;
+ case 0x19: // oris
+ if (dis_int_logic( prefixInstr, theInstr )) //oris
+ goto decode_success;
+ goto decode_failure;
+
/* Integer Rotate Instructions */
case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
if (dis_int_rot( prefixInstr, theInstr )) goto decode_success;
@@ -29064,21 +29701,94 @@ DisResult disInstr_PPC_WRK (
goto decode_failure;
/* Integer Load Instructions */
- case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
- case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
- case 0x20: case 0x21: // lwz, lwzu
+ case 0x20: // lwz
+ case 0x22: // lbz
+ ISA_3_1_PREFIX_CHECK
+ if (dis_int_load_prefix( prefixInstr, theInstr ))
+ goto decode_success;
+ goto decode_failure;
+
+ case 0x21: case 0x23: // lwzu, lbzu
if (dis_int_load( prefixInstr, theInstr )) goto decode_success;
goto decode_failure;
/* Integer Store Instructions */
- case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
- case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
+ case 0x26: case 0x2C: case 0x24: // stb, sth, stw
+ ISA_3_1_PREFIX_CHECK
+ if (dis_int_store_prefix( prefixInstr, theInstr, abiinfo ))
+ goto decode_success;
+ goto decode_failure;
+
+ case 0x27: case 0x2D: case 0x25: // stbu, sthu, stwu
if (dis_int_store( prefixInstr, theInstr, abiinfo )) goto decode_success;
goto decode_failure;
+ case 0x28: // lhz
+ ISA_3_1_PREFIX_CHECK
+ if (dis_int_load_prefix( prefixInstr, theInstr ))
+ goto decode_success;
+ goto decode_failure;
+
+ case 0x29: // lhzu, plwa
+ if (prefix_instruction( prefixInstr)) {
+ if ( !(allow_isa_3_1) ) goto decode_noIsa3_1;
+ // prefix inst: plwa
+ if (dis_int_load_ds_form_prefix( prefixInstr, theInstr ))
+ goto decode_success;
+ } else {
+ // lhzu
+ if (dis_int_load( prefixInstr, theInstr )) goto decode_success;
+ }
+ goto decode_failure;
+
+ case 0x2A: // lha, plha, plxsd
+ {
+ if (prefix_instruction( prefixInstr )) {
+ UInt ptype = PrefixType(prefixInstr);
+ if ( !(allow_isa_3_1) ) goto decode_noIsa3_1;
+ if (ptype == pType0) {
+ if (dis_fp_pair_prefix( prefixInstr, theInstr )) // plxsd
+ goto decode_success;
+ } else if (ptype == pType2) {
+ if (dis_int_load_prefix( prefixInstr, theInstr )) // plha
+ goto decode_success;
+ }
+ } else {
+ if (dis_int_load_prefix( prefixInstr, theInstr )) // lha
+ goto decode_success;
+ }
+ }
+ goto decode_failure;
+
+ case 0x2B: // lhau, plxssp
+ if (prefix_instruction( prefixInstr)) {
+ if ( !(allow_isa_3_1) ) goto decode_noIsa3_1;
+ if (dis_fp_pair_prefix( prefixInstr, theInstr )) // plxssp
+ goto decode_success;
+ } else {
...
[truncated message content] |
|
From: Carl L. <ce...@us...> - 2020-06-18 19:42:10
|
Julian:
ISA 3.1 Adds 64-bit instructions to the architecture. This patch adds
the necessary infrastructure to support 32-bit (word instructions) and
64-bit (prefix instructions). It also adds a prefixed NOP instruction.
Please let me know if you have comments. Thanks.
Carl Love
------------------------------------
Instruction Prefix Support
---
VEX/priv/guest_ppc_toIR.c | 980 +++++++++++++++++++++++++++-----------
VEX/pub/libvex.h | 2 +-
2 files changed, 712 insertions(+), 270 deletions(-)
diff --git a/VEX/priv/guest_ppc_toIR.c b/VEX/priv/guest_ppc_toIR.c
index 96217fb05..98653b396 100644
--- a/VEX/priv/guest_ppc_toIR.c
+++ b/VEX/priv/guest_ppc_toIR.c
@@ -274,11 +274,30 @@ static Bool OV32_CA32_supported = False;
#define SIGN_BIT32 0x80000000
#define SIGN_MASK32 0x7fffffff
+/* The instruction size can be either 4 byte (word instruction) or 8 bytes
+ (prefix instruction) starting with ISA 3.1 */
+#define WORD_INST_SIZE 4
+#define PREFIX_INST_SIZE 8
/*------------------------------------------------------------*/
/*--- Debugging output ---*/
/*------------------------------------------------------------*/
+/* Pre DIP macro for prefix instruction printing. */
+#define pDIP(flag,format, args...) \
+ if (vex_traceflags & VEX_TRACE_FE){ \
+ if (flag) {vex_printf("p"); vex_printf(format, ## args);} \
+ else {vex_printf(format, ## args); vex_printf("\n");}}
+
+/* Post DIP macro to print additional args for prefix instruction printing. */
+#define DIPp(flag,format, args...) \
+ if (vex_traceflags & VEX_TRACE_FE) { \
+ if (flag) {vex_printf(format, ## args); vex_printf("\n");}}
+
+/* Post DIP macro with no additional args for prefix instruction printing. */
+#define DIPn(flag) \
+ if (vex_traceflags & VEX_TRACE_FE) {if (flag) vex_printf("\n");}
+
#define DIP(format, args...) \
if (vex_traceflags & VEX_TRACE_FE) \
vex_printf(format, ## args)
@@ -532,7 +551,7 @@ static ULong MASK64( UInt begin, UInt end )
static Addr64 nextInsnAddr( void )
{
- return guest_CIA_curr_instr + 4;
+ return guest_CIA_curr_instr + WORD_INST_SIZE;
}
@@ -1602,6 +1621,9 @@ typedef enum {
DWORD
} _popcount_data_type;
+/*-----------------------------------------------------------*/
+/*--- IR popcount helpers ---*/
+/*-----------------------------------------------------------*/
/* Generate an IR sequence to do a popcount operation on the supplied
IRTemp, and return a new IRTemp holding the result. 'ty' may be
Ity_I32 or Ity_I64 only. */
@@ -3027,7 +3049,42 @@ static void set_XER_OV_OV32_ADDEX ( IRType ty, IRExpr* res,
}
}
+/*-----------------------------------------------------------*/
+/*--- Prefix instruction helpers ---*/
+/*-----------------------------------------------------------*/
+#define ENABLE_PREFIX_CHECK 1
+
+#if ENABLE_PREFIX_CHECK
+#define PREFIX_CHECK { vassert( !prefix_instruction( prefixInstr ) ); }
+#else
+#define PREFIX_CHECK { }
+#endif
+
+/* Bits 0:5 of all prefix instructions are assigned the primary opcode
+ value 0b000001. 0b000001 is not available for use as a primary opcode for
+ either word instructions or suffixes of prefixed instructions. */
+
+#define PREFIX_INST 0x1
+#define PREFIX_NOP_INVALID -1
+
+#define CONCAT(_aa,_bb,_cc) ((_aa) << (_cc) | (_bb))
+/* The codes for the prefix types */
+#define pType0 0 /* Eight-Byte Load/Store Instructions */
+#define pType1 1 /* Eight-Byte Register-to-Register Instructions */
+#define pType2 2 /* Modified Load/Store Instructions */
+#define pType3 3 /* Modified Register-to-Register Instructions */
+
+static int prefix_instruction ( UInt instr )
+{
+ /* Format of first 4 bytes of prefix instruction
+ bits [0:5] - must be 0x1 identifying this as a prefix inst
+ bits [6:7] - prefix instruction type. */
+ UChar opcode = IFIELD( instr, 26, 6);
+
+ if (opcode == PREFIX_INST) return True;
+ return False;
+}
/*------------------------------------------------------------*/
/*--- Read/write to guest-state --- */
@@ -5107,7 +5164,7 @@ static void storeTMfailure( Addr64 err_address, ULong tm_reason,
/*
Integer Arithmetic Instructions
*/
-static Bool dis_int_mult_add ( UInt theInstr )
+static Bool dis_int_mult_add ( UInt prefixInstr, UInt theInstr )
{
/* VA-Form */
UChar rD_addr = ifieldRegDS( theInstr );
@@ -5131,6 +5188,9 @@ static Bool dis_int_mult_add ( UInt theInstr )
assign( rB, getIReg( rB_addr ) );
assign( rC, getIReg( rC_addr ) );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc2) {
case 0x30: // maddhd multiply-add High doubleword signed
DIP("maddhd r%u,r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr, rC_addr);
@@ -5207,7 +5267,7 @@ static Bool dis_int_mult_add ( UInt theInstr )
return True;
}
-static Bool dis_int_arith ( UInt theInstr )
+static Bool dis_int_arith ( UInt prefixInstr, UInt theInstr )
{
/* D-Form, XO-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -5227,6 +5287,9 @@ static Bool dis_int_arith ( UInt theInstr )
Bool do_rc = False;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rA, getIReg(rA_addr) );
assign( rB, getIReg(rB_addr) ); // XO-Form: rD, rA, rB
@@ -5876,7 +5939,7 @@ static Bool dis_int_arith ( UInt theInstr )
return True;
}
-static Bool dis_modulo_int ( UInt theInstr )
+static Bool dis_modulo_int ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -5887,6 +5950,9 @@ static Bool dis_modulo_int ( UInt theInstr )
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp rD = newTemp( ty );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc1) {
/* X-Form */
case 0x1F:
@@ -6258,7 +6324,7 @@ static Bool dis_modulo_int ( UInt theInstr )
/*
Byte Compare Instructions
*/
-static Bool dis_byte_cmp ( UInt theInstr )
+static Bool dis_byte_cmp ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -6270,6 +6336,9 @@ static Bool dis_byte_cmp ( UInt theInstr )
UChar L = toUChar( IFIELD( theInstr, 21, 1 ) );
UChar BF = toUChar( IFIELD( theInstr, 23, 3 ) );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rA, getIReg(rA_addr) );
assign( rB, getIReg(rB_addr) );
@@ -6376,12 +6445,15 @@ static Bool dis_byte_cmp ( UInt theInstr )
/*
* Integer Miscellaneous instructions
*/
-static Bool dis_int_misc ( UInt theInstr )
+static Bool dis_int_misc ( UInt prefixInstr, UInt theInstr )
{
Int wc = IFIELD(theInstr, 21, 2);
UChar opc1 = ifieldOPC(theInstr);
UInt opc2 = ifieldOPClo10(theInstr);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if ( opc1 != 0x1F ) {
vex_printf("dis_modulo_int(ppc)(opc1)\n");
return False;
@@ -6416,7 +6488,7 @@ static Bool dis_int_misc ( UInt theInstr )
/*
Integer Compare Instructions
*/
-static Bool dis_int_cmp ( UInt theInstr )
+static Bool dis_int_cmp ( UInt prefixInstr, UInt theInstr )
{
/* D-Form, X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -6433,6 +6505,9 @@ static Bool dis_int_cmp ( UInt theInstr )
IRExpr *a = getIReg(rA_addr);
IRExpr *b;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (!mode64 && flag_L==1) { // L==1 invalid for 32 bit.
vex_printf("dis_int_cmp(ppc)(flag_L)\n");
return False;
@@ -6580,7 +6655,7 @@ static Bool dis_int_cmp ( UInt theInstr )
/*
Integer Logical Instructions
*/
-static Bool dis_int_logic ( UInt theInstr )
+static Bool dis_int_logic ( UInt prefixInstr, UInt theInstr )
{
/* D-Form, X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -6597,6 +6672,9 @@ static Bool dis_int_logic ( UInt theInstr )
IRTemp rB = newTemp(ty);
Bool do_rc = False;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rS, getIReg(rS_addr) );
assign( rB, getIReg(rB_addr) );
@@ -6971,7 +7049,7 @@ static Bool dis_int_logic ( UInt theInstr )
/*
Integer Parity Instructions
*/
-static Bool dis_int_parity ( UInt theInstr )
+static Bool dis_int_parity ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -7004,6 +7082,9 @@ static Bool dis_int_parity ( UInt theInstr )
IROp to_bit = (mode64 ? Iop_64to1 : Iop_32to1);
IROp shr_op = (mode64 ? Iop_Shr64 : Iop_Shr32);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x1f || rB_addr || b0) {
vex_printf("dis_int_parity(ppc)(0x1F,opc1:rB|b0)\n");
return False;
@@ -7100,7 +7181,7 @@ static Bool dis_int_parity ( UInt theInstr )
/*
Integer Rotate Instructions
*/
-static Bool dis_int_rot ( UInt theInstr )
+static Bool dis_int_rot ( UInt prefixInstr, UInt theInstr )
{
/* M-Form, MDS-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -7124,6 +7205,9 @@ static Bool dis_int_rot ( UInt theInstr )
UInt mask32;
ULong mask64;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rS, getIReg(rS_addr) );
assign( rB, getIReg(rB_addr) );
@@ -7350,7 +7434,7 @@ static Bool dis_int_rot ( UInt theInstr )
/*
Integer Load Instructions
*/
-static Bool dis_int_load ( UInt theInstr )
+static Bool dis_int_load ( UInt prefixInstr, UInt theInstr )
{
/* D-Form, X-Form, DS-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -7367,6 +7451,9 @@ static Bool dis_int_load ( UInt theInstr )
IRTemp EA = newTemp(ty);
IRExpr* val;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc1) {
case 0x1F: // register offset
assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
@@ -7648,7 +7735,7 @@ static Bool dis_int_load ( UInt theInstr )
/*
Integer Store Instructions
*/
-static Bool dis_int_store ( UInt theInstr, const VexAbiInfo* vbi )
+static Bool dis_int_store ( UInt prefixInstr, UInt theInstr, const VexAbiInfo* vbi )
{
/* D-Form, X-Form, DS-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -7666,6 +7753,9 @@ static Bool dis_int_store ( UInt theInstr, const VexAbiInfo* vbi )
IRTemp rB = newTemp(ty);
IRTemp EA = newTemp(ty);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rB, getIReg(rB_addr) );
assign( rS, getIReg(rS_addr) );
@@ -7874,7 +7964,7 @@ static Bool dis_int_store ( UInt theInstr, const VexAbiInfo* vbi )
/*
Integer Load/Store Multiple Instructions
*/
-static Bool dis_int_ldst_mult ( UInt theInstr )
+static Bool dis_int_ldst_mult ( UInt prefixInstr, UInt theInstr )
{
/* D-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -7891,6 +7981,9 @@ static Bool dis_int_ldst_mult ( UInt theInstr )
UInt ea_off = 0;
IRExpr* irx_addr;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
switch (opc1) {
@@ -8018,7 +8111,7 @@ void generate_stsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
}
}
-static Bool dis_int_ldst_str ( UInt theInstr, /*OUT*/Bool* stopHere )
+static Bool dis_int_ldst_str ( UInt prefixInstr, UInt theInstr, /*OUT*/Bool* stopHere )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -8034,6 +8127,9 @@ static Bool dis_int_ldst_str ( UInt theInstr, /*OUT*/Bool* stopHere )
IRTemp t_EA = newTemp(ty);
IRTemp t_nbytes = IRTemp_INVALID;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
*stopHere = False;
if (opc1 != 0x1F || b0 != 0) {
@@ -8186,7 +8282,7 @@ static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
/*
Integer Branch Instructions
*/
-static Bool dis_branch ( UInt theInstr,
+static Bool dis_branch ( UInt prefixInstr, UInt theInstr,
const VexAbiInfo* vbi,
/*OUT*/DisResult* dres )
{
@@ -8210,6 +8306,9 @@ static Bool dis_branch ( UInt theInstr,
IRConst* c_nia = mkSzConst(ty, nextInsnAddr());
IRTemp lr_old = newTemp(ty);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
/* Hack to pass through code that just wants to read the PC */
if (theInstr == 0x429F0005) {
DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
@@ -8390,7 +8489,7 @@ static Bool dis_branch ( UInt theInstr,
/*
* PC relative instruction
*/
-static Bool dis_pc_relative ( UInt theInstr )
+static Bool dis_pc_relative ( UInt prefixInstr, UInt theInstr )
{
/* DX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -8402,6 +8501,9 @@ static Bool dis_pc_relative ( UInt theInstr )
UInt opc2 = ifieldOPClo5(theInstr);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if ( opc1 != 0x13) {
vex_printf("dis_pc_relative(ppc)(opc1)\n");
return False;
@@ -8441,7 +8543,7 @@ static Bool dis_pc_relative ( UInt theInstr )
/*
Condition Register Logical Instructions
*/
-static Bool dis_cond_logic ( UInt theInstr )
+static Bool dis_cond_logic ( UInt prefixInstr, UInt theInstr )
{
/* XL-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -8457,6 +8559,9 @@ static Bool dis_cond_logic ( UInt theInstr )
IRTemp crbA = newTemp(Ity_I32);
IRTemp crbB = newTemp(Ity_I32);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 19 || b0 != 0) {
vex_printf("dis_cond_logic(ppc)(opc1)\n");
return False;
@@ -8625,7 +8730,7 @@ static Bool do_trap ( UChar TO,
return False; /* not an unconditional trap */
}
-static Bool dis_trapi ( UInt theInstr,
+static Bool dis_trapi ( UInt prefixInstr, UInt theInstr,
/*OUT*/DisResult* dres )
{
/* D-Form */
@@ -8638,6 +8743,9 @@ static Bool dis_trapi ( UInt theInstr,
IRType ty = mode64 ? Ity_I64 : Ity_I32;
Bool uncond = False;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc1) {
case 0x03: // twi (Trap Word Immediate, PPC32 p548)
uncond = do_trap( TO,
@@ -8676,7 +8784,7 @@ static Bool dis_trapi ( UInt theInstr,
return True;
}
-static Bool dis_trap ( UInt theInstr,
+static Bool dis_trap ( UInt prefixInstr, UInt theInstr,
/*OUT*/DisResult* dres )
{
/* X-Form */
@@ -8688,6 +8796,9 @@ static Bool dis_trap ( UInt theInstr,
IRType ty = mode64 ? Ity_I64 : Ity_I32;
Bool uncond = False;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (ifieldBIT0(theInstr) != 0)
return False;
@@ -8734,11 +8845,14 @@ static Bool dis_trap ( UInt theInstr,
/*
System Linkage Instructions
*/
-static Bool dis_syslink ( UInt theInstr,
+static Bool dis_syslink ( UInt prefixInstr, UInt theInstr,
const VexAbiInfo* abiinfo, DisResult* dres )
{
IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (theInstr != 0x44000002) {
vex_printf("dis_syslink(ppc)(theInstr)\n");
return False;
@@ -8772,7 +8886,7 @@ static Bool dis_syslink ( UInt theInstr,
check any stores it does. Instead, the reservation is cancelled when
the scheduler switches to another thread (run_thread_for_a_while()).
*/
-static Bool dis_memsync ( UInt theInstr )
+static Bool dis_memsync ( UInt prefixInstr, UInt theInstr )
{
/* X-Form, XL-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -8790,6 +8904,9 @@ static Bool dis_memsync ( UInt theInstr )
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp EA = newTemp(ty);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
switch (opc1) {
@@ -9182,7 +9299,7 @@ static Bool dis_memsync ( UInt theInstr )
/*
Integer Shift Instructions
*/
-static Bool dis_int_shift ( UInt theInstr )
+static Bool dis_int_shift ( UInt prefixInstr, UInt theInstr )
{
/* X-Form, XS-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -9203,6 +9320,9 @@ static Bool dis_int_shift ( UInt theInstr )
IRTemp rB_lo32 = newTemp(Ity_I32);
IRExpr* e_tmp;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rS, getIReg(rS_addr) );
assign( rB, getIReg(rB_addr) );
assign( rS_lo32, mkNarrowTo32(ty, mkexpr(rS)) );
@@ -9437,7 +9557,7 @@ static IRExpr* /* :: Ity_I32 */ gen_byterev16 ( IRTemp t )
);
}
-static Bool dis_int_ldst_rev ( UInt theInstr )
+static Bool dis_int_ldst_rev ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -9453,6 +9573,9 @@ static Bool dis_int_ldst_rev ( UInt theInstr )
IRTemp w1 = newTemp(Ity_I32);
IRTemp w2 = newTemp(Ity_I32);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x1F || b0 != 0) {
vex_printf("dis_int_ldst_rev(ppc)(opc1|b0)\n");
return False;
@@ -9544,7 +9667,7 @@ static Bool dis_int_ldst_rev ( UInt theInstr )
/*
Processor Control Instructions
*/
-static Bool dis_proc_ctl ( const VexAbiInfo* vbi, UInt theInstr )
+static Bool dis_proc_ctl ( const VexAbiInfo* vbi, UInt prefixInstr, UInt theInstr )
{
UChar opc1 = ifieldOPC(theInstr);
@@ -9567,6 +9690,10 @@ static Bool dis_proc_ctl ( const VexAbiInfo* vbi, UInt theInstr )
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp rS = newTemp(ty);
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rS, getIReg(rS_addr) );
/* Reorder SPR field as per PPC32 p470 */
@@ -10021,7 +10148,7 @@ static Bool dis_proc_ctl ( const VexAbiInfo* vbi, UInt theInstr )
/*
Cache Management Instructions
*/
-static Bool dis_cache_manage ( UInt theInstr,
+static Bool dis_cache_manage ( UInt prefixInstr, UInt theInstr,
DisResult* dres,
const VexArchInfo* guest_archinfo )
{
@@ -10037,6 +10164,9 @@ static Bool dis_cache_manage ( UInt theInstr,
IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
// Check for valid hint values for dcbt and dcbtst as currently described in
// ISA 2.07. If valid, then we simply set b21to25 to zero since we have no
// means of modeling the hint anyway.
@@ -10346,7 +10476,7 @@ static IRExpr * Complement_non_NaN( IRExpr * value, IRExpr * nan_mask )
/*
Floating Point Load Instructions
*/
-static Bool dis_fp_load ( UInt theInstr )
+static Bool dis_fp_load ( UInt prefixInstr, UInt theInstr )
{
/* X-Form, D-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -10365,6 +10495,9 @@ static Bool dis_fp_load ( UInt theInstr )
IRTemp iHi = newTemp(Ity_I32);
IRTemp iLo = newTemp(Ity_I32);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( rA, getIReg(rA_addr) );
assign( rB, getIReg(rB_addr) );
@@ -10484,7 +10617,7 @@ static Bool dis_fp_load ( UInt theInstr )
/*
Floating Point Store Instructions
*/
-static Bool dis_fp_store ( UInt theInstr )
+static Bool dis_fp_store ( UInt prefixInstr, UInt theInstr )
{
/* X-Form, D-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -10502,6 +10635,9 @@ static Bool dis_fp_store ( UInt theInstr )
IRTemp rA = newTemp(ty);
IRTemp rB = newTemp(ty);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frS, getFReg(frS_addr) );
assign( rA, getIReg(rA_addr) );
assign( rB, getIReg(rB_addr) );
@@ -10612,7 +10748,7 @@ static Bool dis_fp_store ( UInt theInstr )
/*
Floating Point Arith Instructions
*/
-static Bool dis_fp_arith ( UInt theInstr )
+static Bool dis_fp_arith ( UInt prefixInstr, UInt theInstr )
{
/* A-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -10640,6 +10776,9 @@ static Bool dis_fp_arith ( UInt theInstr )
zero. Hence cr1 should be cleared if this is a . form insn. */
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frA, getFReg(frA_addr));
assign( frB, getFReg(frB_addr));
assign( frC, getFReg(frC_addr));
@@ -10850,7 +10989,7 @@ static Bool dis_fp_arith ( UInt theInstr )
/*
Floating Point Mult-Add Instructions
*/
-static Bool dis_fp_multadd ( UInt theInstr )
+static Bool dis_fp_multadd ( UInt prefixInstr, UInt theInstr )
{
/* A-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -10882,6 +11021,9 @@ static Bool dis_fp_multadd ( UInt theInstr )
zero. Hence cr1 should be cleared if this is a . form insn. */
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
/* Bind the rounding mode expression to a temp; there's no
point in creating gratuitous CSEs, as we know we'll need
to use it twice. */
@@ -11352,7 +11494,7 @@ static IRExpr * do_fp_tdiv(IRTemp frA_int, IRTemp frB_int)
binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) );
}
-static Bool dis_fp_tests ( UInt theInstr )
+static Bool dis_fp_tests ( UInt prefixInstr, UInt theInstr )
{
UChar opc1 = ifieldOPC(theInstr);
UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
@@ -11361,6 +11503,9 @@ static Bool dis_fp_tests ( UInt theInstr )
UInt opc2 = ifieldOPClo10(theInstr);
IRTemp frB_I64 = newTemp(Ity_I64);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3F || b0 != 0 ){
vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
return False;
@@ -11419,7 +11564,7 @@ static Bool dis_fp_tests ( UInt theInstr )
/*
Floating Point Compare Instructions
*/
-static Bool dis_fp_cmp ( UInt theInstr )
+static Bool dis_fp_cmp ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -11436,6 +11581,9 @@ static Bool dis_fp_cmp ( UInt theInstr )
IRTemp frA = newTemp(Ity_F64);
IRTemp frB = newTemp(Ity_F64);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
vex_printf("dis_fp_cmp(ppc)(instr)\n");
return False;
@@ -11516,7 +11664,7 @@ static Bool dis_fp_cmp ( UInt theInstr )
/*
Floating Point Rounding/Conversion Instructions
*/
-static Bool dis_fp_round ( UInt theInstr )
+static Bool dis_fp_round ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -11542,6 +11690,10 @@ static Bool dis_fp_round ( UInt theInstr )
simulating exceptions, the exception status will appear to be
zero. Hence cr1 should be cleared if this is a . form insn. */
Bool clear_CR1 = True;
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if ((!(opc1 == 0x3F || opc1 == 0x3B)) || b16to20 != 0) {
vex_printf("dis_fp_round(ppc)(instr)\n");
return False;
@@ -11729,7 +11881,7 @@ putFR:
/*
Floating Point Pair Instructions
*/
-static Bool dis_fp_pair ( UInt theInstr )
+static Bool dis_fp_pair ( UInt prefixInstr, UInt theInstr )
{
/* X-Form/DS-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -11748,6 +11900,9 @@ static Bool dis_fp_pair ( UInt theInstr )
UChar b0 = ifieldBIT0(theInstr);
Bool is_load = 0;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc1) {
case 0x1F: // register offset
/* These instructions work on a pair of registers. The specified
@@ -11986,7 +12141,7 @@ static Bool dis_fp_pair ( UInt theInstr )
/*
Floating Point Merge Instructions
*/
-static Bool dis_fp_merge ( UInt theInstr )
+static Bool dis_fp_merge ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UInt opc2 = ifieldOPClo10(theInstr);
@@ -11998,6 +12153,9 @@ static Bool dis_fp_merge ( UInt theInstr )
IRTemp frA = newTemp(Ity_F64);
IRTemp frB = newTemp(Ity_F64);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frA, getFReg(frA_addr));
assign( frB, getFReg(frB_addr));
@@ -12040,7 +12198,7 @@ static Bool dis_fp_merge ( UInt theInstr )
/*
Floating Point Move Instructions
*/
-static Bool dis_fp_move ( UInt theInstr )
+static Bool dis_fp_move ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -12057,6 +12215,9 @@ static Bool dis_fp_move ( UInt theInstr )
IRTemp signA;
IRTemp hiD;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3F || (frA_addr != 0 && opc2 != 0x008)) {
vex_printf("dis_fp_move(ppc)(instr)\n");
return False;
@@ -12141,13 +12302,16 @@ static Bool dis_fp_move ( UInt theInstr )
/*
Floating Point Status/Control Register Instructions
*/
-static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
+static Bool dis_fp_scr ( UInt prefixInstr, UInt theInstr, Bool GX_level )
{
/* Many forms - see each switch case */
UChar opc1 = ifieldOPC(theInstr);
UInt opc2 = ifieldOPClo10(theInstr);
UChar flag_rC = ifieldBIT0(theInstr);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3F) {
vex_printf("dis_fp_scr(ppc)(instr)\n");
return False;
@@ -13078,7 +13242,7 @@ static IRExpr * Check_unordered(IRExpr * val)
/*------------------------------------------------------------*/
/* DFP Arithmetic instructions */
-static Bool dis_dfp_arith(UInt theInstr)
+static Bool dis_dfp_arith( UInt prefixInstr, UInt theInstr )
{
UInt opc2 = ifieldOPClo10( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
@@ -13099,6 +13263,9 @@ static Bool dis_dfp_arith(UInt theInstr)
*/
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frA, getDReg( frA_addr ) );
assign( frB, getDReg( frB_addr ) );
@@ -13136,7 +13303,7 @@ static Bool dis_dfp_arith(UInt theInstr)
}
/* Quad DFP Arithmetic instructions */
-static Bool dis_dfp_arithq(UInt theInstr)
+static Bool dis_dfp_arithq( UInt prefixInstr, UInt theInstr )
{
UInt opc2 = ifieldOPClo10( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
@@ -13157,6 +13324,9 @@ static Bool dis_dfp_arithq(UInt theInstr)
*/
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frA, getDReg_pair( frA_addr ) );
assign( frB, getDReg_pair( frB_addr ) );
@@ -13194,7 +13364,7 @@ static Bool dis_dfp_arithq(UInt theInstr)
}
/* DFP 64-bit logical shift instructions */
-static Bool dis_dfp_shift(UInt theInstr) {
+static Bool dis_dfp_shift( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo9( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frA_addr = ifieldRegA( theInstr );
@@ -13205,6 +13375,9 @@ static Bool dis_dfp_shift(UInt theInstr) {
IRTemp frS = newTemp( Ity_D64 );
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frA, getDReg( frA_addr ) );
switch (opc2) {
@@ -13231,7 +13404,7 @@ static Bool dis_dfp_shift(UInt theInstr) {
}
/* Quad DFP logical shift instructions */
-static Bool dis_dfp_shiftq(UInt theInstr) {
+static Bool dis_dfp_shiftq( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo9( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frA_addr = ifieldRegA( theInstr );
@@ -13242,6 +13415,9 @@ static Bool dis_dfp_shiftq(UInt theInstr) {
IRTemp frS = newTemp( Ity_D128 );
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frA, getDReg_pair( frA_addr ) );
switch (opc2) {
@@ -13268,7 +13444,7 @@ static Bool dis_dfp_shiftq(UInt theInstr) {
}
/* DFP 64-bit format conversion instructions */
-static Bool dis_dfp_fmt_conv(UInt theInstr) {
+static Bool dis_dfp_fmt_conv( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo10( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frB_addr = ifieldRegB( theInstr );
@@ -13278,6 +13454,9 @@ static Bool dis_dfp_fmt_conv(UInt theInstr) {
IRTemp frS;
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc2) {
case 0x102: //dctdp
DIP( "dctdp%s fr%u,fr%u\n",
@@ -13334,7 +13513,7 @@ static Bool dis_dfp_fmt_conv(UInt theInstr) {
}
/* Quad DFP format conversion instructions */
-static Bool dis_dfp_fmt_convq(UInt theInstr) {
+static Bool dis_dfp_fmt_convq( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo10( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frB_addr = ifieldRegB( theInstr );
@@ -13346,6 +13525,9 @@ static Bool dis_dfp_fmt_convq(UInt theInstr) {
UChar flag_rC = ifieldBIT0( theInstr );
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc2) {
case 0x102: // dctqpq
DIP( "dctqpq%s fr%u,fr%u\n",
@@ -13398,7 +13580,7 @@ static Bool dis_dfp_fmt_convq(UInt theInstr) {
return True;
}
-static Bool dis_dfp_round( UInt theInstr ) {
+static Bool dis_dfp_round( UInt prefixInstr, UInt theInstr ) {
UChar frS_addr = ifieldRegDS(theInstr);
UChar R = IFIELD(theInstr, 16, 1);
UChar RMC = IFIELD(theInstr, 9, 2);
@@ -13409,6 +13591,9 @@ static Bool dis_dfp_round( UInt theInstr ) {
UInt opc2 = ifieldOPClo8( theInstr );
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc2) {
/* drintn, is the same as drintx. The only difference is this
* instruction does not generate an exception for an inexact operation.
@@ -13443,7 +13628,7 @@ static Bool dis_dfp_round( UInt theInstr ) {
return True;
}
-static Bool dis_dfp_roundq(UInt theInstr) {
+static Bool dis_dfp_roundq( UInt prefixInstr, UInt theInstr ) {
UChar frS_addr = ifieldRegDS( theInstr );
UChar frB_addr = ifieldRegB( theInstr );
UChar R = IFIELD(theInstr, 16, 1);
@@ -13454,6 +13639,9 @@ static Bool dis_dfp_roundq(UInt theInstr) {
Bool clear_CR1 = True;
UInt opc2 = ifieldOPClo8( theInstr );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
switch (opc2) {
/* drintnq, is the same as drintxq. The only difference is this
* instruction does not generate an exception for an inexact operation.
@@ -13484,7 +13672,7 @@ static Bool dis_dfp_roundq(UInt theInstr) {
return True;
}
-static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
+static Bool dis_dfp_quantize_sig_rrnd( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo8( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frA_addr = ifieldRegA( theInstr );
@@ -13498,6 +13686,9 @@ static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
IRTemp frS = newTemp( Ity_D64 );
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frB, getDReg( frB_addr ) );
switch (opc2) {
@@ -13578,7 +13769,7 @@ static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
return True;
}
-static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
+static Bool dis_dfp_quantize_sig_rrndq( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo8( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frA_addr = ifieldRegA( theInstr );
@@ -13592,6 +13783,9 @@ static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
IRTemp frS = newTemp( Ity_D128 );
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frB, getDReg_pair( frB_addr ) );
switch (opc2) {
@@ -13673,7 +13867,7 @@ static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
return True;
}
-static Bool dis_dfp_extract_insert(UInt theInstr) {
+static Bool dis_dfp_extract_insert( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo10( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frA_addr = ifieldRegA( theInstr );
@@ -13686,6 +13880,9 @@ static Bool dis_dfp_extract_insert(UInt theInstr) {
IRTemp frS = newTemp( Ity_D64 );
IRTemp tmp = newTemp( Ity_I64 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frA, getDReg( frA_addr ) );
assign( frB, getDReg( frB_addr ) );
@@ -13719,7 +13916,7 @@ static Bool dis_dfp_extract_insert(UInt theInstr) {
return True;
}
-static Bool dis_dfp_extract_insertq(UInt theInstr) {
+static Bool dis_dfp_extract_insertq( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo10( theInstr );
UChar frS_addr = ifieldRegDS( theInstr );
UChar frA_addr = ifieldRegA( theInstr );
@@ -13733,6 +13930,9 @@ static Bool dis_dfp_extract_insertq(UInt theInstr) {
IRTemp tmp = newTemp( Ity_I64 );
Bool clear_CR1 = True;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frB, getDReg_pair( frB_addr ) );
switch (opc2) {
@@ -13770,7 +13970,7 @@ static Bool dis_dfp_extract_insertq(UInt theInstr) {
}
/* DFP 64-bit comparison instructions */
-static Bool dis_dfp_compare(UInt theInstr) {
+static Bool dis_dfp_compare( UInt prefixInstr, UInt theInstr ) {
/* X-Form */
UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
UChar frA_addr = ifieldRegA( theInstr );
@@ -13782,6 +13982,8 @@ static Bool dis_dfp_compare(UInt theInstr) {
IRTemp ccIR = newTemp( Ity_I32 );
IRTemp ccPPC32 = newTemp( Ity_I32 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
/* Note: Differences between dcmpu and dcmpo are only in exception
flag settings, which aren't supported anyway. */
@@ -13845,7 +14047,7 @@ static Bool dis_dfp_compare(UInt theInstr) {
}
/* Test class/group/exponent/significance instructions. */
-static Bool dis_dfp_exponent_test ( UInt theInstr )
+static Bool dis_dfp_exponent_test ( UInt prefixInstr, UInt theInstr )
{
UChar frA_addr = ifieldRegA( theInstr );
UChar frB_addr = ifieldRegB( theInstr );
@@ -13872,6 +14074,9 @@ static Bool dis_dfp_exponent_test ( UInt theInstr )
IRTemp cc3 = newTemp( Ity_I32 );
IRTemp cc = newTemp( Ity_I32 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
/* The dtstex and dtstexg instructions only differ in the size of the
* exponent field. The following switch statement takes care of the size
* specific setup. Once the value of the exponents, the G-field shift
@@ -14038,7 +14243,7 @@ static Bool dis_dfp_exponent_test ( UInt theInstr )
}
/* Test class/group/exponent/significance instructions. */
-static Bool dis_dfp_class_test ( UInt theInstr )
+static Bool dis_dfp_class_test ( UInt prefixInstr, UInt theInstr )
{
UChar frA_addr = ifieldRegA( theInstr );
IRTemp frA = newTemp( Ity_D64 );
@@ -14084,6 +14289,9 @@ static Bool dis_dfp_class_test ( UInt theInstr )
IRTemp dcm4 = newTemp( Ity_I32 );
IRTemp dcm5 = newTemp( Ity_I32 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
/* The only difference between the dtstdc and dtstdcq instructions is
* size of the T and G fields. The calculation of the 4 bit field
* is the same. Setup the parameters and values that are DFP size
@@ -14482,7 +14690,7 @@ static Bool dis_dfp_class_test ( UInt theInstr )
return True;
}
-static Bool dis_dfp_bcd(UInt theInstr) {
+static Bool dis_dfp_bcd( UInt prefixInstr, UInt theInstr ) {
UInt opc2 = ifieldOPClo10( theInstr );
ULong sp = IFIELD(theInstr, 19, 2);
ULong s = IFIELD(theInstr, 20, 1);
@@ -14499,6 +14707,9 @@ static Bool dis_dfp_bcd(UInt theInstr) {
IRTemp dbcd_l = newTemp( Ity_I32 );
IRTemp lmd = newTemp( Ity_I32 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frB, getDReg( frB_addr ) );
assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
@@ -14742,7 +14953,7 @@ static Bool dis_dfp_bcd(UInt theInstr) {
return True;
}
-static Bool dis_dfp_bcdq( UInt theInstr )
+static Bool dis_dfp_bcdq( UInt prefixInstr, UInt theInstr )
{
UInt opc2 = ifieldOPClo10( theInstr );
ULong sp = IFIELD(theInstr, 19, 2);
@@ -14758,6 +14969,9 @@ static Bool dis_dfp_bcdq( UInt theInstr )
IRTemp result_hi = newTemp( Ity_I64 );
IRTemp result_lo = newTemp( Ity_I64 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( frB_hi, getDReg( frB_addr ) );
assign( frB_lo, getDReg( frB_addr + 1 ) );
assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
@@ -15151,7 +15365,7 @@ static Bool dis_dfp_bcdq( UInt theInstr )
return True;
}
-static Bool dis_dfp_significant_digits( UInt theInstr )
+static Bool dis_dfp_significant_digits( UInt prefixInstr, UInt theInstr )
{
UInt opc1 = ifieldOPC( theInstr );
UInt opc2 = ifieldOPClo10(theInstr);
@@ -15173,6 +15387,9 @@ static Bool dis_dfp_significant_digits( UInt theInstr )
UChar UIM = toUChar( IFIELD( theInstr, 16, 6 ) );
IRTemp BCD_valid = newTemp( Ity_I32 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc2 == 0x2A2) { // dtstsf DFP Test Significance
// dtstsfq DFP Test Significance Quad
/* Get the reference singificance stored in frA */
@@ -15403,7 +15620,7 @@ static Bool dis_dfp_significant_digits( UInt theInstr )
/*
Altivec Cache Control Instructions (Data Streams)
*/
-static Bool dis_av_datastream ( UInt theInstr )
+static Bool dis_av_datastream ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -15416,6 +15633,9 @@ static Bool dis_av_datastream ( UInt theInstr )
UInt opc2 = ifieldOPClo10(theInstr);
UChar b0 = ifieldBIT0(theInstr);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
vex_printf("dis_av_datastream(ppc)(instr)\n");
return False;
@@ -15454,7 +15674,7 @@ static Bool dis_av_datastream ( UInt theInstr )
/*
AltiVec Processor Control Instructions
*/
-static Bool dis_av_procctl ( UInt theInstr )
+static Bool dis_av_procctl ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -15463,6 +15683,9 @@ static Bool dis_av_procctl ( UInt theInstr )
UChar vB_addr = ifieldRegB(theInstr);
UInt opc2 = IFIELD( theInstr, 0, 11 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x4) {
vex_printf("dis_av_procctl(ppc)(instr)\n");
return False;
@@ -15499,7 +15722,8 @@ static Bool dis_av_procctl ( UInt theInstr )
/*
Vector Extend Sign Instructions
*/
-static Bool dis_av_extend_sign_count_zero ( UInt theInstr, UInt allow_isa_3_0 )
+static Bool dis_av_extend_sign_count_zero ( UInt prefixInstr, UInt theInstr,
+ UInt allow_isa_3_0 )
{
/* VX-Form, sort of, the A register field is used to select the specific
* sign extension instruction or count leading/trailing zero LSB
@@ -15515,6 +15739,9 @@ static Bool dis_av_extend_sign_count_zero ( UInt theInstr, UInt allow_isa_3_0 )
IRTemp vB = newTemp( Ity_V128 );
IRTemp vT = newTemp( Ity_V128 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vB, getVReg ( vB_addr ) );
if ( ( opc1 != 0x4 ) && ( opc2 != 0x602 ) ) {
@@ -15841,7 +16068,7 @@ static Bool dis_av_extend_sign_count_zero ( UInt theInstr, UInt allow_isa_3_0 )
/*
Vector Rotate Instructions
*/
-static Bool dis_av_rotate ( UInt theInstr )
+static Bool dis_av_rotate ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
@@ -15872,6 +16099,9 @@ static Bool dis_av_rotate ( UInt theInstr )
UInt word_size;
unsigned long long word_mask;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if ( opc1 != 0x4 ) {
vex_printf("dis_av_rotate(ppc)(instr)\n");
return False;
@@ -16106,7 +16336,7 @@ static Bool dis_av_rotate ( UInt theInstr )
/*
AltiVec Vector Extract Element Instructions
*/
-static Bool dis_av_extract_element ( UInt theInstr )
+static Bool dis_av_extract_element ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form,
* sorta destination and first source are GPR not vector registers
@@ -16122,6 +16352,9 @@ static Bool dis_av_extract_element ( UInt theInstr )
IRTemp rA = newTemp( Ity_I64 );
IRTemp rT = newTemp( Ity_I64 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vB, getVReg( vB_addr ) );
assign( rA, getIReg( rA_addr ) );
@@ -16192,7 +16425,7 @@ static Bool dis_av_extract_element ( UInt theInstr )
* VSX scalar and vector convert instructions
*/
static Bool
-dis_vx_conv ( UInt theInstr, UInt opc2 )
+dis_vx_conv ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX2-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -16200,6 +16433,10 @@ dis_vx_conv ( UInt theInstr, UInt opc2 )
UChar XB = ifieldRegXB( theInstr );
IRTemp xB, xB2;
IRTemp b3, b2, b1, b0;
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
xB = xB2 = IRTemp_INVALID;
if (opc1 != 0x3C) {
@@ -16854,7 +17091,7 @@ dis_vx_conv ( UInt theInstr, UInt opc2 )
* VSX vector Double Precision Floating Point Arithmetic Instructions
*/
static Bool
-dis_vxv_dp_arith ( UInt theInstr, UInt opc2 )
+dis_vxv_dp_arith ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -16867,6 +17104,9 @@ dis_vxv_dp_arith ( UInt theInstr, UInt opc2 )
IRTemp frA2 = newTemp(Ity_F64);
IRTemp frB2 = newTemp(Ity_F64);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vxv_dp_arith(ppc)(instr)\n" );
return False;
@@ -17097,7 +17337,7 @@ dis_vxv_dp_arith ( UInt theInstr, UInt opc2 )
* VSX vector Single Precision Floating Point Arithmetic Instructions
*/
static Bool
-dis_vxv_sp_arith ( UInt theInstr, UInt opc2 )
+dis_vxv_sp_arith ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -17112,6 +17352,9 @@ dis_vxv_sp_arith ( UInt theInstr, UInt opc2 )
IRTemp res2 = newTemp(Ity_I32);
IRTemp res3 = newTemp(Ity_I32);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
a3 = a2 = a1 = a0 = IRTemp_INVALID;
b3 = b2 = b1 = b0 = IRTemp_INVALID;
@@ -17423,12 +17666,16 @@ dis_vxv_sp_arith ( UInt theInstr, UInt opc2 )
* Vector Population Count/bit matrix transpose
*/
static Bool
-dis_av_count_bitTranspose ( UInt theInstr, UInt opc2 )
+dis_av_count_bitTranspose ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
UChar vRB_addr = ifieldRegB(theInstr);
UChar vRT_addr = ifieldRegDS(theInstr);
UChar opc1 = ifieldOPC( theInstr );
IRTemp vB = newTemp(Ity_V128);
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vB, getVReg(vRB_addr));
if (opc1 != 0x4) {
@@ -18007,13 +18254,16 @@ static IRExpr * _do_vsx_fp_roundToInt(IRTemp frB_I64, UInt opc2)
* Miscellaneous VSX vector instructions
*/
static Bool
-dis_vxv_misc ( UInt theInstr, UInt opc2 )
+dis_vxv_misc ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar opc1 = ifieldOPC( theInstr );
UChar XT = ifieldRegXT( theInstr );
UChar XB = ifieldRegXB( theInstr );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vxv_misc(ppc)(instr)\n" );
return False;
@@ -18504,7 +18754,7 @@ dis_vxv_misc ( UInt theInstr, UInt opc2 )
* VSX Scalar Floating Point Arithmetic Instructions
*/
static Bool
-dis_vxs_arith ( UInt theInstr, UInt opc2 )
+dis_vxs_arith ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -18515,6 +18765,9 @@ dis_vxs_arith ( UInt theInstr, UInt opc2 )
IRTemp frA = newTemp(Ity_F64);
IRTemp frB = newTemp(Ity_F64);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vxs_arith(ppc)(instr)\n" );
return False;
@@ -18833,7 +19086,7 @@ dis_vxs_arith ( UInt theInstr, UInt opc2 )
* VSX Floating Point Compare Instructions
*/
static Bool
-dis_vx_cmp( UInt theInstr, UInt opc2 )
+dis_vx_cmp( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form and XX2-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -18844,6 +19097,9 @@ dis_vx_cmp( UInt theInstr, UInt opc2 )
IRTemp frA = newTemp(Ity_F64);
IRTemp frB = newTemp(Ity_F64);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vx_cmp(ppc)(instr)\n" );
return False;
@@ -18958,7 +19214,7 @@ do_vvec_fp_cmp ( IRTemp vA, IRTemp vB, UChar XT, UChar flag_rC,
* VSX Vector Compare Instructions
*/
static Bool
-dis_vvec_cmp( UInt theInstr, UInt opc2 )
+dis_vvec_cmp( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -18969,6 +19225,9 @@ dis_vvec_cmp( UInt theInstr, UInt opc2 )
IRTemp vA = newTemp( Ity_V128 );
IRTemp vB = newTemp( Ity_V128 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vvec_cmp(ppc)(instr)\n" );
return False;
@@ -19054,7 +19313,7 @@ dis_vvec_cmp( UInt theInstr, UInt opc2 )
* Miscellaneous VSX Scalar Instructions
*/
static Bool
-dis_vxs_misc( UInt theInstr, const VexAbiInfo* vbi, UInt opc2,
+dis_vxs_misc( UInt prefixInstr, UInt theInstr, const VexAbiInfo* vbi, UInt opc2,
int allow_isa_3_0 )
{
#define VG_PPC_SIGN_MASK 0x7fffffffffffffffULL
@@ -19066,6 +19325,9 @@ dis_vxs_misc( UInt theInstr, const VexAbiInfo* vbi, UInt opc2,
IRTemp vA = newTemp( Ity_V128 );
IRTemp vB = newTemp( Ity_V128 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vxs_misc(ppc)(instr)\n" );
return False;
@@ -20320,7 +20582,7 @@ dis_vxs_misc( UInt theInstr, const VexAbiInfo* vbi, UInt opc2,
*/
static Bool
-dis_vx_misc ( UInt theInstr, UInt opc2 )
+dis_vx_misc ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar XT = ifieldRegXT ( theInstr );
@@ -20340,6 +20602,9 @@ dis_vx_misc ( UInt theInstr, UInt opc2 )
IRTemp nan_cmp_value = newTemp(Ity_I64);
UInt trap_enabled = 0; /* 0 - trap enabled is False */
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVSReg( XA ) );
assign( vB, getVSReg( XB ) );
assign( xT, getVSReg( XT ) );
@@ -20554,7 +20819,7 @@ dis_vx_misc ( UInt theInstr, UInt opc2 )
* VSX Logical Instructions
*/
static Bool
-dis_vx_logic ( UInt theInstr, UInt opc2 )
+dis_vx_logic ( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -20564,6 +20829,9 @@ dis_vx_logic ( UInt theInstr, UInt opc2 )
IRTemp vA = newTemp( Ity_V128 );
IRTemp vB = newTemp( Ity_V128 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vx_logic(ppc)(instr)\n" );
return False;
@@ -20625,7 +20893,7 @@ dis_vx_logic ( UInt theInstr, UInt opc2 )
* NOTE: VSX supports word-aligned storage access.
*/
static Bool
-dis_vx_load ( UInt theInstr )
+dis_vx_load ( UInt prefixInstr, UInt theInstr )
{
/* XX1-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -20637,6 +20905,9 @@ dis_vx_load ( UInt theInstr )
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp EA = newTemp( ty );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x1F) {
vex_printf( "dis_vx_load(ppc)(instr)\n" );
return False;
@@ -21261,7 +21532,7 @@ dis_vx_load ( UInt theInstr )
* VSX Move Instructions
*/
static Bool
-dis_vx_move ( UInt theInstr )
+dis_vx_move ( UInt prefixInstr, UInt theInstr )
{
/* XX1-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -21272,6 +21543,9 @@ dis_vx_move ( UInt theInstr )
UInt opc2 = ifieldOPClo10( theInstr );
IRType ty = Ity_I64;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if ( opc1 != 0x1F ) {
vex_printf( "dis_vx_move(ppc)(instr)\n" );
return False;
@@ -21334,7 +21608,7 @@ dis_vx_move ( UInt theInstr )
* NOTE: VSX supports word-aligned storage access.
*/
static Bool
-dis_vx_store ( UInt theInstr )
+dis_vx_store ( UInt prefixInstr, UInt theInstr )
{
/* XX1-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -21347,6 +21621,9 @@ dis_vx_store ( UInt theInstr )
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp EA = newTemp( ty );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x1F) {
vex_printf( "dis_vx_store(ppc)(instr)\n" );
return False;
@@ -22177,7 +22454,8 @@ dis_vx_store ( UInt theInstr )
}
static Bool
-dis_vx_Scalar_Round_to_quad_integer( UInt theInstr, const VexAbiInfo* vbi )
+dis_vx_Scalar_Round_to_quad_integer( UInt prefixInstr, UInt theInstr,
+ const VexAbiInfo* vbi )
{
/* The ISA 3.0 instructions supported in this function require
* the underlying hardware platform that supports the ISA3.0
@@ -22192,6 +22470,9 @@ dis_vx_Scalar_Round_to_quad_integer( UInt theInstr, const VexAbiInfo* vbi )
IRTemp vT = newTemp( Ity_F128 );
UChar EX = IFIELD( theInstr, 0, 1 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vB, getF128Reg( vB_addr ) );
if (opc1 != 0x3F) {
vex_printf( "dis_vx_Scalar_Round_to_quad_integer(ppc)(instr)\n" );
@@ -22244,7 +22525,7 @@ dis_vx_Scalar_Round_to_quad_integer( UInt theInstr, const VexAbiInfo* vbi )
}
static Bool
-dis_vx_Floating_Point_Arithmetic_quad_precision( UInt theInstr,
+dis_vx_Floating_Point_Arithmetic_quad_precision( UInt prefixInstr, UInt theInstr,
const VexAbiInfo* vbi )
{
/* The ISA 3.0 instructions supported in this function require
@@ -22263,6 +22544,9 @@ dis_vx_Floating_Point_Arithmetic_quad_precision( UInt theInstr,
IRExpr* rm = get_IR_roundingmode();
UChar R0 = IFIELD( theInstr, 0, 1 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vB, getF128Reg( vB_addr ) );
if ( opc1 != 0x3F ) {
@@ -22596,7 +22880,7 @@ dis_vx_Floating_Point_Arithmetic_quad_precision( UInt theInstr,
/* VSX Scalar Quad-Precision instructions */
static Bool
-dis_vx_scalar_quad_precision ( UInt theInstr )
+dis_vx_scalar_quad_precision ( UInt prefixInstr, UInt theInstr )
{
/* This function emulates the 128-bit floating point instructions
* using existing 128-bit vector instructions (Iops). The 128-bit
@@ -22613,6 +22897,9 @@ dis_vx_scalar_quad_precision ( UInt theInstr )
IRTemp vB = newTemp( Ity_V128 );
IRTemp vT = newTemp( Ity_V128 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vB, getVSReg( vB_addr ) );
if (opc1 != 0x3F) {
@@ -23006,7 +23293,7 @@ dis_vx_scalar_quad_precision ( UInt theInstr )
* VSX permute and other miscealleous instructions
*/
static Bool
-dis_vx_permute_misc( UInt theInstr, UInt opc2 )
+dis_vx_permute_misc( UInt prefixInstr, UInt theInstr, UInt opc2 )
{
/* XX3-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -23017,6 +23304,9 @@ dis_vx_permute_misc( UInt theInstr, UInt opc2 )
IRTemp vA = newTemp( Ity_V128 );
IRTemp vB = newTemp( Ity_V128 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x3C) {
vex_printf( "dis_vx_permute_misc(ppc)(instr)\n" );
return False;
@@ -23186,7 +23476,7 @@ dis_vx_permute_misc( UInt theInstr, UInt opc2 )
/*
AltiVec Load Instructions
*/
-static Bool dis_av_load ( const VexAbiInfo* vbi, UInt theInstr )
+static Bool dis_av_load ( const VexAbiInfo* vbi, UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -23200,6 +23490,9 @@ static Bool dis_av_load ( const VexAbiInfo* vbi, UInt theInstr )
IRTemp EA = newTemp(ty);
IRTemp EA_align16 = newTemp(ty);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x1F || b0 != 0) {
vex_printf("dis_av_load(ppc)(instr)\n");
return False;
@@ -23349,7 +23642,7 @@ static Bool dis_av_load ( const VexAbiInfo* vbi, UInt theInstr )
/*
AltiVec Store Instructions
*/
-static Bool dis_av_store ( UInt theInstr )
+static Bool dis_av_store ( UInt prefixInstr, UInt theInstr )
{
/* X-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -23366,6 +23659,9 @@ static Bool dis_av_store ( UInt theInstr )
IRTemp eb = newTemp(Ity_I8);
IRTemp idx = newTemp(Ity_I8);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x1F || b0 != 0) {
vex_printf("dis_av_store(ppc)(instr)\n");
return False;
@@ -23447,7 +23743,7 @@ static Bool dis_av_store ( UInt theInstr )
/*
AltiVec Arithmetic Instructions
*/
-static Bool dis_av_arith ( UInt theInstr )
+static Bool dis_av_arith ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -23467,6 +23763,9 @@ static Bool dis_av_arith ( UInt theInstr )
IRTemp a7, a6, a5, a4, a3, a2, a1, a0;
IRTemp b3, b2, b1, b0;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
aEvn = aOdd = IRTemp_INVALID;
a15 = a14 = a13 = a12 = a11 = a10 = a9 = a8 = IRTemp_INVALID;
a7 = a6 = a5 = a4 = a3 = a2 = a1 = a0 = IRTemp_INVALID;
@@ -23954,7 +24253,7 @@ static Bool dis_av_arith ( UInt theInstr )
/*
AltiVec Logic Instructions
*/
-static Bool dis_av_logic ( UInt theInstr )
+static Bool dis_av_logic ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -23968,6 +24267,9 @@ static Bool dis_av_logic ( UInt theInstr )
assign( vA, getVReg(vA_addr));
assign( vB, getVReg(vB_addr));
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
if (opc1 != 0x4) {
vex_printf("dis_av_logic(ppc)(opc1 != 0x4)\n");
return False;
@@ -24032,7 +24334,7 @@ static Bool dis_av_logic ( UInt theInstr )
/*
AltiVec Compare Instructions
*/
-static Bool dis_av_cmp ( UInt theInstr )
+static Bool dis_av_cmp ( UInt prefixInstr, UInt theInstr )
{
/* VXR-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -24045,6 +24347,10 @@ static Bool dis_av_cmp ( UInt theInstr )
IRTemp vA = newTemp(Ity_V128);
IRTemp vB = newTemp(Ity_V128);
IRTemp vD = newTemp(Ity_V128);
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVReg(vA_addr));
assign( vB, getVReg(vB_addr));
@@ -24234,7 +24540,7 @@ static Bool dis_av_cmp ( UInt theInstr )
/*
AltiVec Multiply-Sum Instructions
*/
-static Bool dis_av_multarith ( UInt theInstr )
+static Bool dis_av_multarith ( UInt prefixInstr, UInt theInstr )
{
/* VA-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -24265,6 +24571,9 @@ static Bool dis_av_multarith ( UInt theInstr )
IRTemp ab7, ab6, ab5, ab4, ab3, ab2, ab1, ab0;
IRTemp c3, c2, c1, c0;
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
ab7 = ab6 = ab5 = ab4 = ab3 = ab2 = ab1 = ab0 = IRTemp_INVALID;
c3 = c2 = c1 = c0 = IRTemp_INVALID;
@@ -24627,7 +24936,7 @@ static Bool dis_av_multarith ( UInt theInstr )
/*
AltiVec Polynomial Multiply-Sum Instructions
*/
-static Bool dis_av_polymultarith ( UInt theInstr )
+static Bool dis_av_polymultarith ( UInt prefixInstr, UInt theInstr )
{
/* VA-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -24640,6 +24949,9 @@ static Bool dis_av_polymultarith ( UInt theInstr )
IRTemp vB = newTemp(Ity_V128);
IRTemp vC = newTemp(Ity_V128);
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVReg(vA_addr));
assign( vB, getVReg(vB_addr));
assign( vC, getVReg(vC_addr));
@@ -24681,7 +24993,7 @@ static Bool dis_av_polymultarith ( UInt theInstr )
/*
AltiVec Shift/Rotate Instructions
*/
-static Bool dis_av_shift ( UInt theInstr )
+static Bool dis_av_shift ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -24692,6 +25004,10 @@ static Bool dis_av_shift ( UInt theInstr )
IRTemp vA = newTemp(Ity_V128);
IRTemp vB = newTemp(Ity_V128);
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVReg(vA_addr));
assign( vB, getVReg(vB_addr));
@@ -24839,7 +25155,7 @@ static Bool dis_av_shift ( UInt theInstr )
/*
AltiVec Permute Instructions
*/
-static Bool dis_av_permute ( UInt theInstr )
+static Bool dis_av_permute ( UInt prefixInstr, UInt theInstr )
{
/* VA-Form, VX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -24857,6 +25173,10 @@ static Bool dis_av_permute ( UInt theInstr )
IRTemp vA = newTemp(Ity_V128);
IRTemp vB = newTemp(Ity_V128);
IRTemp vC = newTemp(Ity_V128);
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVReg(vA_addr));
assign( vB, getVReg(vB_addr));
assign( vC, getVReg(vC_addr));
@@ -25337,7 +25657,7 @@ static Bool dis_av_permute ( UInt theInstr )
/*
Vector Integer Absolute Difference
*/
-static Bool dis_abs_diff ( UInt theInstr )
+static Bool dis_abs_diff ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
UChar opc1 = ifieldOPC( theInstr );
@@ -25354,6 +25674,9 @@ static Bool dis_abs_diff ( UInt theInstr )
IRTemp vBminusA = newTemp( Ity_V128 );
IRTemp vMask = newTemp( Ity_V128 );
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVReg( vA_addr ) );
assign( vB, getVReg( vB_addr ) );
@@ -25450,7 +25773,7 @@ static Bool dis_abs_diff ( UInt theInstr )
/*
AltiVec 128 bit integer multiply by 10 Instructions
*/
-static Bool dis_av_mult10 ( UInt theInstr )
+static Bool dis_av_mult10 ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -25460,6 +25783,10 @@ static Bool dis_av_mult10 ( UInt theInstr )
UInt opc2 = IFIELD( theInstr, 0, 11 );
IRTemp vA = newTemp(Ity_V128);
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVReg(vA_addr));
if (opc1 != 0x4) {
@@ -25507,7 +25834,7 @@ static Bool dis_av_mult10 ( UInt theInstr )
/*
AltiVec Pack/Unpack Instructions
*/
-static Bool dis_av_pack ( UInt theInstr )
+static Bool dis_av_pack ( UInt prefixInstr, UInt theInstr )
{
/* VX-Form */
UChar opc1 = ifieldOPC(theInstr);
@@ -25520,6 +25847,10 @@ static Bool dis_av_pack ( UInt theInstr )
IRTemp zeros = IRTemp_INVALID;
IRTemp vA = newTemp(Ity_V128);
IRTemp vB = newTemp(Ity_V128);
+
+ /* There is no prefixed version of these instructions. */
+ PREFIX_CHECK
+
assign( vA, getVReg(vA_addr));
assign( vB, getVReg(vB_addr));
@...
[truncated message content] |
|
From: Carl L. <ce...@us...> - 2020-06-18 19:42:02
|
Julian:
This patch adds the base ISA 3.1 checking to the Valgrind code.
Please let me know if you have comments. Thanks.
Carl Love
------------------------------------------
Add check for isa 3.1 support
---
VEX/priv/guest_ppc_toIR.c | 6 +++++-
VEX/priv/host_ppc_isel.c | 5 +++--
VEX/priv/main_main.c | 23 +++++++++++++++++++++++
VEX/pub/libvex.h | 2 ++
coregrind/m_initimg/initimg-linux.c | 21 ++++++++++++++++++++-
5 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/VEX/priv/guest_ppc_toIR.c b/VEX/priv/guest_ppc_toIR.c
index c4965a19e..96217fb05 100644
--- a/VEX/priv/guest_ppc_toIR.c
+++ b/VEX/priv/guest_ppc_toIR.c
@@ -28431,6 +28431,7 @@ DisResult disInstr_PPC_WRK (
Bool allow_DFP = False;
Bool allow_isa_2_07 = False;
Bool allow_isa_3_0 = False;
+ Bool allow_isa_3_1 = False;
/* What insn variants are we supporting today? */
if (mode64) {
@@ -28442,6 +28443,7 @@ DisResult disInstr_PPC_WRK (
allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC64_DFP));
allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA2_07));
allow_isa_3_0 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA3_0));
+ allow_isa_3_1 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA3_1));
} else {
allow_F = (0 != (hwcaps & VEX_HWCAPS_PPC32_F));
allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC32_V));
@@ -28451,6 +28453,7 @@ DisResult disInstr_PPC_WRK (
allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC32_DFP));
allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA2_07));
allow_isa_3_0 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA3_0));
+ allow_isa_3_1 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA3_1));
}
/* Enable writting the OV32 and CA32 bits added with ISA3.0 */
@@ -30192,7 +30195,8 @@ DisResult disInstr_PPC ( IRSB* irsb_IN,
mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
| VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
- | VEX_HWCAPS_PPC64_ISA2_07 | VEX_HWCAPS_PPC64_ISA3_0;
+ | VEX_HWCAPS_PPC64_ISA2_07 | VEX_HWCAPS_PPC64_ISA3_0
+ | VEX_HWCAPS_PPC64_ISA3_1;
if (mode64) {
vassert((hwcaps_guest & mask32) == 0);
diff --git a/VEX/priv/host_ppc_isel.c b/VEX/priv/host_ppc_isel.c
index 10dbd6597..93d062580 100644
--- a/VEX/priv/host_ppc_isel.c
+++ b/VEX/priv/host_ppc_isel.c
@@ -7053,7 +7053,7 @@ HInstrArray* iselSB_PPC ( const IRSB* bb,
mode64 = arch_host == VexArchPPC64;
/* do some sanity checks,
- * Note: no 32-bit support for ISA 3.0
+ * Note: no 32-bit support for ISA 3.0, ISA 3.1
*/
mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
| VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
@@ -7061,7 +7061,8 @@ HInstrArray* iselSB_PPC ( const IRSB* bb,
mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
| VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
- | VEX_HWCAPS_PPC64_ISA2_07 | VEX_HWCAPS_PPC64_ISA3_0;
+ | VEX_HWCAPS_PPC64_ISA2_07 | VEX_HWCAPS_PPC64_ISA3_0
+ | VEX_HWCAPS_PPC64_ISA3_1;
if (mode64) {
vassert((hwcaps_host & mask32) == 0);
diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c
index 7a3cb75ca..a8fb14eb0 100644
--- a/VEX/priv/main_main.c
+++ b/VEX/priv/main_main.c
@@ -1683,6 +1683,7 @@ static const HChar* show_hwcaps_ppc32 ( UInt hwcaps )
{ VEX_HWCAPS_PPC32_DFP, "DFP" },
{ VEX_HWCAPS_PPC32_ISA2_07, "ISA2_07" },
{ VEX_HWCAPS_PPC32_ISA3_0, "ISA3_0" },
+ { VEX_HWCAPS_PPC32_ISA3_1, "ISA3_1" },
};
/* Allocate a large enough buffer */
static HChar buf[sizeof prefix +
@@ -1714,6 +1715,7 @@ static const HChar* show_hwcaps_ppc64 ( UInt hwcaps )
{ VEX_HWCAPS_PPC64_DFP, "DFP" },
{ VEX_HWCAPS_PPC64_ISA2_07, "ISA2_07" },
{ VEX_HWCAPS_PPC64_ISA3_0, "ISA3_0" },
+ { VEX_HWCAPS_PPC64_ISA3_1, "ISA3_1" },
};
/* Allocate a large enough buffer */
static HChar buf[sizeof prefix +
@@ -2074,6 +2076,27 @@ static void check_hwcaps ( VexArch arch, UInt hwcaps )
invalid_hwcaps(arch, hwcaps,
"ISA3_0 requires DFP capabilities\n");
}
+
+ /* ISA3_1 requires everything else */
+ if ((hwcaps & VEX_HWCAPS_PPC64_ISA3_1) != 0) {
+ if ( !((hwcaps
+ & VEX_HWCAPS_PPC64_ISA3_0) == VEX_HWCAPS_PPC64_ISA3_0))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA3_1 requires ISA3_0 capabilities\n");
+ if ( !((hwcaps
+ & VEX_HWCAPS_PPC64_ISA2_07) == VEX_HWCAPS_PPC64_ISA2_07))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA3_1 requires ISA2_07 capabilities\n");
+ if ( !has_v_fx_gx)
+ invalid_hwcaps(arch, hwcaps,
+ "ISA3_1 requires VMX and FX and GX capabilities\n");
+ if ( !(hwcaps & VEX_HWCAPS_PPC64_VX))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA3_1 requires VX capabilities\n");
+ if ( !(hwcaps & VEX_HWCAPS_PPC64_DFP))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA3_1 requires DFP capabilities\n");
+ }
return;
}
diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h
index 6da26dcb5..a541c019d 100644
--- a/VEX/pub/libvex.h
+++ b/VEX/pub/libvex.h
@@ -111,6 +111,7 @@ typedef
#define VEX_HWCAPS_PPC32_DFP (1<<17) /* Decimal Floating Point (DFP) -- e.g., dadd */
#define VEX_HWCAPS_PPC32_ISA2_07 (1<<19) /* ISA 2.07 -- e.g., mtvsrd */
#define VEX_HWCAPS_PPC32_ISA3_0 (1<<21) /* ISA 3.0 -- e.g., cnttzw */
+#define VEX_HWCAPS_PPC32_ISA3_1 (1<<22) /* ISA 3.1 -- e.g., brh */
/* ppc64: baseline capability is integer and basic FP insns */
#define VEX_HWCAPS_PPC64_V (1<<13) /* Altivec (VMX) */
@@ -121,6 +122,7 @@ typedef
#define VEX_HWCAPS_PPC64_DFP (1<<18) /* Decimal Floating Point (DFP) -- e.g., dadd */
#define VEX_HWCAPS_PPC64_ISA2_07 (1<<20) /* ISA 2.07 -- e.g., mtvsrd */
#define VEX_HWCAPS_PPC64_ISA3_0 (1<<22) /* ISA 3.0 -- e.g., cnttzw */
+#define VEX_HWCAPS_PPC64_ISA3_1 (1<<23) /* ISA 3.1 -- e.g., brh */
/* s390x: Hardware capability encoding
diff --git a/coregrind/m_initimg/initimg-linux.c b/coregrind/m_initimg/initimg-linux.c
index e811ff667..0807628cb 100644
--- a/coregrind/m_initimg/initimg-linux.c
+++ b/coregrind/m_initimg/initimg-linux.c
@@ -721,6 +721,7 @@ Addr setup_client_stack( void* init_sp,
case AT_HWCAP2: {
Bool auxv_2_07, hw_caps_2_07;
Bool auxv_3_0, hw_caps_3_0;
+ Bool auxv_3_1, hw_caps_3_1;
/* The HWCAP2 field may contain an arch_2_07 entry that indicates
* if the processor is compliant with the 2.07 ISA. (i.e. Power 8
@@ -774,7 +775,25 @@ Addr setup_client_stack( void* init_sp,
* matches the setting in VEX HWCAPS.
*/
vg_assert(auxv_3_0 == hw_caps_3_0);
- }
+
+ /* Power ISA version 3.1
+ https://ibm.ent.box.com/s/hhjfw0x0lrbtyzmiaffnbxh2fuo0fog0
+
+ 64-bit ELF V? ABI specification for Power. HWCAP2 bit pattern
+ for ISA 3.0, page ?.
+
+ ADD PUBLIC LINK WHEN AVAILABLE
+ */
+ /* ISA 3.1 */
+ auxv_3_1 = (auxv->u.a_val & 0x01000000ULL) == 0x01000000ULL;
+ hw_caps_3_1 = (vex_archinfo->hwcaps & VEX_HWCAPS_PPC64_ISA3_1)
+ == VEX_HWCAPS_PPC64_ISA3_1;
+
+ /* Verify the PPC_FEATURE2_ARCH_3_1 setting in HWCAP2
+ * matches the setting in VEX HWCAPS.
+ */
+ vg_assert(auxv_3_1 == hw_caps_3_1);
+}
break;
# endif
--
2.17.1
|
|
From: Carl L. <ce...@us...> - 2020-06-18 19:41:57
|
Julian:
Here are the first four patches to add the PPC ISA 3.1 instruction
support and test suite support. Note, all of the patches in this
series of four patches only touch PPC code in Valgrind. These are just
the first few patches of about 36 patches needed to add the instruction
and test suite support for about 244 new instructions.
The plan is to just push out a few functional and testsuite patches at
a time to keep things manageable. We tried to keep the patches
relatively small for development purposes. We may squash some of them
as we get to posting them for review.
Carl Love
|