blob: e49ac96863d03e176aa827ef991eb2d03ead6f64 [file] [log] [blame]
cerion896a1372005-01-25 12:24:25 +00001
sewardj66d5ef22011-04-15 11:55:00 +00002
cerion896a1372005-01-25 12:24:25 +00003/*--------------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00004/*--- begin guest_ppc_toIR.c ---*/
cerion896a1372005-01-25 12:24:25 +00005/*--------------------------------------------------------------------*/
6
7/*
sewardj752f9062010-05-03 21:38:49 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
cerion896a1372005-01-25 12:24:25 +000010
sewardj89ae8472013-10-18 14:12:58 +000011 Copyright (C) 2004-2013 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000012 info@open-works.net
cerion896a1372005-01-25 12:24:25 +000013
sewardj752f9062010-05-03 21:38:49 +000014 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
cerion896a1372005-01-25 12:24:25 +000018
sewardj752f9062010-05-03 21:38:49 +000019 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000027 02110-1301, USA.
28
sewardj752f9062010-05-03 21:38:49 +000029 The GNU General Public License is contained in the file COPYING.
cerion896a1372005-01-25 12:24:25 +000030
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
cerion896a1372005-01-25 12:24:25 +000035*/
36
cerionedf7fc52005-11-18 20:57:41 +000037/* TODO 18/Nov/05:
sewardjb51f0f42005-07-18 11:38:02 +000038
sewardjcf8986c2006-01-18 04:14:52 +000039 Spot rld... cases which are simply left/right shifts and emit
40 Shl64/Shr64 accordingly.
sewardje14bb9f2005-07-22 09:39:02 +000041
cerionedf7fc52005-11-18 20:57:41 +000042 Altivec
43 - datastream insns
44 - lvxl,stvxl: load/store with 'least recently used' hint
45 - vexptefp, vlogefp
sewardj87e651f2005-09-09 08:31:18 +000046
47 LIMITATIONS:
48
49 Various, including:
50
51 - Some invalid forms of lswi and lswx are accepted when they should
52 not be.
53
cerionedf7fc52005-11-18 20:57:41 +000054 - Floating Point:
55 - All exceptions disabled in FPSCR
56 - condition codes not set in FPSCR
cerion76de5cf2005-11-18 18:25:12 +000057
cerionedf7fc52005-11-18 20:57:41 +000058 - Altivec floating point:
59 - vmaddfp, vnmsubfp
60 Because we're using Java/IEEE mode (FPSCR[NJ]), rather than the
61 system default of Non-Java mode, we get some small errors
62 (lowest bit only).
63 This is because Non-Java mode brutally hacks denormalised results
64 to zero, whereas we keep maximum accuracy. However, using
65 Non-Java mode would give us more inaccuracy, as our intermediate
66 results would then be zeroed, too.
sewardjcf8986c2006-01-18 04:14:52 +000067
sewardjaca070a2006-10-17 00:28:22 +000068 - AbiHints for the stack red zone are only emitted for
sewardjcf8986c2006-01-18 04:14:52 +000069 unconditional calls and returns (bl, blr). They should also be
70 emitted for conditional calls and returns, but we don't have a
71 way to express that right now. Ah well.
sewardj20a760e2014-05-05 10:03:56 +000072
73 - Uses of Iop_{Add,Sub,Mul}32Fx4: the backend (host_ppc_isel.c)
74 ignores the rounding mode, and generates code that assumes
75 round-to-nearest. This means V will compute incorrect results
76 for uses of these IROps when the rounding mode (first) arg is
77 not mkU32(Irrm_NEAREST).
sewardjb51f0f42005-07-18 11:38:02 +000078*/
79
sewardjce02aa72006-01-12 12:27:58 +000080/* "Special" instructions.
81
sewardj09e88d12006-01-27 16:05:49 +000082 This instruction decoder can decode four special instructions
sewardjce02aa72006-01-12 12:27:58 +000083 which mean nothing natively (are no-ops as far as regs/mem are
84 concerned) but have meaning for supporting Valgrind. A special
sewardj1eb7e6b2006-01-12 21:13:14 +000085 instruction is flagged by a 16-byte preamble:
86
sewardj2171afd2014-02-10 12:27:29 +000087 32-bit mode: 5400183E 5400683E 5400E83E 5400983E
88 (rlwinm 0,0,3,0,31; rlwinm 0,0,13,0,31;
89 rlwinm 0,0,29,0,31; rlwinm 0,0,19,0,31)
sewardj1eb7e6b2006-01-12 21:13:14 +000090
91 64-bit mode: 78001800 78006800 7800E802 78009802
92 (rotldi 0,0,3; rotldi 0,0,13;
93 rotldi 0,0,61; rotldi 0,0,51)
94
95 Following that, one of the following 3 are allowed
sewardjce02aa72006-01-12 12:27:58 +000096 (standard interpretation in parentheses):
97
98 7C210B78 (or 1,1,1) %R3 = client_request ( %R4 )
99 7C421378 (or 2,2,2) %R3 = guest_NRADDR
carll1f5fe1f2014-08-07 23:25:23 +0000100 7C631B78 (or 3,3,3) branch-and-link-to-noredir %R11 Big endian
101 7C631B78 (or 3,3,3) branch-and-link-to-noredir %R12 Little endian
sewardjaca070a2006-10-17 00:28:22 +0000102 7C842378 (or 4,4,4) %R3 = guest_NRADDR_GPR2
florian2245ce92012-08-28 16:49:30 +0000103 7CA52B78 (or 5,5,5) IR injection
sewardjce02aa72006-01-12 12:27:58 +0000104
105 Any other bytes following the 16-byte preamble are illegal and
106 constitute a failure in instruction decoding. This all assumes
107 that the preamble will never occur except in specific code
108 fragments designed for Valgrind to catch.
109*/
110
carll1f5fe1f2014-08-07 23:25:23 +0000111/* Little Endian notes */
112/*
113 * Vector operations in little Endian mode behave in non-obvious ways at times.
114 * Below is an attempt at explaining this.
115 *
116 * LE/BE vector example
117 * With a vector of unsigned ints declared as follows:
118 * vector unsigned int vec_inA =
119 { 0x11111111, 0x22222222, 0x33333333, 0x44444444 };
120 * The '0x11111111' word is word zero in both LE and BE format. But the
121 * loaded vector register will have word zero on the far left in BE mode and
122 * on the far right in LE mode. The lvx and stvx instructions work naturally
123 * for whatever endianness is in effect. For example, in LE mode, the stvx
124 * stores word zero (far right word) of the vector at the lowest memory
125 * address of the EA; in BE mode, stvx still stores word zero at the lowest
126 * memory address, but with word zero interpreted as the one at the far left
127 * of the register.
128 *
129 * The lxvd2x and stxvd2x instructions are not so well suited for LE mode.
130 * When the compiler generates an lxvd2x instruction to load the
131 * above-declared vector of unsigned integers, it loads the vector as two
132 * double words, but they are in BE word-wise format. To put the vector in
133 * the right order for LE, the compiler also generates an xxswapd after the
134 * load, which puts it in proper LE format. Similarly, the stxvd2x
135 * instruction has a BE bias, storing the vector in BE word-wise format. But
136 * the compiler also generates an xxswapd prior to the store, thus ensuring
137 * the vector is stored in memory in the correct LE order.
138 *
139 * Vector-flavored Iops, such Iop_V128Hito64, reference the hi and lo parts
140 * of a double words and words within a vector. Because of the reverse order
141 * of numbering for LE as described above, the high part refers to word 1 in
142 * LE format. When input data is saved to a guest state vector register
143 * (e.g., via Iop_64HLtoV128), it is first saved to memory and then the
144 * register is loaded via PPCInstr_AvLdSt, which does an lvx instruction.
145 * The saving of the data to memory must be done in proper LE order. For the
146 * inverse operation of extracting data from a vector register (e.g.,
147 * Iop_V128Hito64), the register is first saved (by PPCInstr_AvLdSt resulting
148 * in stvx), and then integer registers are loaded from the memory location
149 * from where the vector register was saved. Again, this must be done in
150 * proper LE order. So for these various vector Iops, we have LE-specific
151 * code in host_ppc_isel.c
152 *
153 * Another unique behavior of vectors in LE mode is with the vector scalar
154 * (VSX) operations that operate on "double word 0" of the source register,
155 * storing the result in "double word 0" of the output vector register. For
156 * these operations, "double word 0" is interpreted as "high half of the
157 * register" (i.e, the part on the left side).
158 *
159 */
cerion5b2325f2005-12-23 00:55:09 +0000160/* Translates PPC32/64 code to IR. */
cerion896a1372005-01-25 12:24:25 +0000161
cerion645c9302005-01-31 10:09:59 +0000162/* References
ceriona982c052005-06-28 17:23:09 +0000163
164#define PPC32
cerion645c9302005-01-31 10:09:59 +0000165 "PowerPC Microprocessor Family:
ceriond953ebb2005-11-29 13:27:20 +0000166 The Programming Environments Manual for 32-Bit Microprocessors"
cerione9d361a2005-03-04 17:35:29 +0000167 02/21/2000
168 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2
169
ceriond953ebb2005-11-29 13:27:20 +0000170#define PPC64
171 "PowerPC Microprocessor Family:
172 Programming Environments Manual for 64-Bit Microprocessors"
173 06/10/2003
174 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/F7E732FF811F783187256FDD004D3797
175
ceriona982c052005-06-28 17:23:09 +0000176#define AV
177 "PowerPC Microprocessor Family:
178 AltiVec(TM) Technology Programming Environments Manual"
179 07/10/2003
180 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D
cerion645c9302005-01-31 10:09:59 +0000181*/
182
cerion896a1372005-01-25 12:24:25 +0000183#include "libvex_basictypes.h"
184#include "libvex_ir.h"
185#include "libvex.h"
florian58a637b2012-09-30 20:30:17 +0000186#include "libvex_emnote.h"
cerion1515db92005-01-25 17:21:23 +0000187#include "libvex_guest_ppc32.h"
ceriond953ebb2005-11-29 13:27:20 +0000188#include "libvex_guest_ppc64.h"
cerion896a1372005-01-25 12:24:25 +0000189
sewardjcef7d3e2009-07-02 12:21:59 +0000190#include "main_util.h"
191#include "main_globals.h"
192#include "guest_generic_bb_to_IR.h"
193#include "guest_ppc_defs.h"
cerion896a1372005-01-25 12:24:25 +0000194
cerion896a1372005-01-25 12:24:25 +0000195/*------------------------------------------------------------*/
196/*--- Globals ---*/
197/*------------------------------------------------------------*/
198
sewardj9e6491a2005-07-02 19:24:10 +0000199/* These are set at the start of the translation of an insn, right
cerion5b2325f2005-12-23 00:55:09 +0000200 down in disInstr_PPC, so that we don't have to pass them around
sewardj9e6491a2005-07-02 19:24:10 +0000201 endlessly. They are all constant during the translation of any
202 given insn. */
cerion896a1372005-01-25 12:24:25 +0000203
cerioned623db2005-06-20 12:42:04 +0000204/* We need to know this to do sub-register accesses correctly. */
sewardj9b769162014-07-24 12:42:03 +0000205static VexEndness host_endness;
cerioned623db2005-06-20 12:42:04 +0000206
cerion896a1372005-01-25 12:24:25 +0000207/* Pointer to the guest code area. */
florian8462d112014-09-24 15:18:09 +0000208static const UChar* guest_code;
cerion896a1372005-01-25 12:24:25 +0000209
210/* The guest address corresponding to guest_code[0]. */
ceriond953ebb2005-11-29 13:27:20 +0000211static Addr64 guest_CIA_bbstart;
cerion896a1372005-01-25 12:24:25 +0000212
sewardj01a9e802005-02-01 20:46:00 +0000213/* The guest address for the instruction currently being
214 translated. */
ceriond953ebb2005-11-29 13:27:20 +0000215static Addr64 guest_CIA_curr_instr;
sewardj01a9e802005-02-01 20:46:00 +0000216
sewardjdd40fdf2006-12-24 02:20:24 +0000217/* The IRSB* into which we're generating code. */
218static IRSB* irsb;
cerion896a1372005-01-25 12:24:25 +0000219
sewardj5df65bb2005-11-29 14:47:04 +0000220/* Is our guest binary 32 or 64bit? Set at each call to
cerion5b2325f2005-12-23 00:55:09 +0000221 disInstr_PPC below. */
sewardj5df65bb2005-11-29 14:47:04 +0000222static Bool mode64 = False;
ceriond953ebb2005-11-29 13:27:20 +0000223
cerion4c4f5ef2006-01-02 14:41:50 +0000224// Given a pointer to a function as obtained by "& functionname" in C,
225// produce a pointer to the actual entry point for the function. For
226// most platforms it's the identity function. Unfortunately, on
sewardjaca070a2006-10-17 00:28:22 +0000227// ppc64-linux it isn't (sigh) and ditto for ppc32-aix5 and
228// ppc64-aix5.
sewardjdd40fdf2006-12-24 02:20:24 +0000229static void* fnptr_to_fnentry( VexAbiInfo* vbi, void* f )
cerion4c4f5ef2006-01-02 14:41:50 +0000230{
sewardjdd40fdf2006-12-24 02:20:24 +0000231 if (vbi->host_ppc_calls_use_fndescrs) {
sewardjaca070a2006-10-17 00:28:22 +0000232 /* f is a pointer to a 3-word function descriptor, of which the
233 first word is the entry address. */
234 /* note, this is correct even with cross-jitting, since this is
235 purely a host issue, not a guest one. */
236 HWord* fdescr = (HWord*)f;
237 return (void*)(fdescr[0]);
238 } else {
239 /* Simple; "& f" points directly at the code for f. */
240 return f;
241 }
cerion4c4f5ef2006-01-02 14:41:50 +0000242}
243
sewardj4aa412a2011-07-24 14:13:21 +0000244#define SIGN_BIT 0x8000000000000000ULL
245#define SIGN_MASK 0x7fffffffffffffffULL
246#define SIGN_BIT32 0x80000000
247#define SIGN_MASK32 0x7fffffff
248
cerion896a1372005-01-25 12:24:25 +0000249
250/*------------------------------------------------------------*/
251/*--- Debugging output ---*/
252/*------------------------------------------------------------*/
253
254#define DIP(format, args...) \
255 if (vex_traceflags & VEX_TRACE_FE) \
256 vex_printf(format, ## args)
257
258#define DIS(buf, format, args...) \
259 if (vex_traceflags & VEX_TRACE_FE) \
260 vex_sprintf(buf, format, ## args)
261
262
cerion896a1372005-01-25 12:24:25 +0000263/*------------------------------------------------------------*/
ceriond953ebb2005-11-29 13:27:20 +0000264/*--- Offsets of various parts of the ppc32/64 guest state ---*/
cerion896a1372005-01-25 12:24:25 +0000265/*------------------------------------------------------------*/
266
cerion5b2325f2005-12-23 00:55:09 +0000267#define offsetofPPCGuestState(_x) \
268 (mode64 ? offsetof(VexGuestPPC64State, _x) : \
269 offsetof(VexGuestPPC32State, _x))
cerion91ad5362005-01-27 23:02:41 +0000270
sewardjaca070a2006-10-17 00:28:22 +0000271#define OFFB_CIA offsetofPPCGuestState(guest_CIA)
sewardje86310f2009-03-19 22:21:40 +0000272#define OFFB_IP_AT_SYSCALL offsetofPPCGuestState(guest_IP_AT_SYSCALL)
sewardjaca070a2006-10-17 00:28:22 +0000273#define OFFB_SPRG3_RO offsetofPPCGuestState(guest_SPRG3_RO)
274#define OFFB_LR offsetofPPCGuestState(guest_LR)
275#define OFFB_CTR offsetofPPCGuestState(guest_CTR)
276#define OFFB_XER_SO offsetofPPCGuestState(guest_XER_SO)
277#define OFFB_XER_OV offsetofPPCGuestState(guest_XER_OV)
278#define OFFB_XER_CA offsetofPPCGuestState(guest_XER_CA)
279#define OFFB_XER_BC offsetofPPCGuestState(guest_XER_BC)
280#define OFFB_FPROUND offsetofPPCGuestState(guest_FPROUND)
sewardjc6bbd472012-04-02 10:20:48 +0000281#define OFFB_DFPROUND offsetofPPCGuestState(guest_DFPROUND)
sewardjaca070a2006-10-17 00:28:22 +0000282#define OFFB_VRSAVE offsetofPPCGuestState(guest_VRSAVE)
283#define OFFB_VSCR offsetofPPCGuestState(guest_VSCR)
florian6ef84be2012-08-26 03:20:07 +0000284#define OFFB_EMNOTE offsetofPPCGuestState(guest_EMNOTE)
sewardj05f5e012014-05-04 10:52:11 +0000285#define OFFB_CMSTART offsetofPPCGuestState(guest_CMSTART)
286#define OFFB_CMLEN offsetofPPCGuestState(guest_CMLEN)
sewardjaca070a2006-10-17 00:28:22 +0000287#define OFFB_NRADDR offsetofPPCGuestState(guest_NRADDR)
288#define OFFB_NRADDR_GPR2 offsetofPPCGuestState(guest_NRADDR_GPR2)
carll8943d022013-10-02 16:25:57 +0000289#define OFFB_TFHAR offsetofPPCGuestState(guest_TFHAR)
290#define OFFB_TEXASR offsetofPPCGuestState(guest_TEXASR)
291#define OFFB_TFIAR offsetofPPCGuestState(guest_TFIAR)
sewardj5ff11dd2006-01-20 14:19:25 +0000292
cerion91ad5362005-01-27 23:02:41 +0000293
cerion38674602005-02-08 02:19:25 +0000294/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +0000295/*--- Extract instruction fields --- */
cerion38674602005-02-08 02:19:25 +0000296/*------------------------------------------------------------*/
cerione9d361a2005-03-04 17:35:29 +0000297
cerion76de5cf2005-11-18 18:25:12 +0000298/* Extract field from insn, given idx (zero = lsb) and field length */
299#define IFIELD( insn, idx, len ) ((insn >> idx) & ((1<<len)-1))
300
sewardjb51f0f42005-07-18 11:38:02 +0000301/* Extract primary opcode, instr[31:26] */
cerion76de5cf2005-11-18 18:25:12 +0000302static UChar ifieldOPC( UInt instr ) {
303 return toUChar( IFIELD( instr, 26, 6 ) );
sewardjb51f0f42005-07-18 11:38:02 +0000304}
cerione9d361a2005-03-04 17:35:29 +0000305
cerion76de5cf2005-11-18 18:25:12 +0000306/* Extract 10-bit secondary opcode, instr[10:1] */
sewardjb51f0f42005-07-18 11:38:02 +0000307static UInt ifieldOPClo10 ( UInt instr) {
cerion76de5cf2005-11-18 18:25:12 +0000308 return IFIELD( instr, 1, 10 );
309}
310
311/* Extract 9-bit secondary opcode, instr[9:1] */
312static UInt ifieldOPClo9 ( UInt instr) {
313 return IFIELD( instr, 1, 9 );
314}
315
sewardjcdc376d2012-04-23 11:21:12 +0000316/* Extract 8-bit secondary opcode, instr[8:1] */
317static UInt ifieldOPClo8 ( UInt instr) {
318 return IFIELD( instr, 1, 8 );
319}
320
cerion76de5cf2005-11-18 18:25:12 +0000321/* Extract 5-bit secondary opcode, instr[5:1] */
322static UInt ifieldOPClo5 ( UInt instr) {
323 return IFIELD( instr, 1, 5 );
sewardjb51f0f42005-07-18 11:38:02 +0000324}
cerione9d361a2005-03-04 17:35:29 +0000325
sewardjb51f0f42005-07-18 11:38:02 +0000326/* Extract RD (destination register) field, instr[25:21] */
cerion76de5cf2005-11-18 18:25:12 +0000327static UChar ifieldRegDS( UInt instr ) {
328 return toUChar( IFIELD( instr, 21, 5 ) );
sewardjb51f0f42005-07-18 11:38:02 +0000329}
cerion094d1392005-06-20 13:45:57 +0000330
sewardj66d5ef22011-04-15 11:55:00 +0000331/* Extract XT (destination register) field, instr[0,25:21] */
332static UChar ifieldRegXT ( UInt instr )
333{
334 UChar upper_bit = toUChar (IFIELD (instr, 0, 1));
335 UChar lower_bits = toUChar (IFIELD (instr, 21, 5));
336 return (upper_bit << 5) | lower_bits;
337}
338
339/* Extract XS (store source register) field, instr[0,25:21] */
340static inline UChar ifieldRegXS ( UInt instr )
341{
342 return ifieldRegXT ( instr );
343}
344
cerion76de5cf2005-11-18 18:25:12 +0000345/* Extract RA (1st source register) field, instr[20:16] */
346static UChar ifieldRegA ( UInt instr ) {
347 return toUChar( IFIELD( instr, 16, 5 ) );
sewardjb51f0f42005-07-18 11:38:02 +0000348}
349
sewardj66d5ef22011-04-15 11:55:00 +0000350/* Extract XA (1st source register) field, instr[2,20:16] */
351static UChar ifieldRegXA ( UInt instr )
352{
353 UChar upper_bit = toUChar (IFIELD (instr, 2, 1));
354 UChar lower_bits = toUChar (IFIELD (instr, 16, 5));
355 return (upper_bit << 5) | lower_bits;
356}
357
cerion76de5cf2005-11-18 18:25:12 +0000358/* Extract RB (2nd source register) field, instr[15:11] */
359static UChar ifieldRegB ( UInt instr ) {
360 return toUChar( IFIELD( instr, 11, 5 ) );
sewardjb51f0f42005-07-18 11:38:02 +0000361}
362
sewardj66d5ef22011-04-15 11:55:00 +0000363/* Extract XB (2nd source register) field, instr[1,15:11] */
364static UChar ifieldRegXB ( UInt instr )
365{
366 UChar upper_bit = toUChar (IFIELD (instr, 1, 1));
367 UChar lower_bits = toUChar (IFIELD (instr, 11, 5));
368 return (upper_bit << 5) | lower_bits;
369}
370
cerion76de5cf2005-11-18 18:25:12 +0000371/* Extract RC (3rd source register) field, instr[10:6] */
372static UChar ifieldRegC ( UInt instr ) {
373 return toUChar( IFIELD( instr, 6, 5 ) );
sewardjb51f0f42005-07-18 11:38:02 +0000374}
375
sewardj4aa412a2011-07-24 14:13:21 +0000376/* Extract XC (3rd source register) field, instr[3,10:6] */
377static UChar ifieldRegXC ( UInt instr )
378{
379 UChar upper_bit = toUChar (IFIELD (instr, 3, 1));
380 UChar lower_bits = toUChar (IFIELD (instr, 6, 5));
381 return (upper_bit << 5) | lower_bits;
382}
383
sewardj66d5ef22011-04-15 11:55:00 +0000384/* Extract bit 10, instr[10] */
cerion76de5cf2005-11-18 18:25:12 +0000385static UChar ifieldBIT10 ( UInt instr ) {
386 return toUChar( IFIELD( instr, 10, 1 ) );
387}
388
389/* Extract 2nd lowest bit, instr[1] */
390static UChar ifieldBIT1 ( UInt instr ) {
391 return toUChar( IFIELD( instr, 1, 1 ) );
392}
393
394/* Extract lowest bit, instr[0] */
395static UChar ifieldBIT0 ( UInt instr ) {
396 return toUChar( instr & 0x1 );
397}
398
399/* Extract unsigned bottom half, instr[15:0] */
400static UInt ifieldUIMM16 ( UInt instr ) {
401 return instr & 0xFFFF;
402}
403
ceriond953ebb2005-11-29 13:27:20 +0000404/* Extract unsigned bottom 26 bits, instr[25:0] */
405static UInt ifieldUIMM26 ( UInt instr ) {
406 return instr & 0x3FFFFFF;
cerion76de5cf2005-11-18 18:25:12 +0000407}
408
sewardj66d5ef22011-04-15 11:55:00 +0000409/* Extract DM field, instr[9:8] */
410static UChar ifieldDM ( UInt instr ) {
411 return toUChar( IFIELD( instr, 8, 2 ) );
412}
413
414/* Extract SHW field, instr[9:8] */
415static inline UChar ifieldSHW ( UInt instr )
416{
417 return ifieldDM ( instr );
418}
sewardjb51f0f42005-07-18 11:38:02 +0000419
cerionedf7fc52005-11-18 20:57:41 +0000420/*------------------------------------------------------------*/
ceriond953ebb2005-11-29 13:27:20 +0000421/*--- Guest-state identifiers ---*/
cerionedf7fc52005-11-18 20:57:41 +0000422/*------------------------------------------------------------*/
sewardje14bb9f2005-07-22 09:39:02 +0000423
cerione9d361a2005-03-04 17:35:29 +0000424typedef enum {
ceriond953ebb2005-11-29 13:27:20 +0000425 PPC_GST_CIA, // Current Instruction Address
426 PPC_GST_LR, // Link Register
427 PPC_GST_CTR, // Count Register
428 PPC_GST_XER, // Overflow, carry flags, byte count
429 PPC_GST_CR, // Condition Register
430 PPC_GST_FPSCR, // Floating Point Status/Control Register
431 PPC_GST_VRSAVE, // Vector Save/Restore Register
432 PPC_GST_VSCR, // Vector Status and Control Register
433 PPC_GST_EMWARN, // Emulation warnings
sewardj05f5e012014-05-04 10:52:11 +0000434 PPC_GST_CMSTART,// For icbi: start of area to invalidate
435 PPC_GST_CMLEN, // For icbi: length of area to invalidate
sewardje86310f2009-03-19 22:21:40 +0000436 PPC_GST_IP_AT_SYSCALL, // the CIA of the most recently executed SC insn
sewardjaca070a2006-10-17 00:28:22 +0000437 PPC_GST_SPRG3_RO, // SPRG3
carll8943d022013-10-02 16:25:57 +0000438 PPC_GST_TFHAR, // Transactional Failure Handler Address Register
439 PPC_GST_TFIAR, // Transactional Failure Instruction Address Register
440 PPC_GST_TEXASR, // Transactional EXception And Summary Register
ceriond953ebb2005-11-29 13:27:20 +0000441 PPC_GST_MAX
442} PPC_GST;
cerione9d361a2005-03-04 17:35:29 +0000443
sewardjc6bbd472012-04-02 10:20:48 +0000444#define MASK_FPSCR_RN 0x3ULL // Binary floating point rounding mode
445#define MASK_FPSCR_DRN 0x700000000ULL // Decimal floating point rounding mode
cerionedf7fc52005-11-18 20:57:41 +0000446#define MASK_VSCR_VALID 0x00010001
sewardje14bb9f2005-07-22 09:39:02 +0000447
cerionedf7fc52005-11-18 20:57:41 +0000448
449/*------------------------------------------------------------*/
450/*--- FP Helpers ---*/
451/*------------------------------------------------------------*/
452
sewardj2ead5222005-11-23 03:53:45 +0000453/* Produce the 32-bit pattern corresponding to the supplied
454 float. */
455static UInt float_to_bits ( Float f )
456{
457 union { UInt i; Float f; } u;
458 vassert(4 == sizeof(UInt));
459 vassert(4 == sizeof(Float));
460 vassert(4 == sizeof(u));
461 u.f = f;
462 return u.i;
463}
464
cerion38674602005-02-08 02:19:25 +0000465
cerion38674602005-02-08 02:19:25 +0000466/*------------------------------------------------------------*/
467/*--- Misc Helpers ---*/
468/*------------------------------------------------------------*/
469
cerionf0de28c2005-12-13 20:21:11 +0000470/* Generate mask with 1's from 'begin' through 'end',
471 wrapping if begin > end.
472 begin->end works from right to left, 0=lsb
473*/
ceriond953ebb2005-11-29 13:27:20 +0000474static UInt MASK32( UInt begin, UInt end )
cerion38674602005-02-08 02:19:25 +0000475{
sewardj63327402006-01-25 03:26:27 +0000476 UInt m1, m2, mask;
ceriond953ebb2005-11-29 13:27:20 +0000477 vassert(begin < 32);
478 vassert(end < 32);
sewardj63327402006-01-25 03:26:27 +0000479 m1 = ((UInt)(-1)) << begin;
480 m2 = ((UInt)(-1)) << end << 1;
481 mask = m1 ^ m2;
cerionb85e8bb2005-02-16 08:54:33 +0000482 if (begin > end) mask = ~mask; // wrap mask
483 return mask;
cerion38674602005-02-08 02:19:25 +0000484}
485
ceriond953ebb2005-11-29 13:27:20 +0000486static ULong MASK64( UInt begin, UInt end )
487{
sewardj63327402006-01-25 03:26:27 +0000488 ULong m1, m2, mask;
ceriond953ebb2005-11-29 13:27:20 +0000489 vassert(begin < 64);
490 vassert(end < 64);
sewardj63327402006-01-25 03:26:27 +0000491 m1 = ((ULong)(-1)) << begin;
492 m2 = ((ULong)(-1)) << end << 1;
493 mask = m1 ^ m2;
ceriond953ebb2005-11-29 13:27:20 +0000494 if (begin > end) mask = ~mask; // wrap mask
495 return mask;
496}
497
cerionf0de28c2005-12-13 20:21:11 +0000498static Addr64 nextInsnAddr( void )
499{
500 return guest_CIA_curr_instr + 4;
501}
ceriond953ebb2005-11-29 13:27:20 +0000502
cerion896a1372005-01-25 12:24:25 +0000503
cerion896a1372005-01-25 12:24:25 +0000504/*------------------------------------------------------------*/
505/*--- Helper bits and pieces for deconstructing the ---*/
ceriond953ebb2005-11-29 13:27:20 +0000506/*--- ppc32/64 insn stream. ---*/
cerion896a1372005-01-25 12:24:25 +0000507/*------------------------------------------------------------*/
508
sewardjdd40fdf2006-12-24 02:20:24 +0000509/* Add a statement to the list held by "irsb". */
cerion896a1372005-01-25 12:24:25 +0000510static void stmt ( IRStmt* st )
511{
sewardjdd40fdf2006-12-24 02:20:24 +0000512 addStmtToIRSB( irsb, st );
cerion896a1372005-01-25 12:24:25 +0000513}
514
cerion896a1372005-01-25 12:24:25 +0000515/* Generate a new temporary of the given type. */
516static IRTemp newTemp ( IRType ty )
517{
sewardj496a58d2005-03-20 18:44:44 +0000518 vassert(isPlausibleIRType(ty));
sewardjdd40fdf2006-12-24 02:20:24 +0000519 return newIRTemp( irsb->tyenv, ty );
cerion896a1372005-01-25 12:24:25 +0000520}
cerion896a1372005-01-25 12:24:25 +0000521
cerion32aad402005-09-10 12:02:24 +0000522/* Various simple conversions */
523
524static UChar extend_s_5to8 ( UChar x )
525{
526 return toUChar((((Int)x) << 27) >> 27);
527}
528
cerion92d9d872005-09-15 21:58:50 +0000529static UInt extend_s_8to32( UChar x )
530{
531 return (UInt)((((Int)x) << 24) >> 24);
532}
cerion91ad5362005-01-27 23:02:41 +0000533
cerion896a1372005-01-25 12:24:25 +0000534static UInt extend_s_16to32 ( UInt x )
535{
536 return (UInt)((((Int)x) << 16) >> 16);
537}
cerion896a1372005-01-25 12:24:25 +0000538
ceriond953ebb2005-11-29 13:27:20 +0000539static ULong extend_s_16to64 ( UInt x )
540{
541 return (ULong)((((Long)x) << 48) >> 48);
542}
543
544static ULong extend_s_26to64 ( UInt x )
545{
546 return (ULong)((((Long)x) << 38) >> 38);
547}
548
549static ULong extend_s_32to64 ( UInt x )
550{
551 return (ULong)((((Long)x) << 32) >> 32);
552}
553
carll1f5fe1f2014-08-07 23:25:23 +0000554/* Do a proper-endian load of a 32-bit word, regardless of the endianness
sewardj684aa952005-01-30 12:52:14 +0000555 of the underlying host. */
florian8462d112014-09-24 15:18:09 +0000556static UInt getUIntPPCendianly ( const UChar* p )
sewardj684aa952005-01-30 12:52:14 +0000557{
cerioncf004462005-01-31 15:24:55 +0000558 UInt w = 0;
carll1f5fe1f2014-08-07 23:25:23 +0000559 if (host_endness == VexEndnessBE) {
560 w = (w << 8) | p[0];
561 w = (w << 8) | p[1];
562 w = (w << 8) | p[2];
563 w = (w << 8) | p[3];
564 } else {
565 w = (w << 8) | p[3];
566 w = (w << 8) | p[2];
567 w = (w << 8) | p[1];
568 w = (w << 8) | p[0];
569 }
sewardj684aa952005-01-30 12:52:14 +0000570 return w;
571}
572
cerion896a1372005-01-25 12:24:25 +0000573
574/*------------------------------------------------------------*/
575/*--- Helpers for constructing IR. ---*/
576/*------------------------------------------------------------*/
577
cerion896a1372005-01-25 12:24:25 +0000578static void assign ( IRTemp dst, IRExpr* e )
579{
sewardjdd40fdf2006-12-24 02:20:24 +0000580 stmt( IRStmt_WrTmp(dst, e) );
cerion896a1372005-01-25 12:24:25 +0000581}
582
sewardje9d8a262009-07-01 08:06:34 +0000583/* This generates a normal (non store-conditional) store. */
carll1f5fe1f2014-08-07 23:25:23 +0000584static void store ( IRExpr* addr, IRExpr* data )
cerion896a1372005-01-25 12:24:25 +0000585{
sewardje9d8a262009-07-01 08:06:34 +0000586 IRType tyA = typeOfIRExpr(irsb->tyenv, addr);
587 vassert(tyA == Ity_I32 || tyA == Ity_I64);
carll1f5fe1f2014-08-07 23:25:23 +0000588
589 if (host_endness == VexEndnessBE)
590 stmt( IRStmt_Store(Iend_BE, addr, data) );
591 else
592 stmt( IRStmt_Store(Iend_LE, addr, data) );
cerion896a1372005-01-25 12:24:25 +0000593}
594
595static IRExpr* unop ( IROp op, IRExpr* a )
596{
597 return IRExpr_Unop(op, a);
598}
599
600static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
601{
602 return IRExpr_Binop(op, a1, a2);
603}
604
sewardjb183b852006-02-03 16:08:03 +0000605static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
606{
607 return IRExpr_Triop(op, a1, a2, a3);
608}
609
sewardj40c80262006-02-08 19:30:46 +0000610static IRExpr* qop ( IROp op, IRExpr* a1, IRExpr* a2,
611 IRExpr* a3, IRExpr* a4 )
612{
613 return IRExpr_Qop(op, a1, a2, a3, a4);
614}
615
cerion896a1372005-01-25 12:24:25 +0000616static IRExpr* mkexpr ( IRTemp tmp )
617{
sewardjdd40fdf2006-12-24 02:20:24 +0000618 return IRExpr_RdTmp(tmp);
cerion896a1372005-01-25 12:24:25 +0000619}
620
sewardj684c0372005-02-07 02:33:58 +0000621static IRExpr* mkU8 ( UChar i )
cerion896a1372005-01-25 12:24:25 +0000622{
cerion896a1372005-01-25 12:24:25 +0000623 return IRExpr_Const(IRConst_U8(i));
624}
cerion896a1372005-01-25 12:24:25 +0000625
cerion92d9d872005-09-15 21:58:50 +0000626static IRExpr* mkU16 ( UInt i )
627{
628 return IRExpr_Const(IRConst_U16(i));
629}
630
cerion896a1372005-01-25 12:24:25 +0000631static IRExpr* mkU32 ( UInt i )
632{
633 return IRExpr_Const(IRConst_U32(i));
634}
635
cerion4a49b032005-11-08 16:23:07 +0000636static IRExpr* mkU64 ( ULong i )
637{
638 return IRExpr_Const(IRConst_U64(i));
639}
640
sewardj66d5ef22011-04-15 11:55:00 +0000641static IRExpr* mkV128 ( UShort i )
642{
643 vassert(i == 0 || i == 0xffff);
644 return IRExpr_Const(IRConst_V128(i));
645}
646
sewardje9d8a262009-07-01 08:06:34 +0000647/* This generates a normal (non load-linked) load. */
carll1f5fe1f2014-08-07 23:25:23 +0000648static IRExpr* load ( IRType ty, IRExpr* addr )
cerion896a1372005-01-25 12:24:25 +0000649{
carll1f5fe1f2014-08-07 23:25:23 +0000650 if (host_endness == VexEndnessBE)
651 return IRExpr_Load(Iend_BE, ty, addr);
652 else
653 return IRExpr_Load(Iend_LE, ty, addr);
654}
655
656static IRStmt* stmt_load ( IRTemp result,
657 IRExpr* addr, IRExpr* storedata )
658{
659 if (host_endness == VexEndnessBE)
660 return IRStmt_LLSC(Iend_BE, result, addr, storedata);
661 else
662 return IRStmt_LLSC(Iend_LE, result, addr, storedata);
cerion896a1372005-01-25 12:24:25 +0000663}
cerion896a1372005-01-25 12:24:25 +0000664
sewardj20ef5472005-07-21 14:48:31 +0000665static IRExpr* mkOR1 ( IRExpr* arg1, IRExpr* arg2 )
666{
sewardjdd40fdf2006-12-24 02:20:24 +0000667 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
668 vassert(typeOfIRExpr(irsb->tyenv, arg2) == Ity_I1);
cerion5b2325f2005-12-23 00:55:09 +0000669 return unop(Iop_32to1, binop(Iop_Or32, unop(Iop_1Uto32, arg1),
670 unop(Iop_1Uto32, arg2)));
sewardj20ef5472005-07-21 14:48:31 +0000671}
672
673static IRExpr* mkAND1 ( IRExpr* arg1, IRExpr* arg2 )
674{
sewardjdd40fdf2006-12-24 02:20:24 +0000675 vassert(typeOfIRExpr(irsb->tyenv, arg1) == Ity_I1);
676 vassert(typeOfIRExpr(irsb->tyenv, arg2) == Ity_I1);
cerion5b2325f2005-12-23 00:55:09 +0000677 return unop(Iop_32to1, binop(Iop_And32, unop(Iop_1Uto32, arg1),
678 unop(Iop_1Uto32, arg2)));
sewardj20ef5472005-07-21 14:48:31 +0000679}
sewardjb51f0f42005-07-18 11:38:02 +0000680
cerion4a49b032005-11-08 16:23:07 +0000681/* expand V128_8Ux16 to 2x V128_16Ux8's */
cerion5b2325f2005-12-23 00:55:09 +0000682static void expand8Ux16( IRExpr* vIn,
683 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
cerion4a49b032005-11-08 16:23:07 +0000684{
685 IRTemp ones8x16 = newTemp(Ity_V128);
686
sewardjdd40fdf2006-12-24 02:20:24 +0000687 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
cerion4a49b032005-11-08 16:23:07 +0000688 vassert(vEvn && *vEvn == IRTemp_INVALID);
689 vassert(vOdd && *vOdd == IRTemp_INVALID);
690 *vEvn = newTemp(Ity_V128);
691 *vOdd = newTemp(Ity_V128);
692
693 assign( ones8x16, unop(Iop_Dup8x16, mkU8(0x1)) );
cerion24d06f12005-11-09 21:34:20 +0000694 assign( *vOdd, binop(Iop_MullEven8Ux16, mkexpr(ones8x16), vIn) );
695 assign( *vEvn, binop(Iop_MullEven8Ux16, mkexpr(ones8x16),
696 binop(Iop_ShrV128, vIn, mkU8(8))) );
cerion4a49b032005-11-08 16:23:07 +0000697}
698
699/* expand V128_8Sx16 to 2x V128_16Sx8's */
cerion5b2325f2005-12-23 00:55:09 +0000700static void expand8Sx16( IRExpr* vIn,
701 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
cerion4a49b032005-11-08 16:23:07 +0000702{
703 IRTemp ones8x16 = newTemp(Ity_V128);
704
sewardjdd40fdf2006-12-24 02:20:24 +0000705 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
cerion4a49b032005-11-08 16:23:07 +0000706 vassert(vEvn && *vEvn == IRTemp_INVALID);
707 vassert(vOdd && *vOdd == IRTemp_INVALID);
708 *vEvn = newTemp(Ity_V128);
709 *vOdd = newTemp(Ity_V128);
710
711 assign( ones8x16, unop(Iop_Dup8x16, mkU8(0x1)) );
cerion24d06f12005-11-09 21:34:20 +0000712 assign( *vOdd, binop(Iop_MullEven8Sx16, mkexpr(ones8x16), vIn) );
713 assign( *vEvn, binop(Iop_MullEven8Sx16, mkexpr(ones8x16),
714 binop(Iop_ShrV128, vIn, mkU8(8))) );
cerion4a49b032005-11-08 16:23:07 +0000715}
716
717/* expand V128_16Uto8 to 2x V128_32Ux4's */
cerion5b2325f2005-12-23 00:55:09 +0000718static void expand16Ux8( IRExpr* vIn,
719 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
cerion4a49b032005-11-08 16:23:07 +0000720{
721 IRTemp ones16x8 = newTemp(Ity_V128);
722
sewardjdd40fdf2006-12-24 02:20:24 +0000723 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
cerion4a49b032005-11-08 16:23:07 +0000724 vassert(vEvn && *vEvn == IRTemp_INVALID);
725 vassert(vOdd && *vOdd == IRTemp_INVALID);
726 *vEvn = newTemp(Ity_V128);
727 *vOdd = newTemp(Ity_V128);
728
729 assign( ones16x8, unop(Iop_Dup16x8, mkU16(0x1)) );
cerion24d06f12005-11-09 21:34:20 +0000730 assign( *vOdd, binop(Iop_MullEven16Ux8, mkexpr(ones16x8), vIn) );
731 assign( *vEvn, binop(Iop_MullEven16Ux8, mkexpr(ones16x8),
732 binop(Iop_ShrV128, vIn, mkU8(16))) );
cerion4a49b032005-11-08 16:23:07 +0000733}
734
735/* expand V128_16Sto8 to 2x V128_32Sx4's */
cerion5b2325f2005-12-23 00:55:09 +0000736static void expand16Sx8( IRExpr* vIn,
737 /*OUTs*/ IRTemp* vEvn, IRTemp* vOdd )
cerion4a49b032005-11-08 16:23:07 +0000738{
739 IRTemp ones16x8 = newTemp(Ity_V128);
740
sewardjdd40fdf2006-12-24 02:20:24 +0000741 vassert(typeOfIRExpr(irsb->tyenv, vIn) == Ity_V128);
cerion4a49b032005-11-08 16:23:07 +0000742 vassert(vEvn && *vEvn == IRTemp_INVALID);
743 vassert(vOdd && *vOdd == IRTemp_INVALID);
744 *vEvn = newTemp(Ity_V128);
745 *vOdd = newTemp(Ity_V128);
746
747 assign( ones16x8, unop(Iop_Dup16x8, mkU16(0x1)) );
cerion24d06f12005-11-09 21:34:20 +0000748 assign( *vOdd, binop(Iop_MullEven16Sx8, mkexpr(ones16x8), vIn) );
749 assign( *vEvn, binop(Iop_MullEven16Sx8, mkexpr(ones16x8),
750 binop(Iop_ShrV128, vIn, mkU8(16))) );
cerion4a49b032005-11-08 16:23:07 +0000751}
752
sewardj4aa412a2011-07-24 14:13:21 +0000753/* break V128 to 4xF64's*/
754static void breakV128to4xF64( IRExpr* t128,
755 /*OUTs*/
756 IRTemp* t3, IRTemp* t2,
757 IRTemp* t1, IRTemp* t0 )
758{
759 IRTemp hi64 = newTemp(Ity_I64);
760 IRTemp lo64 = newTemp(Ity_I64);
761
762 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
763 vassert(t0 && *t0 == IRTemp_INVALID);
764 vassert(t1 && *t1 == IRTemp_INVALID);
765 vassert(t2 && *t2 == IRTemp_INVALID);
766 vassert(t3 && *t3 == IRTemp_INVALID);
767 *t0 = newTemp(Ity_F64);
768 *t1 = newTemp(Ity_F64);
769 *t2 = newTemp(Ity_F64);
770 *t3 = newTemp(Ity_F64);
771
772 assign( hi64, unop(Iop_V128HIto64, t128) );
773 assign( lo64, unop(Iop_V128to64, t128) );
774 assign( *t3,
775 unop( Iop_F32toF64,
776 unop( Iop_ReinterpI32asF32,
777 unop( Iop_64HIto32, mkexpr( hi64 ) ) ) ) );
778 assign( *t2,
779 unop( Iop_F32toF64,
780 unop( Iop_ReinterpI32asF32, unop( Iop_64to32, mkexpr( hi64 ) ) ) ) );
781 assign( *t1,
782 unop( Iop_F32toF64,
783 unop( Iop_ReinterpI32asF32,
784 unop( Iop_64HIto32, mkexpr( lo64 ) ) ) ) );
785 assign( *t0,
786 unop( Iop_F32toF64,
787 unop( Iop_ReinterpI32asF32, unop( Iop_64to32, mkexpr( lo64 ) ) ) ) );
788}
789
790
cerion4a49b032005-11-08 16:23:07 +0000791/* break V128 to 4xI32's, then sign-extend to I64's */
792static void breakV128to4x64S( IRExpr* t128,
793 /*OUTs*/
794 IRTemp* t3, IRTemp* t2,
795 IRTemp* t1, IRTemp* t0 )
796{
797 IRTemp hi64 = newTemp(Ity_I64);
798 IRTemp lo64 = newTemp(Ity_I64);
799
sewardjdd40fdf2006-12-24 02:20:24 +0000800 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
cerion4a49b032005-11-08 16:23:07 +0000801 vassert(t0 && *t0 == IRTemp_INVALID);
802 vassert(t1 && *t1 == IRTemp_INVALID);
803 vassert(t2 && *t2 == IRTemp_INVALID);
804 vassert(t3 && *t3 == IRTemp_INVALID);
805 *t0 = newTemp(Ity_I64);
806 *t1 = newTemp(Ity_I64);
807 *t2 = newTemp(Ity_I64);
808 *t3 = newTemp(Ity_I64);
809
810 assign( hi64, unop(Iop_V128HIto64, t128) );
811 assign( lo64, unop(Iop_V128to64, t128) );
812 assign( *t3, unop(Iop_32Sto64, unop(Iop_64HIto32, mkexpr(hi64))) );
813 assign( *t2, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(hi64))) );
814 assign( *t1, unop(Iop_32Sto64, unop(Iop_64HIto32, mkexpr(lo64))) );
815 assign( *t0, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(lo64))) );
816}
817
818/* break V128 to 4xI32's, then zero-extend to I64's */
819static void breakV128to4x64U ( IRExpr* t128,
820 /*OUTs*/
821 IRTemp* t3, IRTemp* t2,
822 IRTemp* t1, IRTemp* t0 )
823{
824 IRTemp hi64 = newTemp(Ity_I64);
825 IRTemp lo64 = newTemp(Ity_I64);
826
sewardjdd40fdf2006-12-24 02:20:24 +0000827 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
cerion4a49b032005-11-08 16:23:07 +0000828 vassert(t0 && *t0 == IRTemp_INVALID);
829 vassert(t1 && *t1 == IRTemp_INVALID);
830 vassert(t2 && *t2 == IRTemp_INVALID);
831 vassert(t3 && *t3 == IRTemp_INVALID);
832 *t0 = newTemp(Ity_I64);
833 *t1 = newTemp(Ity_I64);
834 *t2 = newTemp(Ity_I64);
835 *t3 = newTemp(Ity_I64);
836
837 assign( hi64, unop(Iop_V128HIto64, t128) );
838 assign( lo64, unop(Iop_V128to64, t128) );
839 assign( *t3, unop(Iop_32Uto64, unop(Iop_64HIto32, mkexpr(hi64))) );
840 assign( *t2, unop(Iop_32Uto64, unop(Iop_64to32, mkexpr(hi64))) );
841 assign( *t1, unop(Iop_32Uto64, unop(Iop_64HIto32, mkexpr(lo64))) );
842 assign( *t0, unop(Iop_32Uto64, unop(Iop_64to32, mkexpr(lo64))) );
843}
844
sewardje71e56a2011-09-05 12:11:06 +0000845static void breakV128to4x32( IRExpr* t128,
846 /*OUTs*/
847 IRTemp* t3, IRTemp* t2,
848 IRTemp* t1, IRTemp* t0 )
849{
850 IRTemp hi64 = newTemp(Ity_I64);
851 IRTemp lo64 = newTemp(Ity_I64);
852
853 vassert(typeOfIRExpr(irsb->tyenv, t128) == Ity_V128);
854 vassert(t0 && *t0 == IRTemp_INVALID);
855 vassert(t1 && *t1 == IRTemp_INVALID);
856 vassert(t2 && *t2 == IRTemp_INVALID);
857 vassert(t3 && *t3 == IRTemp_INVALID);
858 *t0 = newTemp(Ity_I32);
859 *t1 = newTemp(Ity_I32);
860 *t2 = newTemp(Ity_I32);
861 *t3 = newTemp(Ity_I32);
862
863 assign( hi64, unop(Iop_V128HIto64, t128) );
864 assign( lo64, unop(Iop_V128to64, t128) );
865 assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
866 assign( *t2, unop(Iop_64to32, mkexpr(hi64)) );
867 assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
868 assign( *t0, unop(Iop_64to32, mkexpr(lo64)) );
869}
870
carll7deaf952013-10-15 18:11:20 +0000871static IRExpr* mkV128from32( IRTemp t3, IRTemp t2,
872 IRTemp t1, IRTemp t0 )
873{
874 return
875 binop( Iop_64HLtoV128,
876 binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
877 binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
878 );
879}
880
sewardje71e56a2011-09-05 12:11:06 +0000881
cerion4a49b032005-11-08 16:23:07 +0000882/* Signed saturating narrow 64S to 32 */
883static IRExpr* mkQNarrow64Sto32 ( IRExpr* t64 )
884{
885 IRTemp hi32 = newTemp(Ity_I32);
886 IRTemp lo32 = newTemp(Ity_I32);
887
sewardjdd40fdf2006-12-24 02:20:24 +0000888 vassert(typeOfIRExpr(irsb->tyenv, t64) == Ity_I64);
cerion4a49b032005-11-08 16:23:07 +0000889
890 assign( hi32, unop(Iop_64HIto32, t64));
891 assign( lo32, unop(Iop_64to32, t64));
892
florian99dd03e2013-01-29 03:56:06 +0000893 return IRExpr_ITE(
cerion4a49b032005-11-08 16:23:07 +0000894 /* if (hi32 == (lo32 >>s 31)) */
sewardj009230b2013-01-26 11:47:55 +0000895 binop(Iop_CmpEQ32, mkexpr(hi32),
896 binop( Iop_Sar32, mkexpr(lo32), mkU8(31))),
florian99dd03e2013-01-29 03:56:06 +0000897 /* then: within signed-32 range: lo half good enough */
898 mkexpr(lo32),
cerion4a49b032005-11-08 16:23:07 +0000899 /* else: sign dep saturate: 1->0x80000000, 0->0x7FFFFFFF */
900 binop(Iop_Add32, mkU32(0x7FFFFFFF),
florian99dd03e2013-01-29 03:56:06 +0000901 binop(Iop_Shr32, mkexpr(hi32), mkU8(31))));
cerion4a49b032005-11-08 16:23:07 +0000902}
903
904/* Unsigned saturating narrow 64S to 32 */
905static IRExpr* mkQNarrow64Uto32 ( IRExpr* t64 )
906{
907 IRTemp hi32 = newTemp(Ity_I32);
908 IRTemp lo32 = newTemp(Ity_I32);
909
sewardjdd40fdf2006-12-24 02:20:24 +0000910 vassert(typeOfIRExpr(irsb->tyenv, t64) == Ity_I64);
cerion4a49b032005-11-08 16:23:07 +0000911
912 assign( hi32, unop(Iop_64HIto32, t64));
913 assign( lo32, unop(Iop_64to32, t64));
914
florian99dd03e2013-01-29 03:56:06 +0000915 return IRExpr_ITE(
cerion4a49b032005-11-08 16:23:07 +0000916 /* if (top 32 bits of t64 are 0) */
sewardj009230b2013-01-26 11:47:55 +0000917 binop(Iop_CmpEQ32, mkexpr(hi32), mkU32(0)),
cerion4a49b032005-11-08 16:23:07 +0000918 /* then: within unsigned-32 range: lo half good enough */
florian99dd03e2013-01-29 03:56:06 +0000919 mkexpr(lo32),
920 /* else: positive saturate -> 0xFFFFFFFF */
921 mkU32(0xFFFFFFFF));
cerion4a49b032005-11-08 16:23:07 +0000922}
923
924/* Signed saturate narrow 64->32, combining to V128 */
925static IRExpr* mkV128from4x64S ( IRExpr* t3, IRExpr* t2,
926 IRExpr* t1, IRExpr* t0 )
927{
sewardjdd40fdf2006-12-24 02:20:24 +0000928 vassert(typeOfIRExpr(irsb->tyenv, t3) == Ity_I64);
929 vassert(typeOfIRExpr(irsb->tyenv, t2) == Ity_I64);
930 vassert(typeOfIRExpr(irsb->tyenv, t1) == Ity_I64);
931 vassert(typeOfIRExpr(irsb->tyenv, t0) == Ity_I64);
cerion4a49b032005-11-08 16:23:07 +0000932 return binop(Iop_64HLtoV128,
933 binop(Iop_32HLto64,
934 mkQNarrow64Sto32( t3 ),
935 mkQNarrow64Sto32( t2 )),
936 binop(Iop_32HLto64,
937 mkQNarrow64Sto32( t1 ),
938 mkQNarrow64Sto32( t0 )));
939}
940
941/* Unsigned saturate narrow 64->32, combining to V128 */
942static IRExpr* mkV128from4x64U ( IRExpr* t3, IRExpr* t2,
943 IRExpr* t1, IRExpr* t0 )
944{
sewardjdd40fdf2006-12-24 02:20:24 +0000945 vassert(typeOfIRExpr(irsb->tyenv, t3) == Ity_I64);
946 vassert(typeOfIRExpr(irsb->tyenv, t2) == Ity_I64);
947 vassert(typeOfIRExpr(irsb->tyenv, t1) == Ity_I64);
948 vassert(typeOfIRExpr(irsb->tyenv, t0) == Ity_I64);
cerion4a49b032005-11-08 16:23:07 +0000949 return binop(Iop_64HLtoV128,
950 binop(Iop_32HLto64,
951 mkQNarrow64Uto32( t3 ),
952 mkQNarrow64Uto32( t2 )),
953 binop(Iop_32HLto64,
954 mkQNarrow64Uto32( t1 ),
955 mkQNarrow64Uto32( t0 )));
956}
957
cerion24d06f12005-11-09 21:34:20 +0000958/* Simulate irops Iop_MullOdd*, since we don't have them */
959#define MK_Iop_MullOdd8Ux16( expr_vA, expr_vB ) \
960 binop(Iop_MullEven8Ux16, \
961 binop(Iop_ShrV128, expr_vA, mkU8(8)), \
962 binop(Iop_ShrV128, expr_vB, mkU8(8)))
963
964#define MK_Iop_MullOdd8Sx16( expr_vA, expr_vB ) \
965 binop(Iop_MullEven8Sx16, \
966 binop(Iop_ShrV128, expr_vA, mkU8(8)), \
967 binop(Iop_ShrV128, expr_vB, mkU8(8)))
968
969#define MK_Iop_MullOdd16Ux8( expr_vA, expr_vB ) \
970 binop(Iop_MullEven16Ux8, \
971 binop(Iop_ShrV128, expr_vA, mkU8(16)), \
972 binop(Iop_ShrV128, expr_vB, mkU8(16)))
973
carll48ae46b2013-10-01 15:45:54 +0000974#define MK_Iop_MullOdd32Ux4( expr_vA, expr_vB ) \
975 binop(Iop_MullEven32Ux4, \
976 binop(Iop_ShrV128, expr_vA, mkU8(32)), \
977 binop(Iop_ShrV128, expr_vB, mkU8(32)))
978
cerion24d06f12005-11-09 21:34:20 +0000979#define MK_Iop_MullOdd16Sx8( expr_vA, expr_vB ) \
980 binop(Iop_MullEven16Sx8, \
981 binop(Iop_ShrV128, expr_vA, mkU8(16)), \
982 binop(Iop_ShrV128, expr_vB, mkU8(16)))
983
carll48ae46b2013-10-01 15:45:54 +0000984#define MK_Iop_MullOdd32Sx4( expr_vA, expr_vB ) \
985 binop(Iop_MullEven32Sx4, \
986 binop(Iop_ShrV128, expr_vA, mkU8(32)), \
987 binop(Iop_ShrV128, expr_vB, mkU8(32)))
988
989
cerion59b2c312005-12-17 11:28:53 +0000990static IRExpr* /* :: Ity_I64 */ mk64lo32Sto64 ( IRExpr* src )
ceriond953ebb2005-11-29 13:27:20 +0000991{
sewardjdd40fdf2006-12-24 02:20:24 +0000992 vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_I64);
ceriond953ebb2005-11-29 13:27:20 +0000993 return unop(Iop_32Sto64, unop(Iop_64to32, src));
994}
995
cerion59b2c312005-12-17 11:28:53 +0000996static IRExpr* /* :: Ity_I64 */ mk64lo32Uto64 ( IRExpr* src )
cerionbb01b7c2005-12-16 13:40:18 +0000997{
sewardjdd40fdf2006-12-24 02:20:24 +0000998 vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_I64);
cerionbb01b7c2005-12-16 13:40:18 +0000999 return unop(Iop_32Uto64, unop(Iop_64to32, src));
1000}
1001
cerion2831b002005-11-30 19:55:22 +00001002static IROp mkSzOp ( IRType ty, IROp op8 )
ceriond953ebb2005-11-29 13:27:20 +00001003{
1004 Int adj;
1005 vassert(ty == Ity_I8 || ty == Ity_I16 ||
1006 ty == Ity_I32 || ty == Ity_I64);
1007 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8 || op8 == Iop_Mul8 ||
1008 op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8 ||
1009 op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8 ||
1010 op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8 ||
sewardjeb17e492007-08-25 23:07:44 +00001011 op8 == Iop_Not8 );
ceriond953ebb2005-11-29 13:27:20 +00001012 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : (ty==Ity_I32 ? 2 : 3));
1013 return adj + op8;
1014}
1015
cerion5b2325f2005-12-23 00:55:09 +00001016/* Make sure we get valid 32 and 64bit addresses */
cerion2831b002005-11-30 19:55:22 +00001017static Addr64 mkSzAddr ( IRType ty, Addr64 addr )
ceriond953ebb2005-11-29 13:27:20 +00001018{
1019 vassert(ty == Ity_I32 || ty == Ity_I64);
1020 return ( ty == Ity_I64 ?
1021 (Addr64)addr :
1022 (Addr64)extend_s_32to64( toUInt(addr) ) );
1023}
1024
1025/* sz, ULong -> IRExpr */
cerion2831b002005-11-30 19:55:22 +00001026static IRExpr* mkSzImm ( IRType ty, ULong imm64 )
ceriond953ebb2005-11-29 13:27:20 +00001027{
1028 vassert(ty == Ity_I32 || ty == Ity_I64);
1029 return ty == Ity_I64 ? mkU64(imm64) : mkU32((UInt)imm64);
1030}
1031
1032/* sz, ULong -> IRConst */
cerion2831b002005-11-30 19:55:22 +00001033static IRConst* mkSzConst ( IRType ty, ULong imm64 )
ceriond953ebb2005-11-29 13:27:20 +00001034{
1035 vassert(ty == Ity_I32 || ty == Ity_I64);
1036 return ( ty == Ity_I64 ?
1037 IRConst_U64(imm64) :
1038 IRConst_U32((UInt)imm64) );
1039}
1040
1041/* Sign extend imm16 -> IRExpr* */
cerion2831b002005-11-30 19:55:22 +00001042static IRExpr* mkSzExtendS16 ( IRType ty, UInt imm16 )
ceriond953ebb2005-11-29 13:27:20 +00001043{
1044 vassert(ty == Ity_I32 || ty == Ity_I64);
1045 return ( ty == Ity_I64 ?
1046 mkU64(extend_s_16to64(imm16)) :
1047 mkU32(extend_s_16to32(imm16)) );
1048}
1049
1050/* Sign extend imm32 -> IRExpr* */
cerion2831b002005-11-30 19:55:22 +00001051static IRExpr* mkSzExtendS32 ( IRType ty, UInt imm32 )
ceriond953ebb2005-11-29 13:27:20 +00001052{
1053 vassert(ty == Ity_I32 || ty == Ity_I64);
1054 return ( ty == Ity_I64 ?
1055 mkU64(extend_s_32to64(imm32)) :
1056 mkU32(imm32) );
1057}
1058
1059/* IR narrows I32/I64 -> I8/I16/I32 */
sewardje9d8a262009-07-01 08:06:34 +00001060static IRExpr* mkNarrowTo8 ( IRType ty, IRExpr* src )
ceriond953ebb2005-11-29 13:27:20 +00001061{
1062 vassert(ty == Ity_I32 || ty == Ity_I64);
1063 return ty == Ity_I64 ? unop(Iop_64to8, src) : unop(Iop_32to8, src);
1064}
1065
sewardje9d8a262009-07-01 08:06:34 +00001066static IRExpr* mkNarrowTo16 ( IRType ty, IRExpr* src )
ceriond953ebb2005-11-29 13:27:20 +00001067{
1068 vassert(ty == Ity_I32 || ty == Ity_I64);
1069 return ty == Ity_I64 ? unop(Iop_64to16, src) : unop(Iop_32to16, src);
1070}
1071
sewardje9d8a262009-07-01 08:06:34 +00001072static IRExpr* mkNarrowTo32 ( IRType ty, IRExpr* src )
ceriond953ebb2005-11-29 13:27:20 +00001073{
1074 vassert(ty == Ity_I32 || ty == Ity_I64);
1075 return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
1076}
1077
1078/* Signed/Unsigned IR widens I8/I16/I32 -> I32/I64 */
sewardje9d8a262009-07-01 08:06:34 +00001079static IRExpr* mkWidenFrom8 ( IRType ty, IRExpr* src, Bool sined )
ceriond953ebb2005-11-29 13:27:20 +00001080{
ceriond953ebb2005-11-29 13:27:20 +00001081 IROp op;
sewardj63327402006-01-25 03:26:27 +00001082 vassert(ty == Ity_I32 || ty == Ity_I64);
ceriond953ebb2005-11-29 13:27:20 +00001083 if (sined) op = (ty==Ity_I32) ? Iop_8Sto32 : Iop_8Sto64;
1084 else op = (ty==Ity_I32) ? Iop_8Uto32 : Iop_8Uto64;
1085 return unop(op, src);
1086}
1087
sewardje9d8a262009-07-01 08:06:34 +00001088static IRExpr* mkWidenFrom16 ( IRType ty, IRExpr* src, Bool sined )
ceriond953ebb2005-11-29 13:27:20 +00001089{
ceriond953ebb2005-11-29 13:27:20 +00001090 IROp op;
sewardj63327402006-01-25 03:26:27 +00001091 vassert(ty == Ity_I32 || ty == Ity_I64);
ceriond953ebb2005-11-29 13:27:20 +00001092 if (sined) op = (ty==Ity_I32) ? Iop_16Sto32 : Iop_16Sto64;
1093 else op = (ty==Ity_I32) ? Iop_16Uto32 : Iop_16Uto64;
1094 return unop(op, src);
1095}
1096
sewardje9d8a262009-07-01 08:06:34 +00001097static IRExpr* mkWidenFrom32 ( IRType ty, IRExpr* src, Bool sined )
ceriond953ebb2005-11-29 13:27:20 +00001098{
1099 vassert(ty == Ity_I32 || ty == Ity_I64);
1100 if (ty == Ity_I32)
1101 return src;
1102 return (sined) ? unop(Iop_32Sto64, src) : unop(Iop_32Uto64, src);
1103}
cerion24d06f12005-11-09 21:34:20 +00001104
cerion4a49b032005-11-08 16:23:07 +00001105
sewardjb51f0f42005-07-18 11:38:02 +00001106static Int integerGuestRegOffset ( UInt archreg )
cerion45b70ff2005-01-31 17:03:25 +00001107{
sewardjb51f0f42005-07-18 11:38:02 +00001108 vassert(archreg < 32);
1109
1110 // jrs: probably not necessary; only matters if we reference sub-parts
cerion5b2325f2005-12-23 00:55:09 +00001111 // of the ppc registers, but that isn't the case
sewardjb51f0f42005-07-18 11:38:02 +00001112 // later: this might affect Altivec though?
sewardjb51f0f42005-07-18 11:38:02 +00001113
cerion5b2325f2005-12-23 00:55:09 +00001114 switch (archreg) {
1115 case 0: return offsetofPPCGuestState(guest_GPR0);
1116 case 1: return offsetofPPCGuestState(guest_GPR1);
1117 case 2: return offsetofPPCGuestState(guest_GPR2);
1118 case 3: return offsetofPPCGuestState(guest_GPR3);
1119 case 4: return offsetofPPCGuestState(guest_GPR4);
1120 case 5: return offsetofPPCGuestState(guest_GPR5);
1121 case 6: return offsetofPPCGuestState(guest_GPR6);
1122 case 7: return offsetofPPCGuestState(guest_GPR7);
1123 case 8: return offsetofPPCGuestState(guest_GPR8);
1124 case 9: return offsetofPPCGuestState(guest_GPR9);
1125 case 10: return offsetofPPCGuestState(guest_GPR10);
1126 case 11: return offsetofPPCGuestState(guest_GPR11);
1127 case 12: return offsetofPPCGuestState(guest_GPR12);
1128 case 13: return offsetofPPCGuestState(guest_GPR13);
1129 case 14: return offsetofPPCGuestState(guest_GPR14);
1130 case 15: return offsetofPPCGuestState(guest_GPR15);
1131 case 16: return offsetofPPCGuestState(guest_GPR16);
1132 case 17: return offsetofPPCGuestState(guest_GPR17);
1133 case 18: return offsetofPPCGuestState(guest_GPR18);
1134 case 19: return offsetofPPCGuestState(guest_GPR19);
1135 case 20: return offsetofPPCGuestState(guest_GPR20);
1136 case 21: return offsetofPPCGuestState(guest_GPR21);
1137 case 22: return offsetofPPCGuestState(guest_GPR22);
1138 case 23: return offsetofPPCGuestState(guest_GPR23);
1139 case 24: return offsetofPPCGuestState(guest_GPR24);
1140 case 25: return offsetofPPCGuestState(guest_GPR25);
1141 case 26: return offsetofPPCGuestState(guest_GPR26);
1142 case 27: return offsetofPPCGuestState(guest_GPR27);
1143 case 28: return offsetofPPCGuestState(guest_GPR28);
1144 case 29: return offsetofPPCGuestState(guest_GPR29);
1145 case 30: return offsetofPPCGuestState(guest_GPR30);
1146 case 31: return offsetofPPCGuestState(guest_GPR31);
1147 default: break;
sewardjb51f0f42005-07-18 11:38:02 +00001148 }
cerion5b2325f2005-12-23 00:55:09 +00001149 vpanic("integerGuestRegOffset(ppc,be)"); /*notreached*/
sewardjb51f0f42005-07-18 11:38:02 +00001150}
1151
1152static IRExpr* getIReg ( UInt archreg )
1153{
ceriond953ebb2005-11-29 13:27:20 +00001154 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardjb51f0f42005-07-18 11:38:02 +00001155 vassert(archreg < 32);
ceriond953ebb2005-11-29 13:27:20 +00001156 return IRExpr_Get( integerGuestRegOffset(archreg), ty );
sewardjb51f0f42005-07-18 11:38:02 +00001157}
1158
1159/* Ditto, but write to a reg instead. */
1160static void putIReg ( UInt archreg, IRExpr* e )
1161{
ceriond953ebb2005-11-29 13:27:20 +00001162 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardjb51f0f42005-07-18 11:38:02 +00001163 vassert(archreg < 32);
sewardjdd40fdf2006-12-24 02:20:24 +00001164 vassert(typeOfIRExpr(irsb->tyenv, e) == ty );
sewardjb51f0f42005-07-18 11:38:02 +00001165 stmt( IRStmt_Put(integerGuestRegOffset(archreg), e) );
1166}
1167
1168
sewardj66d5ef22011-04-15 11:55:00 +00001169/* Floating point egisters are mapped to VSX registers[0..31]. */
sewardjb51f0f42005-07-18 11:38:02 +00001170static Int floatGuestRegOffset ( UInt archreg )
1171{
1172 vassert(archreg < 32);
1173
carll1f5fe1f2014-08-07 23:25:23 +00001174 if (host_endness == VexEndnessLE) {
1175 switch (archreg) {
1176 case 0: return offsetofPPCGuestState(guest_VSR0 + 8);
1177 case 1: return offsetofPPCGuestState(guest_VSR1 + 8);
1178 case 2: return offsetofPPCGuestState(guest_VSR2 + 8);
1179 case 3: return offsetofPPCGuestState(guest_VSR3 + 8);
1180 case 4: return offsetofPPCGuestState(guest_VSR4 + 8);
1181 case 5: return offsetofPPCGuestState(guest_VSR5 + 8);
1182 case 6: return offsetofPPCGuestState(guest_VSR6 + 8);
1183 case 7: return offsetofPPCGuestState(guest_VSR7 + 8);
1184 case 8: return offsetofPPCGuestState(guest_VSR8 + 8);
1185 case 9: return offsetofPPCGuestState(guest_VSR9 + 8);
1186 case 10: return offsetofPPCGuestState(guest_VSR10 + 8);
1187 case 11: return offsetofPPCGuestState(guest_VSR11 + 8);
1188 case 12: return offsetofPPCGuestState(guest_VSR12 + 8);
1189 case 13: return offsetofPPCGuestState(guest_VSR13 + 8);
1190 case 14: return offsetofPPCGuestState(guest_VSR14 + 8);
1191 case 15: return offsetofPPCGuestState(guest_VSR15 + 8);
1192 case 16: return offsetofPPCGuestState(guest_VSR16 + 8);
1193 case 17: return offsetofPPCGuestState(guest_VSR17 + 8);
1194 case 18: return offsetofPPCGuestState(guest_VSR18 + 8);
1195 case 19: return offsetofPPCGuestState(guest_VSR19 + 8);
1196 case 20: return offsetofPPCGuestState(guest_VSR20 + 8);
1197 case 21: return offsetofPPCGuestState(guest_VSR21 + 8);
1198 case 22: return offsetofPPCGuestState(guest_VSR22 + 8);
1199 case 23: return offsetofPPCGuestState(guest_VSR23 + 8);
1200 case 24: return offsetofPPCGuestState(guest_VSR24 + 8);
1201 case 25: return offsetofPPCGuestState(guest_VSR25 + 8);
1202 case 26: return offsetofPPCGuestState(guest_VSR26 + 8);
1203 case 27: return offsetofPPCGuestState(guest_VSR27 + 8);
1204 case 28: return offsetofPPCGuestState(guest_VSR28 + 8);
1205 case 29: return offsetofPPCGuestState(guest_VSR29 + 8);
1206 case 30: return offsetofPPCGuestState(guest_VSR30 + 8);
1207 case 31: return offsetofPPCGuestState(guest_VSR31 + 8);
1208 default: break;
1209 }
1210 } else {
1211 switch (archreg) {
1212 case 0: return offsetofPPCGuestState(guest_VSR0);
1213 case 1: return offsetofPPCGuestState(guest_VSR1);
1214 case 2: return offsetofPPCGuestState(guest_VSR2);
1215 case 3: return offsetofPPCGuestState(guest_VSR3);
1216 case 4: return offsetofPPCGuestState(guest_VSR4);
1217 case 5: return offsetofPPCGuestState(guest_VSR5);
1218 case 6: return offsetofPPCGuestState(guest_VSR6);
1219 case 7: return offsetofPPCGuestState(guest_VSR7);
1220 case 8: return offsetofPPCGuestState(guest_VSR8);
1221 case 9: return offsetofPPCGuestState(guest_VSR9);
1222 case 10: return offsetofPPCGuestState(guest_VSR10);
1223 case 11: return offsetofPPCGuestState(guest_VSR11);
1224 case 12: return offsetofPPCGuestState(guest_VSR12);
1225 case 13: return offsetofPPCGuestState(guest_VSR13);
1226 case 14: return offsetofPPCGuestState(guest_VSR14);
1227 case 15: return offsetofPPCGuestState(guest_VSR15);
1228 case 16: return offsetofPPCGuestState(guest_VSR16);
1229 case 17: return offsetofPPCGuestState(guest_VSR17);
1230 case 18: return offsetofPPCGuestState(guest_VSR18);
1231 case 19: return offsetofPPCGuestState(guest_VSR19);
1232 case 20: return offsetofPPCGuestState(guest_VSR20);
1233 case 21: return offsetofPPCGuestState(guest_VSR21);
1234 case 22: return offsetofPPCGuestState(guest_VSR22);
1235 case 23: return offsetofPPCGuestState(guest_VSR23);
1236 case 24: return offsetofPPCGuestState(guest_VSR24);
1237 case 25: return offsetofPPCGuestState(guest_VSR25);
1238 case 26: return offsetofPPCGuestState(guest_VSR26);
1239 case 27: return offsetofPPCGuestState(guest_VSR27);
1240 case 28: return offsetofPPCGuestState(guest_VSR28);
1241 case 29: return offsetofPPCGuestState(guest_VSR29);
1242 case 30: return offsetofPPCGuestState(guest_VSR30);
1243 case 31: return offsetofPPCGuestState(guest_VSR31);
1244 default: break;
1245 }
sewardjb51f0f42005-07-18 11:38:02 +00001246 }
cerion5b2325f2005-12-23 00:55:09 +00001247 vpanic("floatGuestRegOffset(ppc)"); /*notreached*/
sewardjb51f0f42005-07-18 11:38:02 +00001248}
1249
1250static IRExpr* getFReg ( UInt archreg )
1251{
1252 vassert(archreg < 32);
1253 return IRExpr_Get( floatGuestRegOffset(archreg), Ity_F64 );
1254}
1255
1256/* Ditto, but write to a reg instead. */
1257static void putFReg ( UInt archreg, IRExpr* e )
1258{
1259 vassert(archreg < 32);
sewardjdd40fdf2006-12-24 02:20:24 +00001260 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
sewardjb51f0f42005-07-18 11:38:02 +00001261 stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
1262}
1263
sewardjc6bbd472012-04-02 10:20:48 +00001264/* get Decimal float value. Note, they share floating point register file. */
1265static IRExpr* getDReg(UInt archreg) {
1266 IRExpr *e;
1267 vassert( archreg < 32 );
1268 e = IRExpr_Get( floatGuestRegOffset( archreg ), Ity_D64 );
1269 return e;
1270}
carllf704eb22013-01-21 18:12:31 +00001271static IRExpr* getDReg32(UInt archreg) {
1272 IRExpr *e;
1273 vassert( archreg < 32 );
1274 e = IRExpr_Get( floatGuestRegOffset( archreg ), Ity_D32 );
1275 return e;
1276}
sewardjc6bbd472012-04-02 10:20:48 +00001277
1278/* Read a floating point register pair and combine their contents into a
1279 128-bit value */
1280static IRExpr *getDReg_pair(UInt archreg) {
1281 IRExpr *high = getDReg( archreg );
1282 IRExpr *low = getDReg( archreg + 1 );
1283
1284 return binop( Iop_D64HLtoD128, high, low );
1285}
1286
1287/* Ditto, but write to a reg instead. */
carllf704eb22013-01-21 18:12:31 +00001288static void putDReg32(UInt archreg, IRExpr* e) {
1289 vassert( archreg < 32 );
1290 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D32 );
1291 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), e ) );
1292}
1293
sewardjc6bbd472012-04-02 10:20:48 +00001294static void putDReg(UInt archreg, IRExpr* e) {
1295 vassert( archreg < 32 );
1296 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D64 );
1297 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), e ) );
1298}
1299
1300/* Write a 128-bit floating point value into a register pair. */
1301static void putDReg_pair(UInt archreg, IRExpr *e) {
1302 IRTemp low = newTemp( Ity_D64 );
1303 IRTemp high = newTemp( Ity_D64 );
1304
1305 vassert( archreg < 32 );
1306 vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_D128 );
1307
1308 assign( low, unop( Iop_D128LOtoD64, e ) );
1309 assign( high, unop( Iop_D128HItoD64, e ) );
1310
1311 stmt( IRStmt_Put( floatGuestRegOffset( archreg ), mkexpr( high ) ) );
1312 stmt( IRStmt_Put( floatGuestRegOffset( archreg + 1 ), mkexpr( low ) ) );
1313}
1314
sewardj66d5ef22011-04-15 11:55:00 +00001315static Int vsxGuestRegOffset ( UInt archreg )
1316{
1317 vassert(archreg < 64);
1318 switch (archreg) {
1319 case 0: return offsetofPPCGuestState(guest_VSR0);
1320 case 1: return offsetofPPCGuestState(guest_VSR1);
1321 case 2: return offsetofPPCGuestState(guest_VSR2);
1322 case 3: return offsetofPPCGuestState(guest_VSR3);
1323 case 4: return offsetofPPCGuestState(guest_VSR4);
1324 case 5: return offsetofPPCGuestState(guest_VSR5);
1325 case 6: return offsetofPPCGuestState(guest_VSR6);
1326 case 7: return offsetofPPCGuestState(guest_VSR7);
1327 case 8: return offsetofPPCGuestState(guest_VSR8);
1328 case 9: return offsetofPPCGuestState(guest_VSR9);
1329 case 10: return offsetofPPCGuestState(guest_VSR10);
1330 case 11: return offsetofPPCGuestState(guest_VSR11);
1331 case 12: return offsetofPPCGuestState(guest_VSR12);
1332 case 13: return offsetofPPCGuestState(guest_VSR13);
1333 case 14: return offsetofPPCGuestState(guest_VSR14);
1334 case 15: return offsetofPPCGuestState(guest_VSR15);
1335 case 16: return offsetofPPCGuestState(guest_VSR16);
1336 case 17: return offsetofPPCGuestState(guest_VSR17);
1337 case 18: return offsetofPPCGuestState(guest_VSR18);
1338 case 19: return offsetofPPCGuestState(guest_VSR19);
1339 case 20: return offsetofPPCGuestState(guest_VSR20);
1340 case 21: return offsetofPPCGuestState(guest_VSR21);
1341 case 22: return offsetofPPCGuestState(guest_VSR22);
1342 case 23: return offsetofPPCGuestState(guest_VSR23);
1343 case 24: return offsetofPPCGuestState(guest_VSR24);
1344 case 25: return offsetofPPCGuestState(guest_VSR25);
1345 case 26: return offsetofPPCGuestState(guest_VSR26);
1346 case 27: return offsetofPPCGuestState(guest_VSR27);
1347 case 28: return offsetofPPCGuestState(guest_VSR28);
1348 case 29: return offsetofPPCGuestState(guest_VSR29);
1349 case 30: return offsetofPPCGuestState(guest_VSR30);
1350 case 31: return offsetofPPCGuestState(guest_VSR31);
1351 case 32: return offsetofPPCGuestState(guest_VSR32);
1352 case 33: return offsetofPPCGuestState(guest_VSR33);
1353 case 34: return offsetofPPCGuestState(guest_VSR34);
1354 case 35: return offsetofPPCGuestState(guest_VSR35);
1355 case 36: return offsetofPPCGuestState(guest_VSR36);
1356 case 37: return offsetofPPCGuestState(guest_VSR37);
1357 case 38: return offsetofPPCGuestState(guest_VSR38);
1358 case 39: return offsetofPPCGuestState(guest_VSR39);
1359 case 40: return offsetofPPCGuestState(guest_VSR40);
1360 case 41: return offsetofPPCGuestState(guest_VSR41);
1361 case 42: return offsetofPPCGuestState(guest_VSR42);
1362 case 43: return offsetofPPCGuestState(guest_VSR43);
1363 case 44: return offsetofPPCGuestState(guest_VSR44);
1364 case 45: return offsetofPPCGuestState(guest_VSR45);
1365 case 46: return offsetofPPCGuestState(guest_VSR46);
1366 case 47: return offsetofPPCGuestState(guest_VSR47);
1367 case 48: return offsetofPPCGuestState(guest_VSR48);
1368 case 49: return offsetofPPCGuestState(guest_VSR49);
1369 case 50: return offsetofPPCGuestState(guest_VSR50);
1370 case 51: return offsetofPPCGuestState(guest_VSR51);
1371 case 52: return offsetofPPCGuestState(guest_VSR52);
1372 case 53: return offsetofPPCGuestState(guest_VSR53);
1373 case 54: return offsetofPPCGuestState(guest_VSR54);
1374 case 55: return offsetofPPCGuestState(guest_VSR55);
1375 case 56: return offsetofPPCGuestState(guest_VSR56);
1376 case 57: return offsetofPPCGuestState(guest_VSR57);
1377 case 58: return offsetofPPCGuestState(guest_VSR58);
1378 case 59: return offsetofPPCGuestState(guest_VSR59);
1379 case 60: return offsetofPPCGuestState(guest_VSR60);
1380 case 61: return offsetofPPCGuestState(guest_VSR61);
1381 case 62: return offsetofPPCGuestState(guest_VSR62);
1382 case 63: return offsetofPPCGuestState(guest_VSR63);
1383 default: break;
1384 }
1385 vpanic("vsxGuestRegOffset(ppc)"); /*notreached*/
1386}
sewardjb51f0f42005-07-18 11:38:02 +00001387
sewardj66d5ef22011-04-15 11:55:00 +00001388/* Vector registers are mapped to VSX registers[32..63]. */
sewardjb51f0f42005-07-18 11:38:02 +00001389static Int vectorGuestRegOffset ( UInt archreg )
1390{
1391 vassert(archreg < 32);
1392
cerion5b2325f2005-12-23 00:55:09 +00001393 switch (archreg) {
sewardj66d5ef22011-04-15 11:55:00 +00001394 case 0: return offsetofPPCGuestState(guest_VSR32);
1395 case 1: return offsetofPPCGuestState(guest_VSR33);
1396 case 2: return offsetofPPCGuestState(guest_VSR34);
1397 case 3: return offsetofPPCGuestState(guest_VSR35);
1398 case 4: return offsetofPPCGuestState(guest_VSR36);
1399 case 5: return offsetofPPCGuestState(guest_VSR37);
1400 case 6: return offsetofPPCGuestState(guest_VSR38);
1401 case 7: return offsetofPPCGuestState(guest_VSR39);
1402 case 8: return offsetofPPCGuestState(guest_VSR40);
1403 case 9: return offsetofPPCGuestState(guest_VSR41);
1404 case 10: return offsetofPPCGuestState(guest_VSR42);
1405 case 11: return offsetofPPCGuestState(guest_VSR43);
1406 case 12: return offsetofPPCGuestState(guest_VSR44);
1407 case 13: return offsetofPPCGuestState(guest_VSR45);
1408 case 14: return offsetofPPCGuestState(guest_VSR46);
1409 case 15: return offsetofPPCGuestState(guest_VSR47);
1410 case 16: return offsetofPPCGuestState(guest_VSR48);
1411 case 17: return offsetofPPCGuestState(guest_VSR49);
1412 case 18: return offsetofPPCGuestState(guest_VSR50);
1413 case 19: return offsetofPPCGuestState(guest_VSR51);
1414 case 20: return offsetofPPCGuestState(guest_VSR52);
1415 case 21: return offsetofPPCGuestState(guest_VSR53);
1416 case 22: return offsetofPPCGuestState(guest_VSR54);
1417 case 23: return offsetofPPCGuestState(guest_VSR55);
1418 case 24: return offsetofPPCGuestState(guest_VSR56);
1419 case 25: return offsetofPPCGuestState(guest_VSR57);
1420 case 26: return offsetofPPCGuestState(guest_VSR58);
1421 case 27: return offsetofPPCGuestState(guest_VSR59);
1422 case 28: return offsetofPPCGuestState(guest_VSR60);
1423 case 29: return offsetofPPCGuestState(guest_VSR61);
1424 case 30: return offsetofPPCGuestState(guest_VSR62);
1425 case 31: return offsetofPPCGuestState(guest_VSR63);
cerion5b2325f2005-12-23 00:55:09 +00001426 default: break;
sewardjb51f0f42005-07-18 11:38:02 +00001427 }
cerion5b2325f2005-12-23 00:55:09 +00001428 vpanic("vextorGuestRegOffset(ppc)"); /*notreached*/
sewardjb51f0f42005-07-18 11:38:02 +00001429}
1430
1431static IRExpr* getVReg ( UInt archreg )
1432{
1433 vassert(archreg < 32);
1434 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 );
1435}
1436
1437/* Ditto, but write to a reg instead. */
1438static void putVReg ( UInt archreg, IRExpr* e )
1439{
1440 vassert(archreg < 32);
sewardjdd40fdf2006-12-24 02:20:24 +00001441 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
sewardjb51f0f42005-07-18 11:38:02 +00001442 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
1443}
1444
sewardj66d5ef22011-04-15 11:55:00 +00001445/* Get contents of VSX guest register */
1446static IRExpr* getVSReg ( UInt archreg )
1447{
1448 vassert(archreg < 64);
1449 return IRExpr_Get( vsxGuestRegOffset(archreg), Ity_V128 );
1450}
1451
1452/* Ditto, but write to a VSX reg instead. */
1453static void putVSReg ( UInt archreg, IRExpr* e )
1454{
1455 vassert(archreg < 64);
1456 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
1457 stmt( IRStmt_Put(vsxGuestRegOffset(archreg), e) );
1458}
1459
1460
sewardjb51f0f42005-07-18 11:38:02 +00001461static Int guestCR321offset ( UInt cr )
1462{
cerion5b2325f2005-12-23 00:55:09 +00001463 switch (cr) {
1464 case 0: return offsetofPPCGuestState(guest_CR0_321 );
1465 case 1: return offsetofPPCGuestState(guest_CR1_321 );
1466 case 2: return offsetofPPCGuestState(guest_CR2_321 );
1467 case 3: return offsetofPPCGuestState(guest_CR3_321 );
1468 case 4: return offsetofPPCGuestState(guest_CR4_321 );
1469 case 5: return offsetofPPCGuestState(guest_CR5_321 );
1470 case 6: return offsetofPPCGuestState(guest_CR6_321 );
1471 case 7: return offsetofPPCGuestState(guest_CR7_321 );
1472 default: vpanic("guestCR321offset(ppc)");
sewardjb51f0f42005-07-18 11:38:02 +00001473 }
1474}
1475
1476static Int guestCR0offset ( UInt cr )
1477{
cerion5b2325f2005-12-23 00:55:09 +00001478 switch (cr) {
1479 case 0: return offsetofPPCGuestState(guest_CR0_0 );
1480 case 1: return offsetofPPCGuestState(guest_CR1_0 );
1481 case 2: return offsetofPPCGuestState(guest_CR2_0 );
1482 case 3: return offsetofPPCGuestState(guest_CR3_0 );
1483 case 4: return offsetofPPCGuestState(guest_CR4_0 );
1484 case 5: return offsetofPPCGuestState(guest_CR5_0 );
1485 case 6: return offsetofPPCGuestState(guest_CR6_0 );
1486 case 7: return offsetofPPCGuestState(guest_CR7_0 );
1487 default: vpanic("guestCR3offset(ppc)");
sewardjb51f0f42005-07-18 11:38:02 +00001488 }
sewardjb51f0f42005-07-18 11:38:02 +00001489}
1490
carll7deaf952013-10-15 18:11:20 +00001491typedef enum {
1492 _placeholder0,
1493 _placeholder1,
1494 _placeholder2,
1495 BYTE,
1496 HWORD,
1497 WORD,
1498 DWORD
1499} _popcount_data_type;
1500
sewardj66d5ef22011-04-15 11:55:00 +00001501/* Generate an IR sequence to do a popcount operation on the supplied
sewardje71e56a2011-09-05 12:11:06 +00001502 IRTemp, and return a new IRTemp holding the result. 'ty' may be
1503 Ity_I32 or Ity_I64 only. */
carll7deaf952013-10-15 18:11:20 +00001504static IRTemp gen_POPCOUNT ( IRType ty, IRTemp src, _popcount_data_type data_type )
sewardj66d5ef22011-04-15 11:55:00 +00001505{
carll7deaf952013-10-15 18:11:20 +00001506 /* Do count across 2^data_type bits,
1507 byte: data_type = 3
1508 half word: data_type = 4
1509 word: data_type = 5
1510 double word: data_type = 6 (not supported for 32-bit type)
1511 */
1512 Int shift[6];
1513 _popcount_data_type idx, i;
sewardje71e56a2011-09-05 12:11:06 +00001514 IRTemp mask[6];
sewardj66d5ef22011-04-15 11:55:00 +00001515 IRTemp old = IRTemp_INVALID;
1516 IRTemp nyu = IRTemp_INVALID;
sewardj66d5ef22011-04-15 11:55:00 +00001517
sewardje71e56a2011-09-05 12:11:06 +00001518 vassert(ty == Ity_I64 || ty == Ity_I32);
1519
1520 if (ty == Ity_I32) {
philippe738d9dd2012-07-06 21:56:53 +00001521
carll7deaf952013-10-15 18:11:20 +00001522 for (idx = 0; idx < WORD; idx++) {
1523 mask[idx] = newTemp(ty);
1524 shift[idx] = 1 << idx;
sewardje71e56a2011-09-05 12:11:06 +00001525 }
1526 assign(mask[0], mkU32(0x55555555));
1527 assign(mask[1], mkU32(0x33333333));
1528 assign(mask[2], mkU32(0x0F0F0F0F));
1529 assign(mask[3], mkU32(0x00FF00FF));
1530 assign(mask[4], mkU32(0x0000FFFF));
1531 old = src;
carll7deaf952013-10-15 18:11:20 +00001532 for (i = 0; i < data_type; i++) {
sewardje71e56a2011-09-05 12:11:06 +00001533 nyu = newTemp(ty);
1534 assign(nyu,
1535 binop(Iop_Add32,
1536 binop(Iop_And32,
1537 mkexpr(old),
1538 mkexpr(mask[i])),
1539 binop(Iop_And32,
1540 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
1541 mkexpr(mask[i]))));
1542 old = nyu;
1543 }
1544 return nyu;
1545 }
philippe738d9dd2012-07-06 21:56:53 +00001546
carll7deaf952013-10-15 18:11:20 +00001547// else, ty == Ity_I64
1548 vassert(mode64);
1549
1550 for (i = 0; i < DWORD; i++) {
sewardj66d5ef22011-04-15 11:55:00 +00001551 mask[i] = newTemp( Ity_I64 );
1552 shift[i] = 1 << i;
1553 }
1554 assign( mask[0], mkU64( 0x5555555555555555ULL ) );
1555 assign( mask[1], mkU64( 0x3333333333333333ULL ) );
1556 assign( mask[2], mkU64( 0x0F0F0F0F0F0F0F0FULL ) );
1557 assign( mask[3], mkU64( 0x00FF00FF00FF00FFULL ) );
1558 assign( mask[4], mkU64( 0x0000FFFF0000FFFFULL ) );
1559 assign( mask[5], mkU64( 0x00000000FFFFFFFFULL ) );
1560 old = src;
carll7deaf952013-10-15 18:11:20 +00001561 for (i = 0; i < data_type; i++) {
sewardj66d5ef22011-04-15 11:55:00 +00001562 nyu = newTemp( Ity_I64 );
1563 assign( nyu,
1564 binop( Iop_Add64,
1565 binop( Iop_And64, mkexpr( old ), mkexpr( mask[i] ) ),
1566 binop( Iop_And64,
1567 binop( Iop_Shr64, mkexpr( old ), mkU8( shift[i] ) ),
1568 mkexpr( mask[i] ) ) ) );
1569 old = nyu;
1570 }
1571 return nyu;
1572}
1573
carll7deaf952013-10-15 18:11:20 +00001574/* Special purpose population count function for
1575 * vpopcntd in 32-bit mode.
1576 */
1577static IRTemp gen_vpopcntd_mode32 ( IRTemp src1, IRTemp src2 )
1578{
1579 Int i, shift[6];
1580 IRTemp mask[6];
1581 IRTemp old = IRTemp_INVALID;
1582 IRTemp nyu1 = IRTemp_INVALID;
1583 IRTemp nyu2 = IRTemp_INVALID;
1584 IRTemp retval = newTemp(Ity_I64);
1585
1586 vassert(!mode64);
1587
1588 for (i = 0; i < WORD; i++) {
1589 mask[i] = newTemp(Ity_I32);
1590 shift[i] = 1 << i;
1591 }
1592 assign(mask[0], mkU32(0x55555555));
1593 assign(mask[1], mkU32(0x33333333));
1594 assign(mask[2], mkU32(0x0F0F0F0F));
1595 assign(mask[3], mkU32(0x00FF00FF));
1596 assign(mask[4], mkU32(0x0000FFFF));
1597 old = src1;
1598 for (i = 0; i < WORD; i++) {
1599 nyu1 = newTemp(Ity_I32);
1600 assign(nyu1,
1601 binop(Iop_Add32,
1602 binop(Iop_And32,
1603 mkexpr(old),
1604 mkexpr(mask[i])),
1605 binop(Iop_And32,
1606 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
1607 mkexpr(mask[i]))));
1608 old = nyu1;
1609 }
1610
1611 old = src2;
1612 for (i = 0; i < WORD; i++) {
1613 nyu2 = newTemp(Ity_I32);
1614 assign(nyu2,
1615 binop(Iop_Add32,
1616 binop(Iop_And32,
1617 mkexpr(old),
1618 mkexpr(mask[i])),
1619 binop(Iop_And32,
1620 binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
1621 mkexpr(mask[i]))));
1622 old = nyu2;
1623 }
1624 assign(retval, unop(Iop_32Uto64, binop(Iop_Add32, mkexpr(nyu1), mkexpr(nyu2))));
1625 return retval;
1626}
1627
sewardj66d5ef22011-04-15 11:55:00 +00001628
cerion07b07a92005-12-22 14:32:35 +00001629// ROTL(src32/64, rot_amt5/6)
ceriond953ebb2005-11-29 13:27:20 +00001630static IRExpr* /* :: Ity_I32/64 */ ROTL ( IRExpr* src,
1631 IRExpr* rot_amt )
sewardjb51f0f42005-07-18 11:38:02 +00001632{
ceriond953ebb2005-11-29 13:27:20 +00001633 IRExpr *mask, *rot;
sewardjdd40fdf2006-12-24 02:20:24 +00001634 vassert(typeOfIRExpr(irsb->tyenv,rot_amt) == Ity_I8);
sewardjb51f0f42005-07-18 11:38:02 +00001635
sewardjdd40fdf2006-12-24 02:20:24 +00001636 if (typeOfIRExpr(irsb->tyenv,src) == Ity_I64) {
ceriond953ebb2005-11-29 13:27:20 +00001637 // rot = (src << rot_amt) | (src >> (64-rot_amt))
1638 mask = binop(Iop_And8, rot_amt, mkU8(63));
1639 rot = binop(Iop_Or64,
1640 binop(Iop_Shl64, src, mask),
1641 binop(Iop_Shr64, src, binop(Iop_Sub8, mkU8(64), mask)));
1642 } else {
ceriond953ebb2005-11-29 13:27:20 +00001643 // rot = (src << rot_amt) | (src >> (32-rot_amt))
cerionf0de28c2005-12-13 20:21:11 +00001644 mask = binop(Iop_And8, rot_amt, mkU8(31));
ceriond953ebb2005-11-29 13:27:20 +00001645 rot = binop(Iop_Or32,
1646 binop(Iop_Shl32, src, mask),
1647 binop(Iop_Shr32, src, binop(Iop_Sub8, mkU8(32), mask)));
cerion2831b002005-11-30 19:55:22 +00001648 }
florian99dd03e2013-01-29 03:56:06 +00001649 /* Note: the ITE not merely an optimisation; it's needed
cerionf0de28c2005-12-13 20:21:11 +00001650 because otherwise the Shr is a shift by the word size when
ceriond953ebb2005-11-29 13:27:20 +00001651 mask denotes zero. For rotates by immediates, a lot of
sewardjc9659532005-07-21 21:33:57 +00001652 this junk gets folded out. */
florian99dd03e2013-01-29 03:56:06 +00001653 return IRExpr_ITE( binop(Iop_CmpNE8, mask, mkU8(0)),
1654 /* non-zero rotate */ rot,
1655 /* zero rotate */ src);
cerion45b70ff2005-01-31 17:03:25 +00001656}
cerion896a1372005-01-25 12:24:25 +00001657
ceriond953ebb2005-11-29 13:27:20 +00001658/* Standard effective address calc: (rA + rB) */
1659static IRExpr* ea_rA_idxd ( UInt rA, UInt rB )
1660{
1661 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1662 vassert(rA < 32);
1663 vassert(rB < 32);
cerion2831b002005-11-30 19:55:22 +00001664 return binop(mkSzOp(ty, Iop_Add8), getIReg(rA), getIReg(rB));
sewardj87e651f2005-09-09 08:31:18 +00001665}
1666
ceriond953ebb2005-11-29 13:27:20 +00001667/* Standard effective address calc: (rA + simm) */
1668static IRExpr* ea_rA_simm ( UInt rA, UInt simm16 )
sewardj87e651f2005-09-09 08:31:18 +00001669{
ceriond953ebb2005-11-29 13:27:20 +00001670 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1671 vassert(rA < 32);
cerion2831b002005-11-30 19:55:22 +00001672 return binop(mkSzOp(ty, Iop_Add8), getIReg(rA),
1673 mkSzExtendS16(ty, simm16));
ceriond953ebb2005-11-29 13:27:20 +00001674}
1675
1676/* Standard effective address calc: (rA|0) */
1677static IRExpr* ea_rAor0 ( UInt rA )
1678{
1679 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1680 vassert(rA < 32);
sewardj87e651f2005-09-09 08:31:18 +00001681 if (rA == 0) {
cerion2831b002005-11-30 19:55:22 +00001682 return mkSzImm(ty, 0);
sewardj87e651f2005-09-09 08:31:18 +00001683 } else {
1684 return getIReg(rA);
1685 }
1686}
1687
ceriond953ebb2005-11-29 13:27:20 +00001688/* Standard effective address calc: (rA|0) + rB */
1689static IRExpr* ea_rAor0_idxd ( UInt rA, UInt rB )
1690{
1691 vassert(rA < 32);
1692 vassert(rB < 32);
1693 return (rA == 0) ? getIReg(rB) : ea_rA_idxd( rA, rB );
1694}
1695
1696/* Standard effective address calc: (rA|0) + simm16 */
1697static IRExpr* ea_rAor0_simm ( UInt rA, UInt simm16 )
1698{
1699 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1700 vassert(rA < 32);
1701 if (rA == 0) {
cerion2831b002005-11-30 19:55:22 +00001702 return mkSzExtendS16(ty, simm16);
ceriond953ebb2005-11-29 13:27:20 +00001703 } else {
1704 return ea_rA_simm( rA, simm16 );
1705 }
1706}
1707
1708
1709/* Align effective address */
1710static IRExpr* addr_align( IRExpr* addr, UChar align )
1711{
1712 IRType ty = mode64 ? Ity_I64 : Ity_I32;
1713 Long mask;
1714 switch (align) {
cerion2831b002005-11-30 19:55:22 +00001715 case 1: return addr; // byte aligned
ceriond953ebb2005-11-29 13:27:20 +00001716 case 2: mask = ((Long)-1) << 1; break; // half-word aligned
1717 case 4: mask = ((Long)-1) << 2; break; // word aligned
1718 case 16: mask = ((Long)-1) << 4; break; // quad-word aligned
1719 default:
1720 vex_printf("addr_align: align = %u\n", align);
cerion5b2325f2005-12-23 00:55:09 +00001721 vpanic("addr_align(ppc)");
ceriond953ebb2005-11-29 13:27:20 +00001722 }
1723
sewardjdd40fdf2006-12-24 02:20:24 +00001724 vassert(typeOfIRExpr(irsb->tyenv,addr) == ty);
cerionfb197c42005-12-24 12:32:10 +00001725 return binop( mkSzOp(ty, Iop_And8), addr, mkSzImm(ty, mask) );
ceriond953ebb2005-11-29 13:27:20 +00001726}
1727
cerion896a1372005-01-25 12:24:25 +00001728
sewardje9d8a262009-07-01 08:06:34 +00001729/* Exit the trace if ADDR (intended to be a guest memory address) is
1730 not ALIGN-aligned, generating a request for a SIGBUS followed by a
1731 restart of the current insn. */
1732static void gen_SIGBUS_if_misaligned ( IRTemp addr, UChar align )
1733{
carll78850ae2013-09-10 18:46:40 +00001734 vassert(align == 4 || align == 8 || align == 16);
sewardje9d8a262009-07-01 08:06:34 +00001735 if (mode64) {
1736 vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I64);
1737 stmt(
1738 IRStmt_Exit(
1739 binop(Iop_CmpNE64,
1740 binop(Iop_And64, mkexpr(addr), mkU64(align-1)),
1741 mkU64(0)),
1742 Ijk_SigBUS,
sewardj3dee8492012-04-20 00:13:28 +00001743 IRConst_U64( guest_CIA_curr_instr ), OFFB_CIA
sewardje9d8a262009-07-01 08:06:34 +00001744 )
1745 );
1746 } else {
1747 vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I32);
1748 stmt(
1749 IRStmt_Exit(
1750 binop(Iop_CmpNE32,
1751 binop(Iop_And32, mkexpr(addr), mkU32(align-1)),
1752 mkU32(0)),
1753 Ijk_SigBUS,
sewardj3dee8492012-04-20 00:13:28 +00001754 IRConst_U32( guest_CIA_curr_instr ), OFFB_CIA
sewardje9d8a262009-07-01 08:06:34 +00001755 )
1756 );
1757 }
1758}
1759
1760
sewardjaca070a2006-10-17 00:28:22 +00001761/* Generate AbiHints which mark points at which the ELF or PowerOpen
1762 ABIs say that the stack red zone (viz, -N(r1) .. -1(r1), for some
1763 N) becomes undefined. That is at function calls and returns. ELF
sewardj478646f2008-05-01 20:13:04 +00001764 ppc32 doesn't have this "feature" (how fortunate for it). nia is
1765 the address of the next instruction to be executed.
sewardjcf8986c2006-01-18 04:14:52 +00001766*/
sewardj478646f2008-05-01 20:13:04 +00001767static void make_redzone_AbiHint ( VexAbiInfo* vbi,
florian55085f82012-11-21 00:36:55 +00001768 IRTemp nia, const HChar* who )
sewardjcf8986c2006-01-18 04:14:52 +00001769{
sewardjdd40fdf2006-12-24 02:20:24 +00001770 Int szB = vbi->guest_stack_redzone_size;
sewardjcf8986c2006-01-18 04:14:52 +00001771 if (0) vex_printf("AbiHint: %s\n", who);
sewardjaca070a2006-10-17 00:28:22 +00001772 vassert(szB >= 0);
1773 if (szB > 0) {
sewardj478646f2008-05-01 20:13:04 +00001774 if (mode64) {
1775 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I64);
sewardjaca070a2006-10-17 00:28:22 +00001776 stmt( IRStmt_AbiHint(
1777 binop(Iop_Sub64, getIReg(1), mkU64(szB)),
sewardj478646f2008-05-01 20:13:04 +00001778 szB,
1779 mkexpr(nia)
sewardjaca070a2006-10-17 00:28:22 +00001780 ));
sewardj478646f2008-05-01 20:13:04 +00001781 } else {
1782 vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I32);
sewardjaca070a2006-10-17 00:28:22 +00001783 stmt( IRStmt_AbiHint(
1784 binop(Iop_Sub32, getIReg(1), mkU32(szB)),
sewardj478646f2008-05-01 20:13:04 +00001785 szB,
1786 mkexpr(nia)
sewardjaca070a2006-10-17 00:28:22 +00001787 ));
sewardj478646f2008-05-01 20:13:04 +00001788 }
sewardjaca070a2006-10-17 00:28:22 +00001789 }
sewardjcf8986c2006-01-18 04:14:52 +00001790}
1791
1792
cerion896a1372005-01-25 12:24:25 +00001793/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +00001794/*--- Helpers for condition codes. ---*/
cerion896a1372005-01-25 12:24:25 +00001795/*------------------------------------------------------------*/
1796
sewardjb51f0f42005-07-18 11:38:02 +00001797/* Condition register layout.
cerion896a1372005-01-25 12:24:25 +00001798
sewardjb51f0f42005-07-18 11:38:02 +00001799 In the hardware, CR is laid out like this. The leftmost end is the
1800 most significant bit in the register; however the IBM documentation
1801 numbers the bits backwards for some reason.
1802
1803 CR0 CR1 .......... CR6 CR7
1804 0 .. 3 ....................... 28 .. 31 (IBM bit numbering)
1805 31 28 3 0 (normal bit numbering)
1806
cerionedf7fc52005-11-18 20:57:41 +00001807 Each CR field is 4 bits: [<,>,==,SO]
sewardjb51f0f42005-07-18 11:38:02 +00001808
cerionedf7fc52005-11-18 20:57:41 +00001809 Hence in IBM's notation, BI=0 is CR7[SO], BI=1 is CR7[==], etc.
sewardjb51f0f42005-07-18 11:38:02 +00001810
1811 Indexing from BI to guest state:
1812
1813 let n = BI / 4
1814 off = BI % 4
1815 this references CR n:
1816
cerionedf7fc52005-11-18 20:57:41 +00001817 off==0 -> guest_CRn_321 >> 3
1818 off==1 -> guest_CRn_321 >> 2
1819 off==2 -> guest_CRn_321 >> 1
sewardjb51f0f42005-07-18 11:38:02 +00001820 off==3 -> guest_CRn_SO
sewardjb51f0f42005-07-18 11:38:02 +00001821
1822 Bear in mind the only significant bit in guest_CRn_SO is bit 0
cerionedf7fc52005-11-18 20:57:41 +00001823 (normal notation) and in guest_CRn_321 the significant bits are
sewardjb51f0f42005-07-18 11:38:02 +00001824 3, 2 and 1 (normal notation).
1825*/
cerionedf7fc52005-11-18 20:57:41 +00001826
1827static void putCR321 ( UInt cr, IRExpr* e )
1828{
1829 vassert(cr < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00001830 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
cerionedf7fc52005-11-18 20:57:41 +00001831 stmt( IRStmt_Put(guestCR321offset(cr), e) );
1832}
1833
1834static void putCR0 ( UInt cr, IRExpr* e )
1835{
1836 vassert(cr < 8);
sewardjdd40fdf2006-12-24 02:20:24 +00001837 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
cerionedf7fc52005-11-18 20:57:41 +00001838 stmt( IRStmt_Put(guestCR0offset(cr), e) );
1839}
1840
1841static IRExpr* /* :: Ity_I8 */ getCR0 ( UInt cr )
1842{
1843 vassert(cr < 8);
1844 return IRExpr_Get(guestCR0offset(cr), Ity_I8);
1845}
1846
1847static IRExpr* /* :: Ity_I8 */ getCR321 ( UInt cr )
1848{
1849 vassert(cr < 8);
1850 return IRExpr_Get(guestCR321offset(cr), Ity_I8);
1851}
1852
sewardjb51f0f42005-07-18 11:38:02 +00001853/* Fetch the specified CR bit (as per IBM/hardware notation) and
1854 return it at the bottom of an I32; the top 31 bits are guaranteed
1855 to be zero. */
1856static IRExpr* /* :: Ity_I32 */ getCRbit ( UInt bi )
cerion896a1372005-01-25 12:24:25 +00001857{
sewardjb51f0f42005-07-18 11:38:02 +00001858 UInt n = bi / 4;
1859 UInt off = bi % 4;
1860 vassert(bi < 32);
1861 if (off == 3) {
1862 /* Fetch the SO bit for this CR field */
1863 /* Note: And32 is redundant paranoia iff guest state only has 0
1864 or 1 in that slot. */
1865 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
1866 } else {
1867 /* Fetch the <, > or == bit for this CR field */
1868 return binop( Iop_And32,
1869 binop( Iop_Shr32,
1870 unop(Iop_8Uto32, getCR321(n)),
sewardjc7cd2142005-09-09 22:31:49 +00001871 mkU8(toUChar(3-off)) ),
sewardjb51f0f42005-07-18 11:38:02 +00001872 mkU32(1) );
1873 }
cerion91ad5362005-01-27 23:02:41 +00001874}
1875
sewardjb51f0f42005-07-18 11:38:02 +00001876/* Dually, write the least significant bit of BIT to the specified CR
1877 bit. Indexing as per getCRbit. */
1878static void putCRbit ( UInt bi, IRExpr* bit )
1879{
sewardj197bd172005-10-12 11:34:33 +00001880 UInt n, off;
sewardjb51f0f42005-07-18 11:38:02 +00001881 IRExpr* safe;
sewardjdd40fdf2006-12-24 02:20:24 +00001882 vassert(typeOfIRExpr(irsb->tyenv,bit) == Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +00001883 safe = binop(Iop_And32, bit, mkU32(1));
sewardj197bd172005-10-12 11:34:33 +00001884 n = bi / 4;
1885 off = bi % 4;
sewardjb51f0f42005-07-18 11:38:02 +00001886 vassert(bi < 32);
1887 if (off == 3) {
1888 /* This is the SO bit for this CR field */
1889 putCR0(n, unop(Iop_32to8, safe));
1890 } else {
1891 off = 3 - off;
1892 vassert(off == 1 || off == 2 || off == 3);
1893 putCR321(
1894 n,
1895 unop( Iop_32to8,
1896 binop( Iop_Or32,
1897 /* old value with field masked out */
1898 binop(Iop_And32, unop(Iop_8Uto32, getCR321(n)),
1899 mkU32(~(1 << off))),
1900 /* new value in the right place */
sewardjc7cd2142005-09-09 22:31:49 +00001901 binop(Iop_Shl32, safe, mkU8(toUChar(off)))
sewardjb51f0f42005-07-18 11:38:02 +00001902 )
1903 )
1904 );
1905 }
1906}
1907
sewardjb51f0f42005-07-18 11:38:02 +00001908/* Fetch the specified CR bit (as per IBM/hardware notation) and
1909 return it somewhere in an I32; it does not matter where, but
1910 whichever bit it is, all other bits are guaranteed to be zero. In
1911 other words, the I32-typed expression will be zero if the bit is
1912 zero and nonzero if the bit is 1. Write into *where the index
1913 of where the bit will be. */
1914
cerion5b2325f2005-12-23 00:55:09 +00001915static
1916IRExpr* /* :: Ity_I32 */ getCRbit_anywhere ( UInt bi, Int* where )
sewardjb51f0f42005-07-18 11:38:02 +00001917{
1918 UInt n = bi / 4;
1919 UInt off = bi % 4;
1920 vassert(bi < 32);
1921 if (off == 3) {
1922 /* Fetch the SO bit for this CR field */
1923 /* Note: And32 is redundant paranoia iff guest state only has 0
1924 or 1 in that slot. */
1925 *where = 0;
1926 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
1927 } else {
1928 /* Fetch the <, > or == bit for this CR field */
1929 *where = 3-off;
1930 return binop( Iop_And32,
1931 unop(Iop_8Uto32, getCR321(n)),
1932 mkU32(1 << (3-off)) );
1933 }
1934}
1935
sewardjb51f0f42005-07-18 11:38:02 +00001936/* Set the CR0 flags following an arithmetic operation.
1937 (Condition Register CR0 Field Definition, PPC32 p60)
cerion896a1372005-01-25 12:24:25 +00001938*/
cerionedf7fc52005-11-18 20:57:41 +00001939static IRExpr* getXER_SO ( void );
sewardj20ef5472005-07-21 14:48:31 +00001940static void set_CR0 ( IRExpr* result )
cerion896a1372005-01-25 12:24:25 +00001941{
sewardjdd40fdf2006-12-24 02:20:24 +00001942 vassert(typeOfIRExpr(irsb->tyenv,result) == Ity_I32 ||
1943 typeOfIRExpr(irsb->tyenv,result) == Ity_I64);
ceriond953ebb2005-11-29 13:27:20 +00001944 if (mode64) {
ceriond953ebb2005-11-29 13:27:20 +00001945 putCR321( 0, unop(Iop_64to8,
cerion2831b002005-11-30 19:55:22 +00001946 binop(Iop_CmpORD64S, result, mkU64(0))) );
ceriond953ebb2005-11-29 13:27:20 +00001947 } else {
1948 putCR321( 0, unop(Iop_32to8,
1949 binop(Iop_CmpORD32S, result, mkU32(0))) );
1950 }
sewardjb51f0f42005-07-18 11:38:02 +00001951 putCR0( 0, getXER_SO() );
cerion896a1372005-01-25 12:24:25 +00001952}
cerion896a1372005-01-25 12:24:25 +00001953
sewardj20ef5472005-07-21 14:48:31 +00001954
sewardj4aa412a2011-07-24 14:13:21 +00001955/* Set the CR6 flags following an AltiVec compare operation.
1956 * NOTE: This also works for VSX single-precision compares.
1957 * */
cerionedf7fc52005-11-18 20:57:41 +00001958static void set_AV_CR6 ( IRExpr* result, Bool test_all_ones )
1959{
1960 /* CR6[0:3] = {all_ones, 0, all_zeros, 0}
1961 all_ones = (v[0] && v[1] && v[2] && v[3])
1962 all_zeros = ~(v[0] || v[1] || v[2] || v[3])
1963 */
1964 IRTemp v0 = newTemp(Ity_V128);
1965 IRTemp v1 = newTemp(Ity_V128);
1966 IRTemp v2 = newTemp(Ity_V128);
1967 IRTemp v3 = newTemp(Ity_V128);
1968 IRTemp rOnes = newTemp(Ity_I8);
1969 IRTemp rZeros = newTemp(Ity_I8);
1970
sewardjdd40fdf2006-12-24 02:20:24 +00001971 vassert(typeOfIRExpr(irsb->tyenv,result) == Ity_V128);
cerionedf7fc52005-11-18 20:57:41 +00001972
1973 assign( v0, result );
1974 assign( v1, binop(Iop_ShrV128, result, mkU8(32)) );
1975 assign( v2, binop(Iop_ShrV128, result, mkU8(64)) );
1976 assign( v3, binop(Iop_ShrV128, result, mkU8(96)) );
1977
1978 assign( rZeros, unop(Iop_1Uto8,
1979 binop(Iop_CmpEQ32, mkU32(0xFFFFFFFF),
1980 unop(Iop_Not32,
1981 unop(Iop_V128to32,
1982 binop(Iop_OrV128,
1983 binop(Iop_OrV128, mkexpr(v0), mkexpr(v1)),
1984 binop(Iop_OrV128, mkexpr(v2), mkexpr(v3))))
1985 ))) );
1986
1987 if (test_all_ones) {
1988 assign( rOnes, unop(Iop_1Uto8,
1989 binop(Iop_CmpEQ32, mkU32(0xFFFFFFFF),
1990 unop(Iop_V128to32,
1991 binop(Iop_AndV128,
1992 binop(Iop_AndV128, mkexpr(v0), mkexpr(v1)),
cerion5b2325f2005-12-23 00:55:09 +00001993 binop(Iop_AndV128, mkexpr(v2), mkexpr(v3)))
1994 ))) );
cerionedf7fc52005-11-18 20:57:41 +00001995 putCR321( 6, binop(Iop_Or8,
1996 binop(Iop_Shl8, mkexpr(rOnes), mkU8(3)),
1997 binop(Iop_Shl8, mkexpr(rZeros), mkU8(1))) );
1998 } else {
1999 putCR321( 6, binop(Iop_Shl8, mkexpr(rZeros), mkU8(1)) );
2000 }
2001 putCR0( 6, mkU8(0) );
2002}
2003
2004
2005
2006/*------------------------------------------------------------*/
2007/*--- Helpers for XER flags. ---*/
2008/*------------------------------------------------------------*/
2009
2010static void putXER_SO ( IRExpr* e )
2011{
sewardj63327402006-01-25 03:26:27 +00002012 IRExpr* so;
sewardjdd40fdf2006-12-24 02:20:24 +00002013 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
sewardj63327402006-01-25 03:26:27 +00002014 so = binop(Iop_And8, e, mkU8(1));
cerion5b2325f2005-12-23 00:55:09 +00002015 stmt( IRStmt_Put( OFFB_XER_SO, so ) );
cerionedf7fc52005-11-18 20:57:41 +00002016}
2017
2018static void putXER_OV ( IRExpr* e )
2019{
sewardj63327402006-01-25 03:26:27 +00002020 IRExpr* ov;
sewardjdd40fdf2006-12-24 02:20:24 +00002021 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
sewardj63327402006-01-25 03:26:27 +00002022 ov = binop(Iop_And8, e, mkU8(1));
cerion5b2325f2005-12-23 00:55:09 +00002023 stmt( IRStmt_Put( OFFB_XER_OV, ov ) );
cerionedf7fc52005-11-18 20:57:41 +00002024}
2025
2026static void putXER_CA ( IRExpr* e )
2027{
sewardj63327402006-01-25 03:26:27 +00002028 IRExpr* ca;
sewardjdd40fdf2006-12-24 02:20:24 +00002029 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
sewardj63327402006-01-25 03:26:27 +00002030 ca = binop(Iop_And8, e, mkU8(1));
cerion5b2325f2005-12-23 00:55:09 +00002031 stmt( IRStmt_Put( OFFB_XER_CA, ca ) );
cerionedf7fc52005-11-18 20:57:41 +00002032}
2033
2034static void putXER_BC ( IRExpr* e )
2035{
sewardj63327402006-01-25 03:26:27 +00002036 IRExpr* bc;
sewardjdd40fdf2006-12-24 02:20:24 +00002037 vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
sewardj63327402006-01-25 03:26:27 +00002038 bc = binop(Iop_And8, e, mkU8(0x7F));
cerion5b2325f2005-12-23 00:55:09 +00002039 stmt( IRStmt_Put( OFFB_XER_BC, bc ) );
cerionedf7fc52005-11-18 20:57:41 +00002040}
2041
2042static IRExpr* /* :: Ity_I8 */ getXER_SO ( void )
2043{
cerion5b2325f2005-12-23 00:55:09 +00002044 return IRExpr_Get( OFFB_XER_SO, Ity_I8 );
cerionedf7fc52005-11-18 20:57:41 +00002045}
2046
2047static IRExpr* /* :: Ity_I32 */ getXER_SO32 ( void )
2048{
2049 return binop( Iop_And32, unop(Iop_8Uto32, getXER_SO()), mkU32(1) );
2050}
2051
2052static IRExpr* /* :: Ity_I8 */ getXER_OV ( void )
2053{
cerion5b2325f2005-12-23 00:55:09 +00002054 return IRExpr_Get( OFFB_XER_OV, Ity_I8 );
cerionedf7fc52005-11-18 20:57:41 +00002055}
2056
2057static IRExpr* /* :: Ity_I32 */ getXER_OV32 ( void )
2058{
2059 return binop( Iop_And32, unop(Iop_8Uto32, getXER_OV()), mkU32(1) );
2060}
2061
2062static IRExpr* /* :: Ity_I32 */ getXER_CA32 ( void )
2063{
cerion5b2325f2005-12-23 00:55:09 +00002064 IRExpr* ca = IRExpr_Get( OFFB_XER_CA, Ity_I8 );
ceriond953ebb2005-11-29 13:27:20 +00002065 return binop( Iop_And32, unop(Iop_8Uto32, ca ), mkU32(1) );
cerionedf7fc52005-11-18 20:57:41 +00002066}
2067
2068static IRExpr* /* :: Ity_I8 */ getXER_BC ( void )
2069{
cerion5b2325f2005-12-23 00:55:09 +00002070 return IRExpr_Get( OFFB_XER_BC, Ity_I8 );
cerionedf7fc52005-11-18 20:57:41 +00002071}
2072
2073static IRExpr* /* :: Ity_I32 */ getXER_BC32 ( void )
2074{
cerion5b2325f2005-12-23 00:55:09 +00002075 IRExpr* bc = IRExpr_Get( OFFB_XER_BC, Ity_I8 );
ceriond953ebb2005-11-29 13:27:20 +00002076 return binop( Iop_And32, unop(Iop_8Uto32, bc), mkU32(0x7F) );
cerionedf7fc52005-11-18 20:57:41 +00002077}
2078
2079
sewardj20ef5472005-07-21 14:48:31 +00002080/* RES is the result of doing OP on ARGL and ARGR. Set %XER.OV and
2081 %XER.SO accordingly. */
2082
ceriond953ebb2005-11-29 13:27:20 +00002083static void set_XER_OV_32( UInt op, IRExpr* res,
2084 IRExpr* argL, IRExpr* argR )
sewardj20ef5472005-07-21 14:48:31 +00002085{
2086 IRTemp t64;
2087 IRExpr* xer_ov;
cerion5b2325f2005-12-23 00:55:09 +00002088 vassert(op < PPCG_FLAG_OP_NUMBER);
sewardjdd40fdf2006-12-24 02:20:24 +00002089 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I32);
2090 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I32);
2091 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I32);
sewardj20ef5472005-07-21 14:48:31 +00002092
2093# define INT32_MIN 0x80000000
2094
2095# define XOR2(_aa,_bb) \
2096 binop(Iop_Xor32,(_aa),(_bb))
2097
2098# define XOR3(_cc,_dd,_ee) \
2099 binop(Iop_Xor32,binop(Iop_Xor32,(_cc),(_dd)),(_ee))
2100
2101# define AND3(_ff,_gg,_hh) \
2102 binop(Iop_And32,binop(Iop_And32,(_ff),(_gg)),(_hh))
2103
2104#define NOT(_jj) \
2105 unop(Iop_Not32, (_jj))
2106
2107 switch (op) {
cerion5b2325f2005-12-23 00:55:09 +00002108 case /* 0 */ PPCG_FLAG_OP_ADD:
2109 case /* 1 */ PPCG_FLAG_OP_ADDE:
ceriond953ebb2005-11-29 13:27:20 +00002110 /* (argL^argR^-1) & (argL^res) & (1<<31) ?1:0 */
2111 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
2112 xer_ov
2113 = AND3( XOR3(argL,argR,mkU32(-1)),
2114 XOR2(argL,res),
2115 mkU32(INT32_MIN) );
2116 /* xer_ov can only be 0 or 1<<31 */
2117 xer_ov
2118 = binop(Iop_Shr32, xer_ov, mkU8(31) );
2119 break;
2120
cerion5b2325f2005-12-23 00:55:09 +00002121 case /* 2 */ PPCG_FLAG_OP_DIVW:
ceriond953ebb2005-11-29 13:27:20 +00002122 /* (argL == INT32_MIN && argR == -1) || argR == 0 */
2123 xer_ov
2124 = mkOR1(
2125 mkAND1(
2126 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)),
2127 binop(Iop_CmpEQ32, argR, mkU32(-1))
2128 ),
2129 binop(Iop_CmpEQ32, argR, mkU32(0) )
2130 );
2131 xer_ov
2132 = unop(Iop_1Uto32, xer_ov);
2133 break;
2134
cerion5b2325f2005-12-23 00:55:09 +00002135 case /* 3 */ PPCG_FLAG_OP_DIVWU:
ceriond953ebb2005-11-29 13:27:20 +00002136 /* argR == 0 */
2137 xer_ov
2138 = unop(Iop_1Uto32, binop(Iop_CmpEQ32, argR, mkU32(0)));
2139 break;
2140
cerion5b2325f2005-12-23 00:55:09 +00002141 case /* 4 */ PPCG_FLAG_OP_MULLW:
ceriond953ebb2005-11-29 13:27:20 +00002142 /* OV true if result can't be represented in 32 bits
2143 i.e sHi != sign extension of sLo */
2144 t64 = newTemp(Ity_I64);
2145 assign( t64, binop(Iop_MullS32, argL, argR) );
2146 xer_ov
2147 = binop( Iop_CmpNE32,
2148 unop(Iop_64HIto32, mkexpr(t64)),
2149 binop( Iop_Sar32,
2150 unop(Iop_64to32, mkexpr(t64)),
2151 mkU8(31))
2152 );
2153 xer_ov
2154 = unop(Iop_1Uto32, xer_ov);
2155 break;
2156
cerion5b2325f2005-12-23 00:55:09 +00002157 case /* 5 */ PPCG_FLAG_OP_NEG:
ceriond953ebb2005-11-29 13:27:20 +00002158 /* argL == INT32_MIN */
2159 xer_ov
2160 = unop( Iop_1Uto32,
2161 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)) );
2162 break;
2163
cerion5b2325f2005-12-23 00:55:09 +00002164 case /* 6 */ PPCG_FLAG_OP_SUBF:
2165 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2166 case /* 8 */ PPCG_FLAG_OP_SUBFE:
ceriond953ebb2005-11-29 13:27:20 +00002167 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<31) ?1:0; */
2168 xer_ov
2169 = AND3( XOR3(NOT(argL),argR,mkU32(-1)),
2170 XOR2(NOT(argL),res),
2171 mkU32(INT32_MIN) );
2172 /* xer_ov can only be 0 or 1<<31 */
2173 xer_ov
2174 = binop(Iop_Shr32, xer_ov, mkU8(31) );
2175 break;
2176
sewardj4aa412a2011-07-24 14:13:21 +00002177 case PPCG_FLAG_OP_DIVWEU:
2178 xer_ov
2179 = binop( Iop_Or32,
2180 unop( Iop_1Uto32, binop( Iop_CmpEQ32, argR, mkU32( 0 ) ) ),
2181 unop( Iop_1Uto32, binop( Iop_CmpLT32U, argR, argL ) ) );
2182 break;
2183
sewardje71e56a2011-09-05 12:11:06 +00002184 case PPCG_FLAG_OP_DIVWE:
2185
2186 /* If argR == 0 of if the result cannot fit in the 32-bit destination register,
2187 * then OV <- 1. If dest reg is 0 AND both dividend and divisor are non-zero,
2188 * an overflow is implied.
2189 */
2190 xer_ov = binop( Iop_Or32,
2191 unop( Iop_1Uto32, binop( Iop_CmpEQ32, argR, mkU32( 0 ) ) ),
2192 unop( Iop_1Uto32, mkAND1( binop( Iop_CmpEQ32, res, mkU32( 0 ) ),
2193 mkAND1( binop( Iop_CmpNE32, argL, mkU32( 0 ) ),
2194 binop( Iop_CmpNE32, argR, mkU32( 0 ) ) ) ) ) );
2195 break;
2196
2197
2198
ceriond953ebb2005-11-29 13:27:20 +00002199 default:
2200 vex_printf("set_XER_OV: op = %u\n", op);
cerion5b2325f2005-12-23 00:55:09 +00002201 vpanic("set_XER_OV(ppc)");
sewardj20ef5472005-07-21 14:48:31 +00002202 }
ceriond953ebb2005-11-29 13:27:20 +00002203
sewardj20ef5472005-07-21 14:48:31 +00002204 /* xer_ov MUST denote either 0 or 1, no other value allowed */
ceriond953ebb2005-11-29 13:27:20 +00002205 putXER_OV( unop(Iop_32to8, xer_ov) );
sewardj20ef5472005-07-21 14:48:31 +00002206
2207 /* Update the summary overflow */
cerionedf7fc52005-11-18 20:57:41 +00002208 putXER_SO( binop(Iop_Or8, getXER_SO(), getXER_OV()) );
sewardj20ef5472005-07-21 14:48:31 +00002209
2210# undef INT32_MIN
2211# undef AND3
2212# undef XOR3
2213# undef XOR2
2214# undef NOT
2215}
2216
ceriond953ebb2005-11-29 13:27:20 +00002217static void set_XER_OV_64( UInt op, IRExpr* res,
2218 IRExpr* argL, IRExpr* argR )
2219{
2220 IRExpr* xer_ov;
cerion5b2325f2005-12-23 00:55:09 +00002221 vassert(op < PPCG_FLAG_OP_NUMBER);
sewardjdd40fdf2006-12-24 02:20:24 +00002222 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I64);
2223 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I64);
2224 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I64);
ceriond953ebb2005-11-29 13:27:20 +00002225
cerion2831b002005-11-30 19:55:22 +00002226# define INT64_MIN 0x8000000000000000ULL
ceriond953ebb2005-11-29 13:27:20 +00002227
2228# define XOR2(_aa,_bb) \
2229 binop(Iop_Xor64,(_aa),(_bb))
2230
2231# define XOR3(_cc,_dd,_ee) \
2232 binop(Iop_Xor64,binop(Iop_Xor64,(_cc),(_dd)),(_ee))
2233
2234# define AND3(_ff,_gg,_hh) \
2235 binop(Iop_And64,binop(Iop_And64,(_ff),(_gg)),(_hh))
2236
2237#define NOT(_jj) \
2238 unop(Iop_Not64, (_jj))
2239
2240 switch (op) {
cerion5b2325f2005-12-23 00:55:09 +00002241 case /* 0 */ PPCG_FLAG_OP_ADD:
2242 case /* 1 */ PPCG_FLAG_OP_ADDE:
ceriond953ebb2005-11-29 13:27:20 +00002243 /* (argL^argR^-1) & (argL^res) & (1<<63) ? 1:0 */
2244 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
2245 xer_ov
2246 = AND3( XOR3(argL,argR,mkU64(-1)),
2247 XOR2(argL,res),
2248 mkU64(INT64_MIN) );
2249 /* xer_ov can only be 0 or 1<<63 */
2250 xer_ov
2251 = unop(Iop_64to1, binop(Iop_Shr64, xer_ov, mkU8(63)));
2252 break;
2253
cerion5b2325f2005-12-23 00:55:09 +00002254 case /* 2 */ PPCG_FLAG_OP_DIVW:
ceriond953ebb2005-11-29 13:27:20 +00002255 /* (argL == INT64_MIN && argR == -1) || argR == 0 */
2256 xer_ov
2257 = mkOR1(
2258 mkAND1(
2259 binop(Iop_CmpEQ64, argL, mkU64(INT64_MIN)),
2260 binop(Iop_CmpEQ64, argR, mkU64(-1))
2261 ),
2262 binop(Iop_CmpEQ64, argR, mkU64(0) )
2263 );
2264 break;
2265
cerion5b2325f2005-12-23 00:55:09 +00002266 case /* 3 */ PPCG_FLAG_OP_DIVWU:
ceriond953ebb2005-11-29 13:27:20 +00002267 /* argR == 0 */
2268 xer_ov
2269 = binop(Iop_CmpEQ64, argR, mkU64(0));
2270 break;
2271
cerion5b2325f2005-12-23 00:55:09 +00002272 case /* 4 */ PPCG_FLAG_OP_MULLW: {
ceriond953ebb2005-11-29 13:27:20 +00002273 /* OV true if result can't be represented in 64 bits
2274 i.e sHi != sign extension of sLo */
ceriond953ebb2005-11-29 13:27:20 +00002275 xer_ov
cerionbb01b7c2005-12-16 13:40:18 +00002276 = binop( Iop_CmpNE32,
2277 unop(Iop_64HIto32, res),
2278 binop( Iop_Sar32,
2279 unop(Iop_64to32, res),
2280 mkU8(31))
2281 );
ceriond953ebb2005-11-29 13:27:20 +00002282 break;
2283 }
2284
cerion5b2325f2005-12-23 00:55:09 +00002285 case /* 5 */ PPCG_FLAG_OP_NEG:
ceriond953ebb2005-11-29 13:27:20 +00002286 /* argL == INT64_MIN */
2287 xer_ov
2288 = binop(Iop_CmpEQ64, argL, mkU64(INT64_MIN));
2289 break;
2290
cerion5b2325f2005-12-23 00:55:09 +00002291 case /* 6 */ PPCG_FLAG_OP_SUBF:
2292 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2293 case /* 8 */ PPCG_FLAG_OP_SUBFE:
ceriond953ebb2005-11-29 13:27:20 +00002294 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<63) ?1:0; */
2295 xer_ov
2296 = AND3( XOR3(NOT(argL),argR,mkU64(-1)),
2297 XOR2(NOT(argL),res),
2298 mkU64(INT64_MIN) );
2299 /* xer_ov can only be 0 or 1<<63 */
2300 xer_ov
2301 = unop(Iop_64to1, binop(Iop_Shr64, xer_ov, mkU8(63)));
2302 break;
2303
sewardj4aa412a2011-07-24 14:13:21 +00002304 case PPCG_FLAG_OP_DIVDE:
2305
2306 /* If argR == 0, we must set the OV bit. But there's another condition
2307 * where we can get overflow set for divde . . . when the
2308 * result cannot fit in the 64-bit destination register. If dest reg is 0 AND
2309 * both dividend and divisor are non-zero, it implies an overflow.
2310 */
2311 xer_ov
2312 = mkOR1( binop( Iop_CmpEQ64, argR, mkU64( 0 ) ),
2313 mkAND1( binop( Iop_CmpEQ64, res, mkU64( 0 ) ),
2314 mkAND1( binop( Iop_CmpNE64, argL, mkU64( 0 ) ),
2315 binop( Iop_CmpNE64, argR, mkU64( 0 ) ) ) ) );
2316 break;
2317
sewardje71e56a2011-09-05 12:11:06 +00002318 case PPCG_FLAG_OP_DIVDEU:
2319 /* If argR == 0 or if argL >= argR, set OV. */
2320 xer_ov = mkOR1( binop( Iop_CmpEQ64, argR, mkU64( 0 ) ),
2321 binop( Iop_CmpLE64U, argR, argL ) );
2322 break;
2323
carll38b79ac2013-09-06 22:27:34 +00002324 case /* 18 */ PPCG_FLAG_OP_MULLD: {
2325 IRTemp t128;
2326 /* OV true if result can't be represented in 64 bits
2327 i.e sHi != sign extension of sLo */
2328 t128 = newTemp(Ity_I128);
2329 assign( t128, binop(Iop_MullS64, argL, argR) );
2330 xer_ov
2331 = binop( Iop_CmpNE64,
2332 unop(Iop_128HIto64, mkexpr(t128)),
2333 binop( Iop_Sar64,
2334 unop(Iop_128to64, mkexpr(t128)),
2335 mkU8(63))
2336 );
2337 break;
2338 }
2339
ceriond953ebb2005-11-29 13:27:20 +00002340 default:
2341 vex_printf("set_XER_OV: op = %u\n", op);
cerion5b2325f2005-12-23 00:55:09 +00002342 vpanic("set_XER_OV(ppc64)");
ceriond953ebb2005-11-29 13:27:20 +00002343 }
2344
2345 /* xer_ov MUST denote either 0 or 1, no other value allowed */
2346 putXER_OV( unop(Iop_1Uto8, xer_ov) );
2347
2348 /* Update the summary overflow */
2349 putXER_SO( binop(Iop_Or8, getXER_SO(), getXER_OV()) );
2350
2351# undef INT64_MIN
2352# undef AND3
2353# undef XOR3
2354# undef XOR2
2355# undef NOT
2356}
2357
2358static void set_XER_OV ( IRType ty, UInt op, IRExpr* res,
2359 IRExpr* argL, IRExpr* argR )
2360{
2361 if (ty == Ity_I32)
2362 set_XER_OV_32( op, res, argL, argR );
2363 else
2364 set_XER_OV_64( op, res, argL, argR );
2365}
2366
2367
2368
sewardjb51f0f42005-07-18 11:38:02 +00002369/* RES is the result of doing OP on ARGL and ARGR with the old %XER.CA
2370 value being OLDCA. Set %XER.CA accordingly. */
cerione9d361a2005-03-04 17:35:29 +00002371
cerion2831b002005-11-30 19:55:22 +00002372static void set_XER_CA_32 ( UInt op, IRExpr* res,
2373 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
cerion38674602005-02-08 02:19:25 +00002374{
sewardj9a036bf2005-03-14 18:19:08 +00002375 IRExpr* xer_ca;
cerion5b2325f2005-12-23 00:55:09 +00002376 vassert(op < PPCG_FLAG_OP_NUMBER);
sewardjdd40fdf2006-12-24 02:20:24 +00002377 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I32);
2378 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I32);
2379 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I32);
2380 vassert(typeOfIRExpr(irsb->tyenv,oldca) == Ity_I32);
cerion70e24122005-03-16 00:27:37 +00002381
sewardj20ef5472005-07-21 14:48:31 +00002382 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
2383 seems reasonable given that it's always generated by
cerionedf7fc52005-11-18 20:57:41 +00002384 getXER_CA32(), which masks it accordingly. In any case it being
cerion75949202005-12-24 13:14:11 +00002385 0 or 1 is an invariant of the ppc guest state representation;
sewardj20ef5472005-07-21 14:48:31 +00002386 if it has any other value, that invariant has been violated. */
cerione9d361a2005-03-04 17:35:29 +00002387
sewardj20ef5472005-07-21 14:48:31 +00002388 switch (op) {
cerion5b2325f2005-12-23 00:55:09 +00002389 case /* 0 */ PPCG_FLAG_OP_ADD:
ceriond953ebb2005-11-29 13:27:20 +00002390 /* res <u argL */
2391 xer_ca
2392 = unop(Iop_1Uto32, binop(Iop_CmpLT32U, res, argL));
2393 break;
2394
cerion5b2325f2005-12-23 00:55:09 +00002395 case /* 1 */ PPCG_FLAG_OP_ADDE:
ceriond953ebb2005-11-29 13:27:20 +00002396 /* res <u argL || (old_ca==1 && res==argL) */
2397 xer_ca
2398 = mkOR1(
2399 binop(Iop_CmpLT32U, res, argL),
2400 mkAND1(
2401 binop(Iop_CmpEQ32, oldca, mkU32(1)),
2402 binop(Iop_CmpEQ32, res, argL)
2403 )
2404 );
2405 xer_ca
2406 = unop(Iop_1Uto32, xer_ca);
2407 break;
2408
cerion5b2325f2005-12-23 00:55:09 +00002409 case /* 8 */ PPCG_FLAG_OP_SUBFE:
ceriond953ebb2005-11-29 13:27:20 +00002410 /* res <u argR || (old_ca==1 && res==argR) */
2411 xer_ca
2412 = mkOR1(
2413 binop(Iop_CmpLT32U, res, argR),
2414 mkAND1(
2415 binop(Iop_CmpEQ32, oldca, mkU32(1)),
2416 binop(Iop_CmpEQ32, res, argR)
2417 )
2418 );
2419 xer_ca
2420 = unop(Iop_1Uto32, xer_ca);
2421 break;
2422
cerion5b2325f2005-12-23 00:55:09 +00002423 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2424 case /* 9 */ PPCG_FLAG_OP_SUBFI:
ceriond953ebb2005-11-29 13:27:20 +00002425 /* res <=u argR */
2426 xer_ca
2427 = unop(Iop_1Uto32, binop(Iop_CmpLE32U, res, argR));
2428 break;
2429
cerion5b2325f2005-12-23 00:55:09 +00002430 case /* 10 */ PPCG_FLAG_OP_SRAW:
ceriond953ebb2005-11-29 13:27:20 +00002431 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
2432 If it is <= 31, behave like SRAWI; else XER.CA is the sign
2433 bit of argL. */
2434 /* This term valid for shift amount < 32 only */
2435 xer_ca
2436 = binop(
2437 Iop_And32,
2438 binop(Iop_Sar32, argL, mkU8(31)),
2439 binop( Iop_And32,
2440 argL,
2441 binop( Iop_Sub32,
cerion5b2325f2005-12-23 00:55:09 +00002442 binop(Iop_Shl32, mkU32(1),
2443 unop(Iop_32to8,argR)),
ceriond953ebb2005-11-29 13:27:20 +00002444 mkU32(1) )
2445 )
sewardj20ef5472005-07-21 14:48:31 +00002446 );
ceriond953ebb2005-11-29 13:27:20 +00002447 xer_ca
florian99dd03e2013-01-29 03:56:06 +00002448 = IRExpr_ITE(
ceriond953ebb2005-11-29 13:27:20 +00002449 /* shift amt > 31 ? */
sewardj009230b2013-01-26 11:47:55 +00002450 binop(Iop_CmpLT32U, mkU32(31), argR),
ceriond953ebb2005-11-29 13:27:20 +00002451 /* yes -- get sign bit of argL */
florian99dd03e2013-01-29 03:56:06 +00002452 binop(Iop_Shr32, argL, mkU8(31)),
2453 /* no -- be like srawi */
2454 unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)))
ceriond953ebb2005-11-29 13:27:20 +00002455 );
2456 break;
sewardj20ef5472005-07-21 14:48:31 +00002457
cerion5b2325f2005-12-23 00:55:09 +00002458 case /* 11 */ PPCG_FLAG_OP_SRAWI:
ceriond953ebb2005-11-29 13:27:20 +00002459 /* xer_ca is 1 iff src was negative and bits_shifted_out !=
2460 0. Since the shift amount is known to be in the range
2461 0 .. 31 inclusive the following seems viable:
2462 xer.ca == 1 iff the following is nonzero:
2463 (argL >>s 31) -- either all 0s or all 1s
2464 & (argL & (1<<argR)-1) -- the stuff shifted out */
2465 xer_ca
2466 = binop(
2467 Iop_And32,
2468 binop(Iop_Sar32, argL, mkU8(31)),
2469 binop( Iop_And32,
2470 argL,
2471 binop( Iop_Sub32,
cerion5b2325f2005-12-23 00:55:09 +00002472 binop(Iop_Shl32, mkU32(1),
2473 unop(Iop_32to8,argR)),
ceriond953ebb2005-11-29 13:27:20 +00002474 mkU32(1) )
2475 )
sewardj20ef5472005-07-21 14:48:31 +00002476 );
ceriond953ebb2005-11-29 13:27:20 +00002477 xer_ca
2478 = unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)));
2479 break;
2480
2481 default:
2482 vex_printf("set_XER_CA: op = %u\n", op);
cerion5b2325f2005-12-23 00:55:09 +00002483 vpanic("set_XER_CA(ppc)");
sewardj20ef5472005-07-21 14:48:31 +00002484 }
2485
2486 /* xer_ca MUST denote either 0 or 1, no other value allowed */
cerionedf7fc52005-11-18 20:57:41 +00002487 putXER_CA( unop(Iop_32to8, xer_ca) );
sewardjb51f0f42005-07-18 11:38:02 +00002488}
2489
cerion2831b002005-11-30 19:55:22 +00002490static void set_XER_CA_64 ( UInt op, IRExpr* res,
2491 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
sewardje14bb9f2005-07-22 09:39:02 +00002492{
ceriond953ebb2005-11-29 13:27:20 +00002493 IRExpr* xer_ca;
cerion5b2325f2005-12-23 00:55:09 +00002494 vassert(op < PPCG_FLAG_OP_NUMBER);
sewardjdd40fdf2006-12-24 02:20:24 +00002495 vassert(typeOfIRExpr(irsb->tyenv,res) == Ity_I64);
2496 vassert(typeOfIRExpr(irsb->tyenv,argL) == Ity_I64);
2497 vassert(typeOfIRExpr(irsb->tyenv,argR) == Ity_I64);
2498 vassert(typeOfIRExpr(irsb->tyenv,oldca) == Ity_I64);
sewardje14bb9f2005-07-22 09:39:02 +00002499
ceriond953ebb2005-11-29 13:27:20 +00002500 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
2501 seems reasonable given that it's always generated by
2502 getXER_CA32(), which masks it accordingly. In any case it being
cerion75949202005-12-24 13:14:11 +00002503 0 or 1 is an invariant of the ppc guest state representation;
ceriond953ebb2005-11-29 13:27:20 +00002504 if it has any other value, that invariant has been violated. */
2505
2506 switch (op) {
cerion5b2325f2005-12-23 00:55:09 +00002507 case /* 0 */ PPCG_FLAG_OP_ADD:
ceriond953ebb2005-11-29 13:27:20 +00002508 /* res <u argL */
2509 xer_ca
cerionf0de28c2005-12-13 20:21:11 +00002510 = unop(Iop_1Uto32, binop(Iop_CmpLT64U, res, argL));
ceriond953ebb2005-11-29 13:27:20 +00002511 break;
sewardje14bb9f2005-07-22 09:39:02 +00002512
cerion5b2325f2005-12-23 00:55:09 +00002513 case /* 1 */ PPCG_FLAG_OP_ADDE:
ceriond953ebb2005-11-29 13:27:20 +00002514 /* res <u argL || (old_ca==1 && res==argL) */
2515 xer_ca
2516 = mkOR1(
2517 binop(Iop_CmpLT64U, res, argL),
2518 mkAND1(
cerionf0de28c2005-12-13 20:21:11 +00002519 binop(Iop_CmpEQ64, oldca, mkU64(1)),
ceriond953ebb2005-11-29 13:27:20 +00002520 binop(Iop_CmpEQ64, res, argL)
2521 )
2522 );
cerionf0de28c2005-12-13 20:21:11 +00002523 xer_ca
2524 = unop(Iop_1Uto32, xer_ca);
cerionedf7fc52005-11-18 20:57:41 +00002525 break;
ceriond953ebb2005-11-29 13:27:20 +00002526
cerion5b2325f2005-12-23 00:55:09 +00002527 case /* 8 */ PPCG_FLAG_OP_SUBFE:
ceriond953ebb2005-11-29 13:27:20 +00002528 /* res <u argR || (old_ca==1 && res==argR) */
2529 xer_ca
2530 = mkOR1(
2531 binop(Iop_CmpLT64U, res, argR),
2532 mkAND1(
2533 binop(Iop_CmpEQ64, oldca, mkU64(1)),
2534 binop(Iop_CmpEQ64, res, argR)
2535 )
2536 );
cerionf0de28c2005-12-13 20:21:11 +00002537 xer_ca
2538 = unop(Iop_1Uto32, xer_ca);
ceriond953ebb2005-11-29 13:27:20 +00002539 break;
2540
cerion5b2325f2005-12-23 00:55:09 +00002541 case /* 7 */ PPCG_FLAG_OP_SUBFC:
2542 case /* 9 */ PPCG_FLAG_OP_SUBFI:
ceriond953ebb2005-11-29 13:27:20 +00002543 /* res <=u argR */
2544 xer_ca
cerionf0de28c2005-12-13 20:21:11 +00002545 = unop(Iop_1Uto32, binop(Iop_CmpLE64U, res, argR));
ceriond953ebb2005-11-29 13:27:20 +00002546 break;
2547
2548
cerion5b2325f2005-12-23 00:55:09 +00002549 case /* 10 */ PPCG_FLAG_OP_SRAW:
cerionf0de28c2005-12-13 20:21:11 +00002550 /* The shift amount is guaranteed to be in 0 .. 31 inclusive.
ceriond953ebb2005-11-29 13:27:20 +00002551 If it is <= 31, behave like SRAWI; else XER.CA is the sign
2552 bit of argL. */
cerionf0de28c2005-12-13 20:21:11 +00002553 /* This term valid for shift amount < 31 only */
2554
ceriond953ebb2005-11-29 13:27:20 +00002555 xer_ca
2556 = binop(
cerionf0de28c2005-12-13 20:21:11 +00002557 Iop_And64,
2558 binop(Iop_Sar64, argL, mkU8(31)),
2559 binop( Iop_And64,
ceriond953ebb2005-11-29 13:27:20 +00002560 argL,
cerionf0de28c2005-12-13 20:21:11 +00002561 binop( Iop_Sub64,
cerion5b2325f2005-12-23 00:55:09 +00002562 binop(Iop_Shl64, mkU64(1),
2563 unop(Iop_64to8,argR)),
cerionf0de28c2005-12-13 20:21:11 +00002564 mkU64(1) )
ceriond953ebb2005-11-29 13:27:20 +00002565 )
2566 );
2567 xer_ca
florian99dd03e2013-01-29 03:56:06 +00002568 = IRExpr_ITE(
ceriond953ebb2005-11-29 13:27:20 +00002569 /* shift amt > 31 ? */
sewardj009230b2013-01-26 11:47:55 +00002570 binop(Iop_CmpLT64U, mkU64(31), argR),
ceriond953ebb2005-11-29 13:27:20 +00002571 /* yes -- get sign bit of argL */
florian99dd03e2013-01-29 03:56:06 +00002572 unop(Iop_64to32, binop(Iop_Shr64, argL, mkU8(63))),
2573 /* no -- be like srawi */
2574 unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)))
2575 );
ceriond953ebb2005-11-29 13:27:20 +00002576 break;
2577
cerion5b2325f2005-12-23 00:55:09 +00002578 case /* 11 */ PPCG_FLAG_OP_SRAWI:
cerionf0de28c2005-12-13 20:21:11 +00002579 /* xer_ca is 1 iff src was negative and bits_shifted_out != 0.
2580 Since the shift amount is known to be in the range 0 .. 31
2581 inclusive the following seems viable:
ceriond953ebb2005-11-29 13:27:20 +00002582 xer.ca == 1 iff the following is nonzero:
2583 (argL >>s 31) -- either all 0s or all 1s
2584 & (argL & (1<<argR)-1) -- the stuff shifted out */
cerionf0de28c2005-12-13 20:21:11 +00002585
ceriond953ebb2005-11-29 13:27:20 +00002586 xer_ca
2587 = binop(
cerionf0de28c2005-12-13 20:21:11 +00002588 Iop_And64,
2589 binop(Iop_Sar64, argL, mkU8(31)),
2590 binop( Iop_And64,
ceriond953ebb2005-11-29 13:27:20 +00002591 argL,
cerionf0de28c2005-12-13 20:21:11 +00002592 binop( Iop_Sub64,
cerion5b2325f2005-12-23 00:55:09 +00002593 binop(Iop_Shl64, mkU64(1),
2594 unop(Iop_64to8,argR)),
cerionf0de28c2005-12-13 20:21:11 +00002595 mkU64(1) )
ceriond953ebb2005-11-29 13:27:20 +00002596 )
2597 );
2598 xer_ca
cerionf0de28c2005-12-13 20:21:11 +00002599 = unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)));
ceriond953ebb2005-11-29 13:27:20 +00002600 break;
ceriond953ebb2005-11-29 13:27:20 +00002601
cerionf0de28c2005-12-13 20:21:11 +00002602
cerion5b2325f2005-12-23 00:55:09 +00002603 case /* 12 */ PPCG_FLAG_OP_SRAD:
cerionf0de28c2005-12-13 20:21:11 +00002604 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
2605 If it is <= 63, behave like SRADI; else XER.CA is the sign
2606 bit of argL. */
2607 /* This term valid for shift amount < 63 only */
2608
2609 xer_ca
2610 = binop(
2611 Iop_And64,
2612 binop(Iop_Sar64, argL, mkU8(63)),
2613 binop( Iop_And64,
2614 argL,
2615 binop( Iop_Sub64,
cerion5b2325f2005-12-23 00:55:09 +00002616 binop(Iop_Shl64, mkU64(1),
2617 unop(Iop_64to8,argR)),
cerionf0de28c2005-12-13 20:21:11 +00002618 mkU64(1) )
2619 )
2620 );
2621 xer_ca
florian99dd03e2013-01-29 03:56:06 +00002622 = IRExpr_ITE(
cerionf0de28c2005-12-13 20:21:11 +00002623 /* shift amt > 63 ? */
sewardj009230b2013-01-26 11:47:55 +00002624 binop(Iop_CmpLT64U, mkU64(63), argR),
cerionf0de28c2005-12-13 20:21:11 +00002625 /* yes -- get sign bit of argL */
florian99dd03e2013-01-29 03:56:06 +00002626 unop(Iop_64to32, binop(Iop_Shr64, argL, mkU8(63))),
2627 /* no -- be like sradi */
2628 unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)))
cerionf0de28c2005-12-13 20:21:11 +00002629 );
2630 break;
2631
2632
cerion5b2325f2005-12-23 00:55:09 +00002633 case /* 13 */ PPCG_FLAG_OP_SRADI:
cerionf0de28c2005-12-13 20:21:11 +00002634 /* xer_ca is 1 iff src was negative and bits_shifted_out != 0.
2635 Since the shift amount is known to be in the range 0 .. 63
2636 inclusive, the following seems viable:
2637 xer.ca == 1 iff the following is nonzero:
2638 (argL >>s 63) -- either all 0s or all 1s
2639 & (argL & (1<<argR)-1) -- the stuff shifted out */
2640
2641 xer_ca
2642 = binop(
2643 Iop_And64,
2644 binop(Iop_Sar64, argL, mkU8(63)),
2645 binop( Iop_And64,
2646 argL,
2647 binop( Iop_Sub64,
cerion5b2325f2005-12-23 00:55:09 +00002648 binop(Iop_Shl64, mkU64(1),
2649 unop(Iop_64to8,argR)),
cerionf0de28c2005-12-13 20:21:11 +00002650 mkU64(1) )
2651 )
2652 );
2653 xer_ca
2654 = unop(Iop_1Uto32, binop(Iop_CmpNE64, xer_ca, mkU64(0)));
2655 break;
2656
ceriond953ebb2005-11-29 13:27:20 +00002657 default:
2658 vex_printf("set_XER_CA: op = %u\n", op);
cerionf0de28c2005-12-13 20:21:11 +00002659 vpanic("set_XER_CA(ppc64)");
sewardje14bb9f2005-07-22 09:39:02 +00002660 }
2661
ceriond953ebb2005-11-29 13:27:20 +00002662 /* xer_ca MUST denote either 0 or 1, no other value allowed */
cerionf0de28c2005-12-13 20:21:11 +00002663 putXER_CA( unop(Iop_32to8, xer_ca) );
sewardje14bb9f2005-07-22 09:39:02 +00002664}
2665
cerion2831b002005-11-30 19:55:22 +00002666static void set_XER_CA ( IRType ty, UInt op, IRExpr* res,
2667 IRExpr* argL, IRExpr* argR, IRExpr* oldca )
cerionedf7fc52005-11-18 20:57:41 +00002668{
cerion2831b002005-11-30 19:55:22 +00002669 if (ty == Ity_I32)
ceriond953ebb2005-11-29 13:27:20 +00002670 set_XER_CA_32( op, res, argL, argR, oldca );
2671 else
2672 set_XER_CA_64( op, res, argL, argR, oldca );
cerionedf7fc52005-11-18 20:57:41 +00002673}
2674
ceriond953ebb2005-11-29 13:27:20 +00002675
2676
2677/*------------------------------------------------------------*/
2678/*--- Read/write to guest-state --- */
2679/*------------------------------------------------------------*/
2680
cerionf0de28c2005-12-13 20:21:11 +00002681static IRExpr* /* :: Ity_I32/64 */ getGST ( PPC_GST reg )
cerionedf7fc52005-11-18 20:57:41 +00002682{
ceriond953ebb2005-11-29 13:27:20 +00002683 IRType ty = mode64 ? Ity_I64 : Ity_I32;
cerionedf7fc52005-11-18 20:57:41 +00002684 switch (reg) {
sewardjaca070a2006-10-17 00:28:22 +00002685 case PPC_GST_SPRG3_RO:
2686 return IRExpr_Get( OFFB_SPRG3_RO, ty );
2687
2688 case PPC_GST_CIA:
2689 return IRExpr_Get( OFFB_CIA, ty );
2690
ceriond953ebb2005-11-29 13:27:20 +00002691 case PPC_GST_LR:
cerion5b2325f2005-12-23 00:55:09 +00002692 return IRExpr_Get( OFFB_LR, ty );
ceriond953ebb2005-11-29 13:27:20 +00002693
2694 case PPC_GST_CTR:
cerion5b2325f2005-12-23 00:55:09 +00002695 return IRExpr_Get( OFFB_CTR, ty );
ceriond953ebb2005-11-29 13:27:20 +00002696
2697 case PPC_GST_VRSAVE:
cerion5b2325f2005-12-23 00:55:09 +00002698 return IRExpr_Get( OFFB_VRSAVE, Ity_I32 );
ceriond953ebb2005-11-29 13:27:20 +00002699
2700 case PPC_GST_VSCR:
cerion5b2325f2005-12-23 00:55:09 +00002701 return binop(Iop_And32, IRExpr_Get( OFFB_VSCR,Ity_I32 ),
2702 mkU32(MASK_VSCR_VALID));
ceriond953ebb2005-11-29 13:27:20 +00002703
2704 case PPC_GST_CR: {
cerionedf7fc52005-11-18 20:57:41 +00002705 /* Synthesise the entire CR into a single word. Expensive. */
2706# define FIELD(_n) \
2707 binop(Iop_Shl32, \
2708 unop(Iop_8Uto32, \
2709 binop(Iop_Or8, \
2710 binop(Iop_And8, getCR321(_n), mkU8(7<<1)), \
2711 binop(Iop_And8, getCR0(_n), mkU8(1)) \
2712 ) \
2713 ), \
2714 mkU8(4 * (7-(_n))) \
2715 )
2716 return binop(Iop_Or32,
2717 binop(Iop_Or32,
2718 binop(Iop_Or32, FIELD(0), FIELD(1)),
2719 binop(Iop_Or32, FIELD(2), FIELD(3))
2720 ),
2721 binop(Iop_Or32,
2722 binop(Iop_Or32, FIELD(4), FIELD(5)),
2723 binop(Iop_Or32, FIELD(6), FIELD(7))
2724 )
2725 );
2726# undef FIELD
2727 }
ceriond953ebb2005-11-29 13:27:20 +00002728
2729 case PPC_GST_XER:
cerionedf7fc52005-11-18 20:57:41 +00002730 return binop(Iop_Or32,
2731 binop(Iop_Or32,
2732 binop( Iop_Shl32, getXER_SO32(), mkU8(31)),
2733 binop( Iop_Shl32, getXER_OV32(), mkU8(30))),
2734 binop(Iop_Or32,
2735 binop( Iop_Shl32, getXER_CA32(), mkU8(29)),
2736 getXER_BC32()));
ceriond953ebb2005-11-29 13:27:20 +00002737
carll8943d022013-10-02 16:25:57 +00002738 case PPC_GST_TFHAR:
2739 return IRExpr_Get( OFFB_TFHAR, ty );
2740
2741 case PPC_GST_TEXASR:
2742 return IRExpr_Get( OFFB_TEXASR, ty );
2743
2744 case PPC_GST_TFIAR:
2745 return IRExpr_Get( OFFB_TFIAR, ty );
2746
cerionedf7fc52005-11-18 20:57:41 +00002747 default:
cerion5b2325f2005-12-23 00:55:09 +00002748 vex_printf("getGST(ppc): reg = %u", reg);
2749 vpanic("getGST(ppc)");
ceriond953ebb2005-11-29 13:27:20 +00002750 }
2751}
2752
2753/* Get a masked word from the given reg */
2754static IRExpr* /* ::Ity_I32 */ getGST_masked ( PPC_GST reg, UInt mask )
2755{
2756 IRTemp val = newTemp(Ity_I32);
2757 vassert( reg < PPC_GST_MAX );
2758
2759 switch (reg) {
2760
2761 case PPC_GST_FPSCR: {
cerion5b2325f2005-12-23 00:55:09 +00002762 /* Vex-generated code expects the FPSCR to be set as follows:
ceriond953ebb2005-11-29 13:27:20 +00002763 all exceptions masked, round-to-nearest.
2764 This corresponds to a FPSCR value of 0x0. */
2765
sewardjc6bbd472012-04-02 10:20:48 +00002766 /* In the lower 32 bits of FPSCR, we're only keeping track of
2767 * the binary floating point rounding mode, so if the mask isn't
2768 * asking for this, just return 0x0.
2769 */
2770 if (mask & MASK_FPSCR_RN) {
2771 assign( val, unop( Iop_8Uto32, IRExpr_Get( OFFB_FPROUND, Ity_I8 ) ) );
ceriond953ebb2005-11-29 13:27:20 +00002772 } else {
2773 assign( val, mkU32(0x0) );
2774 }
2775 break;
2776 }
2777
2778 default:
cerion5b2325f2005-12-23 00:55:09 +00002779 vex_printf("getGST_masked(ppc): reg = %u", reg);
2780 vpanic("getGST_masked(ppc)");
ceriond953ebb2005-11-29 13:27:20 +00002781 }
2782
2783 if (mask != 0xFFFFFFFF) {
2784 return binop(Iop_And32, mkexpr(val), mkU32(mask));
2785 } else {
2786 return mkexpr(val);
2787 }
2788}
2789
sewardjc6bbd472012-04-02 10:20:48 +00002790/* Get a masked word from the given reg */
2791static IRExpr* /* ::Ity_I32 */getGST_masked_upper(PPC_GST reg, ULong mask) {
2792 IRExpr * val;
2793 vassert( reg < PPC_GST_MAX );
2794
2795 switch (reg) {
2796
2797 case PPC_GST_FPSCR: {
2798 /* In the upper 32 bits of FPSCR, we're only keeping track
2799 * of the decimal floating point rounding mode, so if the mask
2800 * isn't asking for this, just return 0x0.
2801 */
2802 if (mask & MASK_FPSCR_DRN) {
2803 val = binop( Iop_And32,
2804 unop( Iop_8Uto32, IRExpr_Get( OFFB_DFPROUND, Ity_I8 ) ),
2805 unop( Iop_64HIto32, mkU64( mask ) ) );
2806 } else {
2807 val = mkU32( 0x0ULL );
2808 }
2809 break;
2810 }
2811
2812 default:
2813 vex_printf( "getGST_masked_upper(ppc): reg = %u", reg );
2814 vpanic( "getGST_masked_upper(ppc)" );
2815 }
2816 return val;
2817}
2818
2819
ceriond953ebb2005-11-29 13:27:20 +00002820/* Fetch the specified REG[FLD] nibble (as per IBM/hardware notation)
2821 and return it at the bottom of an I32; the top 27 bits are
2822 guaranteed to be zero. */
2823static IRExpr* /* ::Ity_I32 */ getGST_field ( PPC_GST reg, UInt fld )
2824{
2825 UInt shft, mask;
2826
2827 vassert( fld < 8 );
2828 vassert( reg < PPC_GST_MAX );
2829
2830 shft = 4*(7-fld);
2831 mask = 0xF<<shft;
2832
2833 switch (reg) {
2834 case PPC_GST_XER:
2835 vassert(fld ==7);
2836 return binop(Iop_Or32,
2837 binop(Iop_Or32,
2838 binop(Iop_Shl32, getXER_SO32(), mkU8(3)),
2839 binop(Iop_Shl32, getXER_OV32(), mkU8(2))),
2840 binop( Iop_Shl32, getXER_CA32(), mkU8(1)));
2841 break;
2842
2843 default:
2844 if (shft == 0)
2845 return getGST_masked( reg, mask );
2846 else
2847 return binop(Iop_Shr32,
2848 getGST_masked( reg, mask ),
2849 mkU8(toUChar( shft )));
2850 }
2851}
2852
2853static void putGST ( PPC_GST reg, IRExpr* src )
2854{
cerion5b2325f2005-12-23 00:55:09 +00002855 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardjdd40fdf2006-12-24 02:20:24 +00002856 IRType ty_src = typeOfIRExpr(irsb->tyenv,src );
ceriond953ebb2005-11-29 13:27:20 +00002857 vassert( reg < PPC_GST_MAX );
2858 switch (reg) {
sewardje86310f2009-03-19 22:21:40 +00002859 case PPC_GST_IP_AT_SYSCALL:
sewardjaca070a2006-10-17 00:28:22 +00002860 vassert( ty_src == ty );
sewardje86310f2009-03-19 22:21:40 +00002861 stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL, src ) );
sewardjaca070a2006-10-17 00:28:22 +00002862 break;
ceriond953ebb2005-11-29 13:27:20 +00002863 case PPC_GST_CIA:
cerion5b2325f2005-12-23 00:55:09 +00002864 vassert( ty_src == ty );
2865 stmt( IRStmt_Put( OFFB_CIA, src ) );
ceriond953ebb2005-11-29 13:27:20 +00002866 break;
2867 case PPC_GST_LR:
cerion5b2325f2005-12-23 00:55:09 +00002868 vassert( ty_src == ty );
2869 stmt( IRStmt_Put( OFFB_LR, src ) );
ceriond953ebb2005-11-29 13:27:20 +00002870 break;
2871 case PPC_GST_CTR:
cerion5b2325f2005-12-23 00:55:09 +00002872 vassert( ty_src == ty );
2873 stmt( IRStmt_Put( OFFB_CTR, src ) );
ceriond953ebb2005-11-29 13:27:20 +00002874 break;
2875 case PPC_GST_VRSAVE:
cerion5b2325f2005-12-23 00:55:09 +00002876 vassert( ty_src == Ity_I32 );
2877 stmt( IRStmt_Put( OFFB_VRSAVE,src));
ceriond953ebb2005-11-29 13:27:20 +00002878 break;
2879 case PPC_GST_VSCR:
cerion5b2325f2005-12-23 00:55:09 +00002880 vassert( ty_src == Ity_I32 );
2881 stmt( IRStmt_Put( OFFB_VSCR,
ceriond953ebb2005-11-29 13:27:20 +00002882 binop(Iop_And32, src,
2883 mkU32(MASK_VSCR_VALID)) ) );
2884 break;
2885 case PPC_GST_XER:
cerion5b2325f2005-12-23 00:55:09 +00002886 vassert( ty_src == Ity_I32 );
ceriond953ebb2005-11-29 13:27:20 +00002887 putXER_SO( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(31))) );
2888 putXER_OV( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(30))) );
2889 putXER_CA( unop(Iop_32to8, binop(Iop_Shr32, src, mkU8(29))) );
2890 putXER_BC( unop(Iop_32to8, src) );
2891 break;
2892
2893 case PPC_GST_EMWARN:
cerion5b2325f2005-12-23 00:55:09 +00002894 vassert( ty_src == Ity_I32 );
florian6ef84be2012-08-26 03:20:07 +00002895 stmt( IRStmt_Put( OFFB_EMNOTE,src) );
ceriond953ebb2005-11-29 13:27:20 +00002896 break;
2897
sewardj05f5e012014-05-04 10:52:11 +00002898 case PPC_GST_CMSTART:
cerion5b2325f2005-12-23 00:55:09 +00002899 vassert( ty_src == ty );
sewardj05f5e012014-05-04 10:52:11 +00002900 stmt( IRStmt_Put( OFFB_CMSTART, src) );
ceriond953ebb2005-11-29 13:27:20 +00002901 break;
2902
sewardj05f5e012014-05-04 10:52:11 +00002903 case PPC_GST_CMLEN:
cerion5b2325f2005-12-23 00:55:09 +00002904 vassert( ty_src == ty );
sewardj05f5e012014-05-04 10:52:11 +00002905 stmt( IRStmt_Put( OFFB_CMLEN, src) );
ceriond953ebb2005-11-29 13:27:20 +00002906 break;
2907
carll8943d022013-10-02 16:25:57 +00002908 case PPC_GST_TEXASR:
2909 vassert( ty_src == Ity_I64 );
2910 stmt( IRStmt_Put( OFFB_TEXASR, src ) );
2911 break;
2912 case PPC_GST_TFIAR:
2913 vassert( ty_src == Ity_I64 );
2914 stmt( IRStmt_Put( OFFB_TFIAR, src ) );
2915 break;
2916 case PPC_GST_TFHAR:
2917 vassert( ty_src == Ity_I64 );
2918 stmt( IRStmt_Put( OFFB_TFHAR, src ) );
2919 break;
ceriond953ebb2005-11-29 13:27:20 +00002920 default:
cerion5b2325f2005-12-23 00:55:09 +00002921 vex_printf("putGST(ppc): reg = %u", reg);
2922 vpanic("putGST(ppc)");
cerionedf7fc52005-11-18 20:57:41 +00002923 }
2924}
sewardje14bb9f2005-07-22 09:39:02 +00002925
2926/* Write masked src to the given reg */
sewardjc6bbd472012-04-02 10:20:48 +00002927static void putGST_masked ( PPC_GST reg, IRExpr* src, ULong mask )
sewardje14bb9f2005-07-22 09:39:02 +00002928{
ceriond953ebb2005-11-29 13:27:20 +00002929 IRType ty = mode64 ? Ity_I64 : Ity_I32;
2930 vassert( reg < PPC_GST_MAX );
sewardjc6bbd472012-04-02 10:20:48 +00002931 vassert( typeOfIRExpr( irsb->tyenv,src ) == Ity_I64 );
2932
sewardje14bb9f2005-07-22 09:39:02 +00002933 switch (reg) {
ceriond953ebb2005-11-29 13:27:20 +00002934 case PPC_GST_FPSCR: {
sewardjc6bbd472012-04-02 10:20:48 +00002935 /* Allow writes to either binary or decimal floating point
sewardj150794d2014-08-20 08:54:06 +00002936 Rounding Mode.
2937 */
2938 /* If any part of |mask| covers FPSCR.RN, update the bits of
2939 FPSCR.RN by copying in |src| for locations where the
2940 corresponding bit in |mask| is 1, and leaving it unchanged
2941 for corresponding |mask| zero bits. */
sewardjc6bbd472012-04-02 10:20:48 +00002942 if (mask & MASK_FPSCR_RN) {
sewardj150794d2014-08-20 08:54:06 +00002943 stmt(
2944 IRStmt_Put(
2945 OFFB_FPROUND,
2946 unop(
2947 Iop_32to8,
2948 binop(
2949 Iop_Or32,
2950 binop(
2951 Iop_And32,
2952 unop(Iop_64to32, src),
2953 mkU32(MASK_FPSCR_RN & mask)
2954 ),
2955 binop(
2956 Iop_And32,
2957 unop(Iop_8Uto32, IRExpr_Get(OFFB_FPROUND,Ity_I8)),
2958 mkU32(MASK_FPSCR_RN & ~mask)
2959 )
2960 )
2961 )
2962 )
2963 );
2964 }
2965 /* Similarly, update FPSCR.DRN if any bits of |mask|
2966 corresponding to FPSCR.DRN are set. */
2967 if (mask & MASK_FPSCR_DRN) {
2968 stmt(
2969 IRStmt_Put(
2970 OFFB_DFPROUND,
2971 unop(
2972 Iop_32to8,
2973 binop(
2974 Iop_Or32,
2975 binop(
2976 Iop_And32,
2977 unop(Iop_64HIto32, src),
2978 mkU32((MASK_FPSCR_DRN & mask) >> 32)
2979 ),
2980 binop(
2981 Iop_And32,
2982 unop(Iop_8Uto32, IRExpr_Get(OFFB_DFPROUND,Ity_I8)),
2983 mkU32((MASK_FPSCR_DRN & ~mask) >> 32)
2984 )
2985 )
2986 )
2987 )
2988 );
sewardje14bb9f2005-07-22 09:39:02 +00002989 }
2990
florian6ef84be2012-08-26 03:20:07 +00002991 /* Give EmNote for attempted writes to:
sewardje14bb9f2005-07-22 09:39:02 +00002992 - Exception Controls
2993 - Non-IEEE Mode
2994 */
2995 if (mask & 0xFC) { // Exception Control, Non-IEE mode
florian6ef84be2012-08-26 03:20:07 +00002996 VexEmNote ew = EmWarn_PPCexns;
sewardje14bb9f2005-07-22 09:39:02 +00002997
2998 /* If any of the src::exception_control bits are actually set,
2999 side-exit to the next insn, reporting the warning,
3000 so that Valgrind's dispatcher sees the warning. */
ceriond953ebb2005-11-29 13:27:20 +00003001 putGST( PPC_GST_EMWARN, mkU32(ew) );
sewardje14bb9f2005-07-22 09:39:02 +00003002 stmt(
3003 IRStmt_Exit(
florian6ef84be2012-08-26 03:20:07 +00003004 binop(Iop_CmpNE32, mkU32(ew), mkU32(EmNote_NONE)),
sewardje14bb9f2005-07-22 09:39:02 +00003005 Ijk_EmWarn,
sewardj3dee8492012-04-20 00:13:28 +00003006 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
sewardje14bb9f2005-07-22 09:39:02 +00003007 }
3008
cerionedf7fc52005-11-18 20:57:41 +00003009 /* Ignore all other writes */
sewardje14bb9f2005-07-22 09:39:02 +00003010 break;
cerionedf7fc52005-11-18 20:57:41 +00003011 }
sewardje14bb9f2005-07-22 09:39:02 +00003012
3013 default:
cerion5b2325f2005-12-23 00:55:09 +00003014 vex_printf("putGST_masked(ppc): reg = %u", reg);
3015 vpanic("putGST_masked(ppc)");
sewardje14bb9f2005-07-22 09:39:02 +00003016 }
3017}
3018
cerionedf7fc52005-11-18 20:57:41 +00003019/* Write the least significant nibble of src to the specified
3020 REG[FLD] (as per IBM/hardware notation). */
ceriond953ebb2005-11-29 13:27:20 +00003021static void putGST_field ( PPC_GST reg, IRExpr* src, UInt fld )
cerionedf7fc52005-11-18 20:57:41 +00003022{
sewardjc6bbd472012-04-02 10:20:48 +00003023 UInt shft;
3024 ULong mask;
sewardj41a7b702005-11-18 22:18:23 +00003025
sewardjdd40fdf2006-12-24 02:20:24 +00003026 vassert( typeOfIRExpr(irsb->tyenv,src ) == Ity_I32 );
sewardjc6bbd472012-04-02 10:20:48 +00003027 vassert( fld < 16 );
ceriond953ebb2005-11-29 13:27:20 +00003028 vassert( reg < PPC_GST_MAX );
cerionedf7fc52005-11-18 20:57:41 +00003029
sewardjc6bbd472012-04-02 10:20:48 +00003030 if (fld < 8)
3031 shft = 4*(7-fld);
3032 else
3033 shft = 4*(15-fld);
florian654b7f92013-02-02 00:10:36 +00003034 mask = 0xF;
3035 mask = mask << shft;
cerionedf7fc52005-11-18 20:57:41 +00003036
3037 switch (reg) {
ceriond953ebb2005-11-29 13:27:20 +00003038 case PPC_GST_CR:
cerionedf7fc52005-11-18 20:57:41 +00003039 putCR0 (fld, binop(Iop_And8, mkU8(1 ), unop(Iop_32to8, src)));
3040 putCR321(fld, binop(Iop_And8, mkU8(7<<1), unop(Iop_32to8, src)));
3041 break;
3042
3043 default:
sewardjc6bbd472012-04-02 10:20:48 +00003044 {
3045 IRExpr * src64 = unop( Iop_32Uto64, src );
3046
3047 if (shft == 0) {
3048 putGST_masked( reg, src64, mask );
3049 } else {
3050 putGST_masked( reg,
3051 binop( Iop_Shl64, src64, mkU8( toUChar( shft ) ) ),
3052 mask );
3053 }
cerionedf7fc52005-11-18 20:57:41 +00003054 }
3055 }
3056}
cerion62bec572005-02-01 21:29:39 +00003057
sewardj66d5ef22011-04-15 11:55:00 +00003058/*------------------------------------------------------------*/
3059/* Helpers for VSX instructions that do floating point
3060 * operations and need to determine if a src contains a
3061 * special FP value.
3062 *
3063 *------------------------------------------------------------*/
3064
3065#define NONZERO_FRAC_MASK 0x000fffffffffffffULL
3066#define FP_FRAC_PART(x) binop( Iop_And64, \
3067 mkexpr( x ), \
3068 mkU64( NONZERO_FRAC_MASK ) )
3069
sewardje71e56a2011-09-05 12:11:06 +00003070// Returns exponent part of a single precision floating point as I32
3071static IRExpr * fp_exp_part_sp(IRTemp src)
3072{
3073 return binop( Iop_And32,
3074 binop( Iop_Shr32, mkexpr( src ), mkU8( 23 ) ),
3075 mkU32( 0xff ) );
3076}
3077
sewardj66d5ef22011-04-15 11:55:00 +00003078// Returns exponent part of floating point as I32
sewardje71e56a2011-09-05 12:11:06 +00003079static IRExpr * fp_exp_part(IRTemp src, Bool sp)
sewardj66d5ef22011-04-15 11:55:00 +00003080{
3081 IRExpr * exp;
sewardje71e56a2011-09-05 12:11:06 +00003082 if (sp)
3083 return fp_exp_part_sp(src);
3084
sewardj66d5ef22011-04-15 11:55:00 +00003085 if (!mode64)
3086 exp = binop( Iop_And32, binop( Iop_Shr32, unop( Iop_64HIto32,
3087 mkexpr( src ) ),
3088 mkU8( 20 ) ), mkU32( 0x7ff ) );
3089 else
3090 exp = unop( Iop_64to32,
3091 binop( Iop_And64,
3092 binop( Iop_Shr64, mkexpr( src ), mkU8( 52 ) ),
3093 mkU64( 0x7ff ) ) );
3094 return exp;
3095}
3096
sewardje71e56a2011-09-05 12:11:06 +00003097static IRExpr * is_Inf_sp(IRTemp src)
3098{
3099 IRTemp frac_part = newTemp(Ity_I32);
3100 IRExpr * Inf_exp;
3101
3102 assign( frac_part, binop( Iop_And32, mkexpr(src), mkU32(0x007fffff)) );
3103 Inf_exp = binop( Iop_CmpEQ32, fp_exp_part( src, True /*single precision*/ ), mkU32( 0xff ) );
3104 return mkAND1( Inf_exp, binop( Iop_CmpEQ32, mkexpr( frac_part ), mkU32( 0 ) ) );
3105}
3106
sewardj66d5ef22011-04-15 11:55:00 +00003107
3108// Infinity: exp = 7ff and fraction is zero; s = 0/1
sewardje71e56a2011-09-05 12:11:06 +00003109static IRExpr * is_Inf(IRTemp src, Bool sp)
sewardj66d5ef22011-04-15 11:55:00 +00003110{
3111 IRExpr * Inf_exp, * hi32, * low32;
sewardje71e56a2011-09-05 12:11:06 +00003112 IRTemp frac_part;
sewardj66d5ef22011-04-15 11:55:00 +00003113
sewardje71e56a2011-09-05 12:11:06 +00003114 if (sp)
3115 return is_Inf_sp(src);
3116
3117 frac_part = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +00003118 assign( frac_part, FP_FRAC_PART(src) );
sewardje71e56a2011-09-05 12:11:06 +00003119 Inf_exp = binop( Iop_CmpEQ32, fp_exp_part( src, False /*not single precision*/ ), mkU32( 0x7ff ) );
sewardj66d5ef22011-04-15 11:55:00 +00003120 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
3121 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
3122 return mkAND1( Inf_exp, binop( Iop_CmpEQ32, binop( Iop_Or32, low32, hi32 ),
3123 mkU32( 0 ) ) );
3124}
3125
sewardje71e56a2011-09-05 12:11:06 +00003126static IRExpr * is_Zero_sp(IRTemp src)
3127{
3128 IRTemp sign_less_part = newTemp(Ity_I32);
3129 assign( sign_less_part, binop( Iop_And32, mkexpr( src ), mkU32( SIGN_MASK32 ) ) );
3130 return binop( Iop_CmpEQ32, mkexpr( sign_less_part ), mkU32( 0 ) );
3131}
3132
sewardj66d5ef22011-04-15 11:55:00 +00003133// Zero: exp is zero and fraction is zero; s = 0/1
sewardje71e56a2011-09-05 12:11:06 +00003134static IRExpr * is_Zero(IRTemp src, Bool sp)
sewardj66d5ef22011-04-15 11:55:00 +00003135{
sewardj66d5ef22011-04-15 11:55:00 +00003136 IRExpr * hi32, * low32;
sewardje71e56a2011-09-05 12:11:06 +00003137 IRTemp sign_less_part;
3138 if (sp)
3139 return is_Zero_sp(src);
3140
3141 sign_less_part = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +00003142
3143 assign( sign_less_part, binop( Iop_And64, mkexpr( src ), mkU64( SIGN_MASK ) ) );
3144 hi32 = unop( Iop_64HIto32, mkexpr( sign_less_part ) );
3145 low32 = unop( Iop_64to32, mkexpr( sign_less_part ) );
3146 return binop( Iop_CmpEQ32, binop( Iop_Or32, low32, hi32 ),
3147 mkU32( 0 ) );
3148}
3149
3150/* SNAN: s = 1/0; exp = 0x7ff; fraction is nonzero, with highest bit '1'
3151 * QNAN: s = 1/0; exp = 0x7ff; fraction is nonzero, with highest bit '0'
3152 * This function returns an IRExpr value of '1' for any type of NaN.
3153 */
3154static IRExpr * is_NaN(IRTemp src)
3155{
3156 IRExpr * NaN_exp, * hi32, * low32;
3157 IRTemp frac_part = newTemp(Ity_I64);
3158
3159 assign( frac_part, FP_FRAC_PART(src) );
3160 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
3161 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
sewardje71e56a2011-09-05 12:11:06 +00003162 NaN_exp = binop( Iop_CmpEQ32, fp_exp_part( src, False /*not single precision*/ ),
3163 mkU32( 0x7ff ) );
sewardj66d5ef22011-04-15 11:55:00 +00003164
3165 return mkAND1( NaN_exp, binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
3166 mkU32( 0 ) ) );
3167}
cerion76222262005-02-05 13:45:57 +00003168
sewardj4aa412a2011-07-24 14:13:21 +00003169/* This function returns an IRExpr value of '1' for any type of NaN.
3170 * The passed 'src' argument is assumed to be Ity_I32.
3171 */
3172static IRExpr * is_NaN_32(IRTemp src)
3173{
3174#define NONZERO_FRAC_MASK32 0x007fffffULL
3175#define FP_FRAC_PART32(x) binop( Iop_And32, \
3176 mkexpr( x ), \
3177 mkU32( NONZERO_FRAC_MASK32 ) )
3178
3179 IRExpr * frac_part = FP_FRAC_PART32(src);
3180 IRExpr * exp_part = binop( Iop_And32,
3181 binop( Iop_Shr32, mkexpr( src ), mkU8( 23 ) ),
3182 mkU32( 0x0ff ) );
3183 IRExpr * NaN_exp = binop( Iop_CmpEQ32, exp_part, mkU32( 0xff ) );
3184
3185 return mkAND1( NaN_exp, binop( Iop_CmpNE32, frac_part, mkU32( 0 ) ) );
3186}
3187
carll6fef87a2013-09-12 17:26:42 +00003188/* This function takes an Ity_I32 input argument interpreted
3189 * as a single-precision floating point value. If src is a
3190 * SNaN, it is changed to a QNaN and returned; otherwise,
3191 * the original value is returned.
3192 */
3193static IRExpr * handle_SNaN_to_QNaN_32(IRExpr * src)
3194{
3195#define SNAN_MASK32 0x00400000
3196 IRTemp tmp = newTemp(Ity_I32);
3197 IRTemp mask = newTemp(Ity_I32);
3198 IRTemp is_SNAN = newTemp(Ity_I1);
3199
3200 vassert( typeOfIRExpr(irsb->tyenv, src ) == Ity_I32 );
3201 assign(tmp, src);
3202
3203 /* check if input is SNaN, if it is convert to QNaN */
3204 assign( is_SNAN,
3205 mkAND1( is_NaN_32( tmp ),
3206 binop( Iop_CmpEQ32,
3207 binop( Iop_And32, mkexpr( tmp ),
3208 mkU32( SNAN_MASK32 ) ),
3209 mkU32( 0 ) ) ) );
3210 /* create mask with QNaN bit set to make it a QNaN if tmp is SNaN */
3211 assign ( mask, binop( Iop_And32,
3212 unop( Iop_1Sto32, mkexpr( is_SNAN ) ),
3213 mkU32( SNAN_MASK32 ) ) );
3214 return binop( Iop_Or32, mkexpr( mask ), mkexpr( tmp) );
3215}
3216
3217
sewardj4aa412a2011-07-24 14:13:21 +00003218/* This helper function performs the negation part of operations of the form:
3219 * "Negate Multiply-<op>"
3220 * where "<op>" is either "Add" or "Sub".
3221 *
3222 * This function takes one argument -- the floating point intermediate result (converted to
3223 * Ity_I64 via Iop_ReinterpF64asI64) that was obtained from the "Multip-<op>" part of
3224 * the operation described above.
3225 */
3226static IRTemp getNegatedResult(IRTemp intermediateResult)
3227{
3228 ULong signbit_mask = 0x8000000000000000ULL;
3229 IRTemp signbit_32 = newTemp(Ity_I32);
3230 IRTemp resultantSignbit = newTemp(Ity_I1);
3231 IRTemp negatedResult = newTemp(Ity_I64);
3232 assign( signbit_32, binop( Iop_Shr32,
3233 unop( Iop_64HIto32,
3234 binop( Iop_And64, mkexpr( intermediateResult ),
3235 mkU64( signbit_mask ) ) ),
3236 mkU8( 31 ) ) );
3237 /* We negate the signbit if and only if the intermediate result from the
3238 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
3239 */
3240 assign( resultantSignbit,
3241 unop( Iop_Not1,
3242 binop( Iop_CmpEQ32,
3243 binop( Iop_Xor32,
3244 mkexpr( signbit_32 ),
3245 unop( Iop_1Uto32, is_NaN( intermediateResult ) ) ),
3246 mkU32( 1 ) ) ) );
3247
3248 assign( negatedResult,
3249 binop( Iop_Or64,
3250 binop( Iop_And64,
3251 mkexpr( intermediateResult ),
3252 mkU64( ~signbit_mask ) ),
3253 binop( Iop_32HLto64,
3254 binop( Iop_Shl32,
3255 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
3256 mkU8( 31 ) ),
3257 mkU32( 0 ) ) ) );
3258
3259 return negatedResult;
3260}
3261
3262/* This helper function performs the negation part of operations of the form:
3263 * "Negate Multiply-<op>"
3264 * where "<op>" is either "Add" or "Sub".
3265 *
3266 * This function takes one argument -- the floating point intermediate result (converted to
3267 * Ity_I32 via Iop_ReinterpF32asI32) that was obtained from the "Multip-<op>" part of
3268 * the operation described above.
3269 */
3270static IRTemp getNegatedResult_32(IRTemp intermediateResult)
3271{
3272 UInt signbit_mask = 0x80000000;
3273 IRTemp signbit_32 = newTemp(Ity_I32);
3274 IRTemp resultantSignbit = newTemp(Ity_I1);
3275 IRTemp negatedResult = newTemp(Ity_I32);
3276 assign( signbit_32, binop( Iop_Shr32,
3277 binop( Iop_And32, mkexpr( intermediateResult ),
3278 mkU32( signbit_mask ) ),
3279 mkU8( 31 ) ) );
3280 /* We negate the signbit if and only if the intermediate result from the
3281 * multiply-<op> was NOT a NaN. This is an XNOR predicate.
3282 */
3283 assign( resultantSignbit,
3284 unop( Iop_Not1,
3285 binop( Iop_CmpEQ32,
3286 binop( Iop_Xor32,
3287 mkexpr( signbit_32 ),
3288 unop( Iop_1Uto32, is_NaN_32( intermediateResult ) ) ),
3289 mkU32( 1 ) ) ) );
3290
3291 assign( negatedResult,
3292 binop( Iop_Or32,
3293 binop( Iop_And32,
3294 mkexpr( intermediateResult ),
3295 mkU32( ~signbit_mask ) ),
3296 binop( Iop_Shl32,
3297 unop( Iop_1Uto32, mkexpr( resultantSignbit ) ),
3298 mkU8( 31 ) ) ) );
3299
3300 return negatedResult;
3301}
cerion76222262005-02-05 13:45:57 +00003302
cerione9d361a2005-03-04 17:35:29 +00003303/*------------------------------------------------------------*/
carll8943d022013-10-02 16:25:57 +00003304/* Transactional memory helpers
3305 *
3306 *------------------------------------------------------------*/
3307
3308static ULong generate_TMreason( UInt failure_code,
3309 UInt persistant,
3310 UInt nest_overflow,
3311 UInt tm_exact )
3312{
3313 ULong tm_err_code =
3314 ( (ULong) 0) << (63-6) /* Failure code */
3315 | ( (ULong) persistant) << (63-7) /* Failure persistant */
3316 | ( (ULong) 0) << (63-8) /* Disallowed */
3317 | ( (ULong) nest_overflow) << (63-9) /* Nesting Overflow */
3318 | ( (ULong) 0) << (63-10) /* Footprint Overflow */
3319 | ( (ULong) 0) << (63-11) /* Self-Induced Conflict */
3320 | ( (ULong) 0) << (63-12) /* Non-Transactional Conflict */
3321 | ( (ULong) 0) << (63-13) /* Transactional Conflict */
3322 | ( (ULong) 0) << (63-14) /* Translation Invalidation Conflict */
3323 | ( (ULong) 0) << (63-15) /* Implementation-specific */
3324 | ( (ULong) 0) << (63-16) /* Instruction Fetch Conflict */
3325 | ( (ULong) 0) << (63-30) /* Reserved */
3326 | ( (ULong) 0) << (63-31) /* Abort */
3327 | ( (ULong) 0) << (63-32) /* Suspend */
3328 | ( (ULong) 0) << (63-33) /* Reserved */
3329 | ( (ULong) 0) << (63-35) /* Privilege */
3330 | ( (ULong) 0) << (63-36) /* Failure Summary */
3331 | ( (ULong) tm_exact) << (63-37) /* TFIAR Exact */
3332 | ( (ULong) 0) << (63-38) /* ROT */
3333 | ( (ULong) 0) << (63-51) /* Reserved */
3334 | ( (ULong) 0) << (63-63); /* Transaction Level */
3335
3336 return tm_err_code;
3337}
3338
3339static void storeTMfailure( Addr64 err_address, ULong tm_reason,
3340 Addr64 handler_address )
3341{
3342 putGST( PPC_GST_TFIAR, mkU64( err_address ) );
3343 putGST( PPC_GST_TEXASR, mkU64( tm_reason ) );
3344 putGST( PPC_GST_TFHAR, mkU64( handler_address ) );
3345}
3346
3347/*------------------------------------------------------------*/
cerion3d870a32005-03-18 12:23:33 +00003348/*--- Integer Instruction Translation --- */
cerione9d361a2005-03-04 17:35:29 +00003349/*------------------------------------------------------------*/
cerion896a1372005-01-25 12:24:25 +00003350
cerion91ad5362005-01-27 23:02:41 +00003351/*
3352 Integer Arithmetic Instructions
3353*/
cerion645c9302005-01-31 10:09:59 +00003354static Bool dis_int_arith ( UInt theInstr )
cerion91ad5362005-01-27 23:02:41 +00003355{
cerion76de5cf2005-11-18 18:25:12 +00003356 /* D-Form, XO-Form */
3357 UChar opc1 = ifieldOPC(theInstr);
3358 UChar rD_addr = ifieldRegDS(theInstr);
3359 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00003360 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00003361 UChar rB_addr = ifieldRegB(theInstr);
3362 UChar flag_OE = ifieldBIT10(theInstr);
3363 UInt opc2 = ifieldOPClo9(theInstr);
3364 UChar flag_rC = ifieldBIT0(theInstr);
3365
ceriond953ebb2005-11-29 13:27:20 +00003366 Long simm16 = extend_s_16to64(uimm16);
3367 IRType ty = mode64 ? Ity_I64 : Ity_I32;
3368 IRTemp rA = newTemp(ty);
3369 IRTemp rB = newTemp(ty);
3370 IRTemp rD = newTemp(ty);
cerion70e24122005-03-16 00:27:37 +00003371
cerionb85e8bb2005-02-16 08:54:33 +00003372 Bool do_rc = False;
cerion91ad5362005-01-27 23:02:41 +00003373
cerion76de5cf2005-11-18 18:25:12 +00003374 assign( rA, getIReg(rA_addr) );
3375 assign( rB, getIReg(rB_addr) ); // XO-Form: rD, rA, rB
sewardjb51f0f42005-07-18 11:38:02 +00003376
cerionb85e8bb2005-02-16 08:54:33 +00003377 switch (opc1) {
cerionb85e8bb2005-02-16 08:54:33 +00003378 /* D-Form */
cerione9d361a2005-03-04 17:35:29 +00003379 case 0x0C: // addic (Add Immediate Carrying, PPC32 p351
ceriond953ebb2005-11-29 13:27:20 +00003380 DIP("addic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003381 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3382 mkSzExtendS16(ty, uimm16) ) );
cerion5b2325f2005-12-23 00:55:09 +00003383 set_XER_CA( ty, PPCG_FLAG_OP_ADD,
cerion2831b002005-11-30 19:55:22 +00003384 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
3385 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion4561acb2005-02-21 14:07:48 +00003386 break;
sewardjb51f0f42005-07-18 11:38:02 +00003387
cerione9d361a2005-03-04 17:35:29 +00003388 case 0x0D: // addic. (Add Immediate Carrying and Record, PPC32 p352)
ceriond953ebb2005-11-29 13:27:20 +00003389 DIP("addic. r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003390 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3391 mkSzExtendS16(ty, uimm16) ) );
cerion5b2325f2005-12-23 00:55:09 +00003392 set_XER_CA( ty, PPCG_FLAG_OP_ADD,
cerion2831b002005-11-30 19:55:22 +00003393 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
3394 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00003395 do_rc = True; // Always record to CR
cerion76de5cf2005-11-18 18:25:12 +00003396 flag_rC = 1;
cerion4561acb2005-02-21 14:07:48 +00003397 break;
3398
cerione9d361a2005-03-04 17:35:29 +00003399 case 0x0E: // addi (Add Immediate, PPC32 p350)
cerionb85e8bb2005-02-16 08:54:33 +00003400 // li rD,val == addi rD,0,val
3401 // la disp(rA) == addi rD,rA,disp
cerion76de5cf2005-11-18 18:25:12 +00003402 if ( rA_addr == 0 ) {
ceriond953ebb2005-11-29 13:27:20 +00003403 DIP("li r%u,%d\n", rD_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003404 assign( rD, mkSzExtendS16(ty, uimm16) );
cerionb85e8bb2005-02-16 08:54:33 +00003405 } else {
ceriond953ebb2005-11-29 13:27:20 +00003406 DIP("addi r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003407 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3408 mkSzExtendS16(ty, uimm16) ) );
cerionb85e8bb2005-02-16 08:54:33 +00003409 }
3410 break;
cerion91ad5362005-01-27 23:02:41 +00003411
cerione9d361a2005-03-04 17:35:29 +00003412 case 0x0F: // addis (Add Immediate Shifted, PPC32 p353)
cerionb85e8bb2005-02-16 08:54:33 +00003413 // lis rD,val == addis rD,0,val
cerion76de5cf2005-11-18 18:25:12 +00003414 if ( rA_addr == 0 ) {
ceriond953ebb2005-11-29 13:27:20 +00003415 DIP("lis r%u,%d\n", rD_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003416 assign( rD, mkSzExtendS32(ty, uimm16 << 16) );
cerionb85e8bb2005-02-16 08:54:33 +00003417 } else {
ceriond953ebb2005-11-29 13:27:20 +00003418 DIP("addis r%u,r%u,0x%x\n", rD_addr, rA_addr, (Int)simm16);
cerion2831b002005-11-30 19:55:22 +00003419 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3420 mkSzExtendS32(ty, uimm16 << 16) ) );
cerionb85e8bb2005-02-16 08:54:33 +00003421 }
3422 break;
cerion91ad5362005-01-27 23:02:41 +00003423
cerione9d361a2005-03-04 17:35:29 +00003424 case 0x07: // mulli (Multiply Low Immediate, PPC32 p490)
ceriond953ebb2005-11-29 13:27:20 +00003425 DIP("mulli r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
3426 if (mode64)
3427 assign( rD, unop(Iop_128to64,
3428 binop(Iop_MullS64, mkexpr(rA),
cerion2831b002005-11-30 19:55:22 +00003429 mkSzExtendS16(ty, uimm16))) );
ceriond953ebb2005-11-29 13:27:20 +00003430 else
3431 assign( rD, unop(Iop_64to32,
3432 binop(Iop_MullS32, mkexpr(rA),
cerion2831b002005-11-30 19:55:22 +00003433 mkSzExtendS16(ty, uimm16))) );
cerionb85e8bb2005-02-16 08:54:33 +00003434 break;
cerion38674602005-02-08 02:19:25 +00003435
cerione9d361a2005-03-04 17:35:29 +00003436 case 0x08: // subfic (Subtract from Immediate Carrying, PPC32 p540)
ceriond953ebb2005-11-29 13:27:20 +00003437 DIP("subfic r%u,r%u,%d\n", rD_addr, rA_addr, (Int)simm16);
cerion76de5cf2005-11-18 18:25:12 +00003438 // rD = simm16 - rA
cerion2831b002005-11-30 19:55:22 +00003439 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
3440 mkSzExtendS16(ty, uimm16),
ceriond953ebb2005-11-29 13:27:20 +00003441 mkexpr(rA)) );
cerion5b2325f2005-12-23 00:55:09 +00003442 set_XER_CA( ty, PPCG_FLAG_OP_SUBFI,
cerion2831b002005-11-30 19:55:22 +00003443 mkexpr(rD), mkexpr(rA), mkSzExtendS16(ty, uimm16),
3444 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerionb85e8bb2005-02-16 08:54:33 +00003445 break;
cerion38674602005-02-08 02:19:25 +00003446
cerionb85e8bb2005-02-16 08:54:33 +00003447 /* XO-Form */
3448 case 0x1F:
cerionb85e8bb2005-02-16 08:54:33 +00003449 do_rc = True; // All below record to CR
3450
3451 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00003452 case 0x10A: // add (Add, PPC32 p347)
ceriond953ebb2005-11-29 13:27:20 +00003453 DIP("add%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003454 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003455 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003456 assign( rD, binop( mkSzOp(ty, Iop_Add8),
ceriond953ebb2005-11-29 13:27:20 +00003457 mkexpr(rA), mkexpr(rB) ) );
cerion70e24122005-03-16 00:27:37 +00003458 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003459 set_XER_OV( ty, PPCG_FLAG_OP_ADD,
cerion76de5cf2005-11-18 18:25:12 +00003460 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003461 }
cerionb85e8bb2005-02-16 08:54:33 +00003462 break;
cerion91ad5362005-01-27 23:02:41 +00003463
cerione9d361a2005-03-04 17:35:29 +00003464 case 0x00A: // addc (Add Carrying, PPC32 p348)
ceriond953ebb2005-11-29 13:27:20 +00003465 DIP("addc%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003466 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003467 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003468 assign( rD, binop( mkSzOp(ty, Iop_Add8),
ceriond953ebb2005-11-29 13:27:20 +00003469 mkexpr(rA), mkexpr(rB)) );
cerion5b2325f2005-12-23 00:55:09 +00003470 set_XER_CA( ty, PPCG_FLAG_OP_ADD,
cerion76de5cf2005-11-18 18:25:12 +00003471 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003472 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00003473 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003474 set_XER_OV( ty, PPCG_FLAG_OP_ADD,
cerion76de5cf2005-11-18 18:25:12 +00003475 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003476 }
cerionb85e8bb2005-02-16 08:54:33 +00003477 break;
3478
sewardjb51f0f42005-07-18 11:38:02 +00003479 case 0x08A: { // adde (Add Extended, PPC32 p349)
cerion2831b002005-11-30 19:55:22 +00003480 IRTemp old_xer_ca = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00003481 DIP("adde%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003482 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003483 rD_addr, rA_addr, rB_addr);
cerionb85e8bb2005-02-16 08:54:33 +00003484 // rD = rA + rB + XER[CA]
sewardje9d8a262009-07-01 08:06:34 +00003485 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003486 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3487 binop( mkSzOp(ty, Iop_Add8),
3488 mkexpr(rB), mkexpr(old_xer_ca))) );
cerion5b2325f2005-12-23 00:55:09 +00003489 set_XER_CA( ty, PPCG_FLAG_OP_ADDE,
cerion76de5cf2005-11-18 18:25:12 +00003490 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003491 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003492 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003493 set_XER_OV( ty, PPCG_FLAG_OP_ADDE,
cerion76de5cf2005-11-18 18:25:12 +00003494 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003495 }
cerionb85e8bb2005-02-16 08:54:33 +00003496 break;
sewardjb51f0f42005-07-18 11:38:02 +00003497 }
3498
cerion5b2325f2005-12-23 00:55:09 +00003499 case 0x0EA: { // addme (Add to Minus One Extended, PPC32 p354)
cerion2831b002005-11-30 19:55:22 +00003500 IRTemp old_xer_ca = newTemp(ty);
3501 IRExpr *min_one;
cerion76de5cf2005-11-18 18:25:12 +00003502 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003503 vex_printf("dis_int_arith(ppc)(addme,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003504 return False;
3505 }
ceriond953ebb2005-11-29 13:27:20 +00003506 DIP("addme%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003507 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003508 rD_addr, rA_addr, rB_addr);
cerion70e24122005-03-16 00:27:37 +00003509 // rD = rA + (-1) + XER[CA]
3510 // => Just another form of adde
sewardje9d8a262009-07-01 08:06:34 +00003511 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003512 min_one = mkSzImm(ty, (Long)-1);
3513 assign( rD, binop( mkSzOp(ty, Iop_Add8), mkexpr(rA),
3514 binop( mkSzOp(ty, Iop_Add8),
3515 min_one, mkexpr(old_xer_ca)) ));
cerion5b2325f2005-12-23 00:55:09 +00003516 set_XER_CA( ty, PPCG_FLAG_OP_ADDE,
ceriond953ebb2005-11-29 13:27:20 +00003517 mkexpr(rD), mkexpr(rA), min_one,
cerion2831b002005-11-30 19:55:22 +00003518 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003519 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003520 set_XER_OV( ty, PPCG_FLAG_OP_ADDE,
ceriond953ebb2005-11-29 13:27:20 +00003521 mkexpr(rD), mkexpr(rA), min_one );
cerion70e24122005-03-16 00:27:37 +00003522 }
cerionb85e8bb2005-02-16 08:54:33 +00003523 break;
sewardjb51f0f42005-07-18 11:38:02 +00003524 }
3525
3526 case 0x0CA: { // addze (Add to Zero Extended, PPC32 p355)
cerion2831b002005-11-30 19:55:22 +00003527 IRTemp old_xer_ca = newTemp(ty);
cerion76de5cf2005-11-18 18:25:12 +00003528 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003529 vex_printf("dis_int_arith(ppc)(addze,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003530 return False;
3531 }
ceriond953ebb2005-11-29 13:27:20 +00003532 DIP("addze%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003533 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003534 rD_addr, rA_addr, rB_addr);
cerion70e24122005-03-16 00:27:37 +00003535 // rD = rA + (0) + XER[CA]
3536 // => Just another form of adde
sewardje9d8a262009-07-01 08:06:34 +00003537 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003538 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3539 mkexpr(rA), mkexpr(old_xer_ca)) );
cerion5b2325f2005-12-23 00:55:09 +00003540 set_XER_CA( ty, PPCG_FLAG_OP_ADDE,
cerion2831b002005-11-30 19:55:22 +00003541 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
3542 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003543 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003544 set_XER_OV( ty, PPCG_FLAG_OP_ADDE,
cerion2831b002005-11-30 19:55:22 +00003545 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
cerion70e24122005-03-16 00:27:37 +00003546 }
cerionb85e8bb2005-02-16 08:54:33 +00003547 break;
sewardjb51f0f42005-07-18 11:38:02 +00003548 }
cerion91ad5362005-01-27 23:02:41 +00003549
cerione9d361a2005-03-04 17:35:29 +00003550 case 0x1EB: // divw (Divide Word, PPC32 p388)
ceriond953ebb2005-11-29 13:27:20 +00003551 DIP("divw%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003552 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003553 rD_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00003554 if (mode64) {
cerion2831b002005-11-30 19:55:22 +00003555 /* Note:
3556 XER settings are mode independent, and reflect the
3557 overflow of the low-order 32bit result
3558 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
3559 */
cerionbb01b7c2005-12-16 13:40:18 +00003560 /* rD[hi32] are undefined: setting them to sign of lo32
3561 - makes set_CR0 happy */
3562 IRExpr* dividend = mk64lo32Sto64( mkexpr(rA) );
3563 IRExpr* divisor = mk64lo32Sto64( mkexpr(rB) );
cerion5b2325f2005-12-23 00:55:09 +00003564 assign( rD, mk64lo32Uto64( binop(Iop_DivS64, dividend,
3565 divisor) ) );
ceriond953ebb2005-11-29 13:27:20 +00003566 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003567 set_XER_OV( ty, PPCG_FLAG_OP_DIVW,
cerionf0de28c2005-12-13 20:21:11 +00003568 mkexpr(rD), dividend, divisor );
ceriond953ebb2005-11-29 13:27:20 +00003569 }
3570 } else {
3571 assign( rD, binop(Iop_DivS32, mkexpr(rA), mkexpr(rB)) );
3572 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003573 set_XER_OV( ty, PPCG_FLAG_OP_DIVW,
ceriond953ebb2005-11-29 13:27:20 +00003574 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3575 }
cerion70e24122005-03-16 00:27:37 +00003576 }
cerionb85e8bb2005-02-16 08:54:33 +00003577 /* Note:
3578 if (0x8000_0000 / -1) or (x / 0)
cerion76de5cf2005-11-18 18:25:12 +00003579 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
cerionb85e8bb2005-02-16 08:54:33 +00003580 => But _no_ exception raised. */
3581 break;
cerion91ad5362005-01-27 23:02:41 +00003582
cerione9d361a2005-03-04 17:35:29 +00003583 case 0x1CB: // divwu (Divide Word Unsigned, PPC32 p389)
ceriond953ebb2005-11-29 13:27:20 +00003584 DIP("divwu%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003585 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003586 rD_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00003587 if (mode64) {
cerion2831b002005-11-30 19:55:22 +00003588 /* Note:
3589 XER settings are mode independent, and reflect the
3590 overflow of the low-order 32bit result
3591 CR0[LT|GT|EQ] are undefined if flag_rC && mode64
3592 */
cerionbb01b7c2005-12-16 13:40:18 +00003593 IRExpr* dividend = mk64lo32Uto64( mkexpr(rA) );
3594 IRExpr* divisor = mk64lo32Uto64( mkexpr(rB) );
cerion5b2325f2005-12-23 00:55:09 +00003595 assign( rD, mk64lo32Uto64( binop(Iop_DivU64, dividend,
3596 divisor) ) );
ceriond953ebb2005-11-29 13:27:20 +00003597 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003598 set_XER_OV( ty, PPCG_FLAG_OP_DIVWU,
cerionf0de28c2005-12-13 20:21:11 +00003599 mkexpr(rD), dividend, divisor );
ceriond953ebb2005-11-29 13:27:20 +00003600 }
cerion2831b002005-11-30 19:55:22 +00003601 } else {
ceriond953ebb2005-11-29 13:27:20 +00003602 assign( rD, binop(Iop_DivU32, mkexpr(rA), mkexpr(rB)) );
3603 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003604 set_XER_OV( ty, PPCG_FLAG_OP_DIVWU,
ceriond953ebb2005-11-29 13:27:20 +00003605 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3606 }
cerion70e24122005-03-16 00:27:37 +00003607 }
cerionb85e8bb2005-02-16 08:54:33 +00003608 /* Note: ditto comment divw, for (x / 0) */
3609 break;
cerion91ad5362005-01-27 23:02:41 +00003610
cerione9d361a2005-03-04 17:35:29 +00003611 case 0x04B: // mulhw (Multiply High Word, PPC32 p488)
cerionb85e8bb2005-02-16 08:54:33 +00003612 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003613 vex_printf("dis_int_arith(ppc)(mulhw,flag_OE)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003614 return False;
3615 }
cerion5b2325f2005-12-23 00:55:09 +00003616 DIP("mulhw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003617 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003618 if (mode64) {
cerionbb01b7c2005-12-16 13:40:18 +00003619 /* rD[hi32] are undefined: setting them to sign of lo32
3620 - makes set_CR0 happy */
3621 assign( rD, binop(Iop_Sar64,
3622 binop(Iop_Mul64,
3623 mk64lo32Sto64( mkexpr(rA) ),
3624 mk64lo32Sto64( mkexpr(rB) )),
3625 mkU8(32)) );
cerion2831b002005-11-30 19:55:22 +00003626 } else {
ceriond953ebb2005-11-29 13:27:20 +00003627 assign( rD, unop(Iop_64HIto32,
3628 binop(Iop_MullS32,
3629 mkexpr(rA), mkexpr(rB))) );
cerion2831b002005-11-30 19:55:22 +00003630 }
cerionb85e8bb2005-02-16 08:54:33 +00003631 break;
cerionc19d5e12005-02-01 15:56:25 +00003632
cerion5b2325f2005-12-23 00:55:09 +00003633 case 0x00B: // mulhwu (Multiply High Word Unsigned, PPC32 p489)
cerionb85e8bb2005-02-16 08:54:33 +00003634 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003635 vex_printf("dis_int_arith(ppc)(mulhwu,flag_OE)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003636 return False;
3637 }
cerion5b2325f2005-12-23 00:55:09 +00003638 DIP("mulhwu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003639 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003640 if (mode64) {
cerionbb01b7c2005-12-16 13:40:18 +00003641 /* rD[hi32] are undefined: setting them to sign of lo32
3642 - makes set_CR0 happy */
3643 assign( rD, binop(Iop_Sar64,
3644 binop(Iop_Mul64,
3645 mk64lo32Uto64( mkexpr(rA) ),
3646 mk64lo32Uto64( mkexpr(rB) ) ),
3647 mkU8(32)) );
cerion2831b002005-11-30 19:55:22 +00003648 } else {
ceriond953ebb2005-11-29 13:27:20 +00003649 assign( rD, unop(Iop_64HIto32,
3650 binop(Iop_MullU32,
3651 mkexpr(rA), mkexpr(rB))) );
cerion2831b002005-11-30 19:55:22 +00003652 }
cerionb85e8bb2005-02-16 08:54:33 +00003653 break;
3654
cerione9d361a2005-03-04 17:35:29 +00003655 case 0x0EB: // mullw (Multiply Low Word, PPC32 p491)
ceriond953ebb2005-11-29 13:27:20 +00003656 DIP("mullw%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003657 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003658 rD_addr, rA_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00003659 if (mode64) {
cerionbb01b7c2005-12-16 13:40:18 +00003660 /* rD[hi32] are undefined: setting them to sign of lo32
3661 - set_XER_OV() and set_CR0() depend on this */
3662 IRExpr *a = unop(Iop_64to32, mkexpr(rA) );
3663 IRExpr *b = unop(Iop_64to32, mkexpr(rB) );
3664 assign( rD, binop(Iop_MullS32, a, b) );
3665 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003666 set_XER_OV( ty, PPCG_FLAG_OP_MULLW,
cerionbb01b7c2005-12-16 13:40:18 +00003667 mkexpr(rD),
3668 unop(Iop_32Uto64, a), unop(Iop_32Uto64, b) );
3669 }
cerion2831b002005-11-30 19:55:22 +00003670 } else {
ceriond953ebb2005-11-29 13:27:20 +00003671 assign( rD, unop(Iop_64to32,
3672 binop(Iop_MullU32,
3673 mkexpr(rA), mkexpr(rB))) );
cerionbb01b7c2005-12-16 13:40:18 +00003674 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003675 set_XER_OV( ty, PPCG_FLAG_OP_MULLW,
cerionbb01b7c2005-12-16 13:40:18 +00003676 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3677 }
cerion70e24122005-03-16 00:27:37 +00003678 }
cerionb85e8bb2005-02-16 08:54:33 +00003679 break;
cerionc19d5e12005-02-01 15:56:25 +00003680
cerione9d361a2005-03-04 17:35:29 +00003681 case 0x068: // neg (Negate, PPC32 p493)
cerion76de5cf2005-11-18 18:25:12 +00003682 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003683 vex_printf("dis_int_arith(ppc)(neg,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003684 return False;
3685 }
ceriond953ebb2005-11-29 13:27:20 +00003686 DIP("neg%s%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003687 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003688 rD_addr, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00003689 // rD = (~rA) + 1
cerion2831b002005-11-30 19:55:22 +00003690 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3691 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA) ),
3692 mkSzImm(ty, 1)) );
cerion70e24122005-03-16 00:27:37 +00003693 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003694 set_XER_OV( ty, PPCG_FLAG_OP_NEG,
cerion76de5cf2005-11-18 18:25:12 +00003695 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003696 }
cerionb85e8bb2005-02-16 08:54:33 +00003697 break;
cerion91ad5362005-01-27 23:02:41 +00003698
cerione9d361a2005-03-04 17:35:29 +00003699 case 0x028: // subf (Subtract From, PPC32 p537)
ceriond953ebb2005-11-29 13:27:20 +00003700 DIP("subf%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003701 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003702 rD_addr, rA_addr, rB_addr);
cerion01908472005-02-25 16:43:08 +00003703 // rD = rB - rA
cerion2831b002005-11-30 19:55:22 +00003704 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
ceriond953ebb2005-11-29 13:27:20 +00003705 mkexpr(rB), mkexpr(rA)) );
cerion70e24122005-03-16 00:27:37 +00003706 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003707 set_XER_OV( ty, PPCG_FLAG_OP_SUBF,
cerion76de5cf2005-11-18 18:25:12 +00003708 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003709 }
cerionb85e8bb2005-02-16 08:54:33 +00003710 break;
cerion38674602005-02-08 02:19:25 +00003711
cerione9d361a2005-03-04 17:35:29 +00003712 case 0x008: // subfc (Subtract from Carrying, PPC32 p538)
ceriond953ebb2005-11-29 13:27:20 +00003713 DIP("subfc%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003714 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003715 rD_addr, rA_addr, rB_addr);
cerion01908472005-02-25 16:43:08 +00003716 // rD = rB - rA
cerion2831b002005-11-30 19:55:22 +00003717 assign( rD, binop( mkSzOp(ty, Iop_Sub8),
ceriond953ebb2005-11-29 13:27:20 +00003718 mkexpr(rB), mkexpr(rA)) );
cerion5b2325f2005-12-23 00:55:09 +00003719 set_XER_CA( ty, PPCG_FLAG_OP_SUBFC,
cerion76de5cf2005-11-18 18:25:12 +00003720 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003721 mkSzImm(ty, 0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00003722 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003723 set_XER_OV( ty, PPCG_FLAG_OP_SUBFC,
cerion76de5cf2005-11-18 18:25:12 +00003724 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003725 }
cerionb85e8bb2005-02-16 08:54:33 +00003726 break;
3727
sewardjb51f0f42005-07-18 11:38:02 +00003728 case 0x088: {// subfe (Subtract from Extended, PPC32 p539)
cerion2831b002005-11-30 19:55:22 +00003729 IRTemp old_xer_ca = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00003730 DIP("subfe%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003731 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003732 rD_addr, rA_addr, rB_addr);
cerionb85e8bb2005-02-16 08:54:33 +00003733 // rD = (log not)rA + rB + XER[CA]
sewardje9d8a262009-07-01 08:06:34 +00003734 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003735 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3736 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA)),
3737 binop( mkSzOp(ty, Iop_Add8),
3738 mkexpr(rB), mkexpr(old_xer_ca))) );
cerion5b2325f2005-12-23 00:55:09 +00003739 set_XER_CA( ty, PPCG_FLAG_OP_SUBFE,
cerion76de5cf2005-11-18 18:25:12 +00003740 mkexpr(rD), mkexpr(rA), mkexpr(rB),
cerion2831b002005-11-30 19:55:22 +00003741 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003742 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003743 set_XER_OV( ty, PPCG_FLAG_OP_SUBFE,
cerion76de5cf2005-11-18 18:25:12 +00003744 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
cerion70e24122005-03-16 00:27:37 +00003745 }
cerionb85e8bb2005-02-16 08:54:33 +00003746 break;
sewardjb51f0f42005-07-18 11:38:02 +00003747 }
3748
cerion5b2325f2005-12-23 00:55:09 +00003749 case 0x0E8: { // subfme (Subtract from -1 Extended, PPC32 p541)
cerion2831b002005-11-30 19:55:22 +00003750 IRTemp old_xer_ca = newTemp(ty);
3751 IRExpr *min_one;
cerion76de5cf2005-11-18 18:25:12 +00003752 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003753 vex_printf("dis_int_arith(ppc)(subfme,rB_addr)\n");
sewardj20ef5472005-07-21 14:48:31 +00003754 return False;
3755 }
ceriond953ebb2005-11-29 13:27:20 +00003756 DIP("subfme%s%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003757 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003758 rD_addr, rA_addr);
sewardj20ef5472005-07-21 14:48:31 +00003759 // rD = (log not)rA + (-1) + XER[CA]
3760 // => Just another form of subfe
sewardje9d8a262009-07-01 08:06:34 +00003761 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003762 min_one = mkSzImm(ty, (Long)-1);
3763 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3764 unop( mkSzOp(ty, Iop_Not8), mkexpr(rA)),
3765 binop( mkSzOp(ty, Iop_Add8),
3766 min_one, mkexpr(old_xer_ca))) );
cerion5b2325f2005-12-23 00:55:09 +00003767 set_XER_CA( ty, PPCG_FLAG_OP_SUBFE,
ceriond953ebb2005-11-29 13:27:20 +00003768 mkexpr(rD), mkexpr(rA), min_one,
cerion2831b002005-11-30 19:55:22 +00003769 mkexpr(old_xer_ca) );
sewardj20ef5472005-07-21 14:48:31 +00003770 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003771 set_XER_OV( ty, PPCG_FLAG_OP_SUBFE,
ceriond953ebb2005-11-29 13:27:20 +00003772 mkexpr(rD), mkexpr(rA), min_one );
sewardj20ef5472005-07-21 14:48:31 +00003773 }
3774 break;
3775 }
3776
cerion5b2325f2005-12-23 00:55:09 +00003777 case 0x0C8: { // subfze (Subtract from Zero Extended, PPC32 p542)
cerion2831b002005-11-30 19:55:22 +00003778 IRTemp old_xer_ca = newTemp(ty);
cerion76de5cf2005-11-18 18:25:12 +00003779 if (rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003780 vex_printf("dis_int_arith(ppc)(subfze,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003781 return False;
3782 }
ceriond953ebb2005-11-29 13:27:20 +00003783 DIP("subfze%s%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003784 flag_OE ? "o" : "", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00003785 rD_addr, rA_addr);
cerion70e24122005-03-16 00:27:37 +00003786 // rD = (log not)rA + (0) + XER[CA]
3787 // => Just another form of subfe
sewardje9d8a262009-07-01 08:06:34 +00003788 assign( old_xer_ca, mkWidenFrom32(ty, getXER_CA32(), False) );
cerion2831b002005-11-30 19:55:22 +00003789 assign( rD, binop( mkSzOp(ty, Iop_Add8),
3790 unop( mkSzOp(ty, Iop_Not8),
3791 mkexpr(rA)), mkexpr(old_xer_ca)) );
cerion5b2325f2005-12-23 00:55:09 +00003792 set_XER_CA( ty, PPCG_FLAG_OP_SUBFE,
cerion2831b002005-11-30 19:55:22 +00003793 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0),
3794 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00003795 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003796 set_XER_OV( ty, PPCG_FLAG_OP_SUBFE,
cerion2831b002005-11-30 19:55:22 +00003797 mkexpr(rD), mkexpr(rA), mkSzImm(ty, 0) );
cerion70e24122005-03-16 00:27:37 +00003798 }
cerionb85e8bb2005-02-16 08:54:33 +00003799 break;
sewardjb51f0f42005-07-18 11:38:02 +00003800 }
cerionae694622005-01-28 17:52:47 +00003801
cerionf0de28c2005-12-13 20:21:11 +00003802
3803 /* 64bit Arithmetic */
cerion5b2325f2005-12-23 00:55:09 +00003804 case 0x49: // mulhd (Multiply High DWord, PPC64 p539)
cerionf0de28c2005-12-13 20:21:11 +00003805 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003806 vex_printf("dis_int_arith(ppc)(mulhd,flagOE)\n");
cerionf0de28c2005-12-13 20:21:11 +00003807 return False;
3808 }
cerion5b2325f2005-12-23 00:55:09 +00003809 DIP("mulhd%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003810 rD_addr, rA_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00003811 assign( rD, unop(Iop_128HIto64,
cerion07b07a92005-12-22 14:32:35 +00003812 binop(Iop_MullS64,
cerionf0de28c2005-12-13 20:21:11 +00003813 mkexpr(rA), mkexpr(rB))) );
cerion07b07a92005-12-22 14:32:35 +00003814
3815 break;
cerionf0de28c2005-12-13 20:21:11 +00003816
cerion5b2325f2005-12-23 00:55:09 +00003817 case 0x9: // mulhdu (Multiply High DWord Unsigned, PPC64 p540)
cerionf0de28c2005-12-13 20:21:11 +00003818 if (flag_OE != 0) {
cerion5b2325f2005-12-23 00:55:09 +00003819 vex_printf("dis_int_arith(ppc)(mulhdu,flagOE)\n");
cerionf0de28c2005-12-13 20:21:11 +00003820 return False;
3821 }
cerion5b2325f2005-12-23 00:55:09 +00003822 DIP("mulhdu%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003823 rD_addr, rA_addr, rB_addr);
cerion07b07a92005-12-22 14:32:35 +00003824 assign( rD, unop(Iop_128HIto64,
3825 binop(Iop_MullU64,
3826 mkexpr(rA), mkexpr(rB))) );
3827 break;
cerionf0de28c2005-12-13 20:21:11 +00003828
cerion5b2325f2005-12-23 00:55:09 +00003829 case 0xE9: // mulld (Multiply Low DWord, PPC64 p543)
cerionf0de28c2005-12-13 20:21:11 +00003830 DIP("mulld%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003831 flag_OE ? "o" : "", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003832 rD_addr, rA_addr, rB_addr);
3833 assign( rD, binop(Iop_Mul64, mkexpr(rA), mkexpr(rB)) );
3834 if (flag_OE) {
carll38b79ac2013-09-06 22:27:34 +00003835 set_XER_OV( ty, PPCG_FLAG_OP_MULLD,
cerionf0de28c2005-12-13 20:21:11 +00003836 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3837 }
3838 break;
3839
cerion5b2325f2005-12-23 00:55:09 +00003840 case 0x1E9: // divd (Divide DWord, PPC64 p419)
cerionf0de28c2005-12-13 20:21:11 +00003841 DIP("divd%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003842 flag_OE ? "o" : "", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003843 rD_addr, rA_addr, rB_addr);
cerion07b07a92005-12-22 14:32:35 +00003844 assign( rD, binop(Iop_DivS64, mkexpr(rA), mkexpr(rB)) );
3845 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003846 set_XER_OV( ty, PPCG_FLAG_OP_DIVW,
cerion07b07a92005-12-22 14:32:35 +00003847 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3848 }
3849 break;
cerionf0de28c2005-12-13 20:21:11 +00003850 /* Note:
cerion07b07a92005-12-22 14:32:35 +00003851 if (0x8000_0000_0000_0000 / -1) or (x / 0)
cerionf0de28c2005-12-13 20:21:11 +00003852 => rD=undef, if(flag_rC) CR7=undef, if(flag_OE) XER_OV=1
3853 => But _no_ exception raised. */
3854
cerion5b2325f2005-12-23 00:55:09 +00003855 case 0x1C9: // divdu (Divide DWord Unsigned, PPC64 p420)
cerionf0de28c2005-12-13 20:21:11 +00003856 DIP("divdu%s%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00003857 flag_OE ? "o" : "", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00003858 rD_addr, rA_addr, rB_addr);
cerion07b07a92005-12-22 14:32:35 +00003859 assign( rD, binop(Iop_DivU64, mkexpr(rA), mkexpr(rB)) );
3860 if (flag_OE) {
cerion5b2325f2005-12-23 00:55:09 +00003861 set_XER_OV( ty, PPCG_FLAG_OP_DIVWU,
cerion07b07a92005-12-22 14:32:35 +00003862 mkexpr(rD), mkexpr(rA), mkexpr(rB) );
3863 }
3864 break;
cerionf0de28c2005-12-13 20:21:11 +00003865 /* Note: ditto comment divd, for (x / 0) */
3866
sewardj4aa412a2011-07-24 14:13:21 +00003867 case 0x18B: // divweu (Divide Word Extended Unsigned)
3868 {
3869 /*
3870 * If (RA) >= (RB), or if an attempt is made to perform the division
3871 * <anything> / 0
3872 * then the contents of register RD are undefined as are (if Rc=1) the contents of
3873 * the LT, GT, and EQ bits of CR Field 0. In these cases, if OE=1 then OV is set
3874 * to 1.
3875 */
3876 IRTemp res = newTemp(Ity_I32);
3877 IRExpr * dividend, * divisor;
3878 DIP("divweu%s%s r%u,r%u,r%u\n",
3879 flag_OE ? "o" : "", flag_rC ? ".":"",
3880 rD_addr, rA_addr, rB_addr);
3881 if (mode64) {
3882 dividend = unop( Iop_64to32, mkexpr( rA ) );
3883 divisor = unop( Iop_64to32, mkexpr( rB ) );
3884 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
3885 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
3886 } else {
3887 dividend = mkexpr( rA );
3888 divisor = mkexpr( rB );
3889 assign( res, binop( Iop_DivU32E, dividend, divisor ) );
3890 assign( rD, mkexpr( res) );
3891 }
3892
3893 if (flag_OE) {
3894 set_XER_OV_32( PPCG_FLAG_OP_DIVWEU,
3895 mkexpr(res), dividend, divisor );
3896 }
3897 break;
3898 }
3899
sewardje71e56a2011-09-05 12:11:06 +00003900 case 0x1AB: // divwe (Divide Word Extended)
3901 {
3902 /*
3903 * If the quotient cannot be represented in 32 bits, or if an
3904 * attempt is made to perform the division
3905 * <anything> / 0
3906 * then the contents of register RD are undefined as are (if
3907 * Rc=1) the contents of the LT, GT, and EQ bits of CR
3908 * Field 0. In these cases, if OE=1 then OV is set to 1.
3909 */
3910
3911 IRTemp res = newTemp(Ity_I32);
3912 IRExpr * dividend, * divisor;
3913 DIP("divwe%s%s r%u,r%u,r%u\n",
3914 flag_OE ? "o" : "", flag_rC ? ".":"",
3915 rD_addr, rA_addr, rB_addr);
3916 if (mode64) {
3917 dividend = unop( Iop_64to32, mkexpr( rA ) );
3918 divisor = unop( Iop_64to32, mkexpr( rB ) );
3919 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
3920 assign( rD, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( res ) ) );
3921 } else {
3922 dividend = mkexpr( rA );
3923 divisor = mkexpr( rB );
3924 assign( res, binop( Iop_DivS32E, dividend, divisor ) );
3925 assign( rD, mkexpr( res) );
3926 }
3927
3928 if (flag_OE) {
3929 set_XER_OV_32( PPCG_FLAG_OP_DIVWE,
3930 mkexpr(res), dividend, divisor );
3931 }
3932 break;
3933 }
3934
3935
sewardj4aa412a2011-07-24 14:13:21 +00003936 case 0x1A9: // divde (Divide Doubleword Extended)
3937 /*
3938 * If the quotient cannot be represented in 64 bits, or if an
3939 * attempt is made to perform the division
3940 * <anything> / 0
3941 * then the contents of register RD are undefined as are (if
3942 * Rc=1) the contents of the LT, GT, and EQ bits of CR
3943 * Field 0. In these cases, if OE=1 then OV is set to 1.
3944 */
3945 DIP("divde%s%s r%u,r%u,r%u\n",
3946 flag_OE ? "o" : "", flag_rC ? ".":"",
3947 rD_addr, rA_addr, rB_addr);
3948 assign( rD, binop(Iop_DivS64E, mkexpr(rA), mkexpr(rB)) );
3949 if (flag_OE) {
3950 set_XER_OV_64( PPCG_FLAG_OP_DIVDE, mkexpr( rD ),
3951 mkexpr( rA ), mkexpr( rB ) );
3952 }
3953 break;
3954
sewardje71e56a2011-09-05 12:11:06 +00003955 case 0x189: // divdeuo (Divide Doubleword Extended Unsigned)
3956 // Same CR and OV rules as given for divweu above
3957 DIP("divdeu%s%s r%u,r%u,r%u\n",
3958 flag_OE ? "o" : "", flag_rC ? ".":"",
3959 rD_addr, rA_addr, rB_addr);
3960 assign( rD, binop(Iop_DivU64E, mkexpr(rA), mkexpr(rB)) );
3961 if (flag_OE) {
3962 set_XER_OV_64( PPCG_FLAG_OP_DIVDEU, mkexpr( rD ),
3963 mkexpr( rA ), mkexpr( rB ) );
3964 }
3965 break;
3966
cerionb85e8bb2005-02-16 08:54:33 +00003967 default:
cerion5b2325f2005-12-23 00:55:09 +00003968 vex_printf("dis_int_arith(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003969 return False;
3970 }
3971 break;
cerionf0de28c2005-12-13 20:21:11 +00003972
cerionb85e8bb2005-02-16 08:54:33 +00003973 default:
cerion5b2325f2005-12-23 00:55:09 +00003974 vex_printf("dis_int_arith(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00003975 return False;
3976 }
cerion91ad5362005-01-27 23:02:41 +00003977
cerion76de5cf2005-11-18 18:25:12 +00003978 putIReg( rD_addr, mkexpr(rD) );
3979
3980 if (do_rc && flag_rC) {
3981 set_CR0( mkexpr(rD) );
cerionb85e8bb2005-02-16 08:54:33 +00003982 }
3983 return True;
cerion91ad5362005-01-27 23:02:41 +00003984}
3985
3986
3987
cerion3d870a32005-03-18 12:23:33 +00003988/*
3989 Integer Compare Instructions
3990*/
cerion7aa4bbc2005-01-29 09:32:07 +00003991static Bool dis_int_cmp ( UInt theInstr )
3992{
cerion76de5cf2005-11-18 18:25:12 +00003993 /* D-Form, X-Form */
3994 UChar opc1 = ifieldOPC(theInstr);
3995 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
3996 UChar b22 = toUChar( IFIELD( theInstr, 22, 1 ) );
3997 UChar flag_L = toUChar( IFIELD( theInstr, 21, 1 ) );
3998 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00003999 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004000 UChar rB_addr = ifieldRegB(theInstr);
4001 UInt opc2 = ifieldOPClo10(theInstr);
4002 UChar b0 = ifieldBIT0(theInstr);
cerion7aa4bbc2005-01-29 09:32:07 +00004003
cerionbb01b7c2005-12-16 13:40:18 +00004004 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4005 IRExpr *a = getIReg(rA_addr);
4006 IRExpr *b;
cerion76de5cf2005-11-18 18:25:12 +00004007
ceriond953ebb2005-11-29 13:27:20 +00004008 if (!mode64 && flag_L==1) { // L==1 invalid for 32 bit.
cerion5b2325f2005-12-23 00:55:09 +00004009 vex_printf("dis_int_cmp(ppc)(flag_L)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004010 return False;
4011 }
4012
cerion76de5cf2005-11-18 18:25:12 +00004013 if (b22 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00004014 vex_printf("dis_int_cmp(ppc)(b22)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004015 return False;
4016 }
4017
4018 switch (opc1) {
ceriond953ebb2005-11-29 13:27:20 +00004019 case 0x0B: // cmpi (Compare Immediate, PPC32 p368)
4020 DIP("cmpi cr%u,%u,r%u,%d\n", crfD, flag_L, rA_addr,
4021 (Int)extend_s_16to32(uimm16));
cerion2831b002005-11-30 19:55:22 +00004022 b = mkSzExtendS16( ty, uimm16 );
cerionbb01b7c2005-12-16 13:40:18 +00004023 if (flag_L == 1) {
cerion2831b002005-11-30 19:55:22 +00004024 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004025 } else {
sewardje9d8a262009-07-01 08:06:34 +00004026 a = mkNarrowTo32( ty, a );
4027 b = mkNarrowTo32( ty, b );
ceriond953ebb2005-11-29 13:27:20 +00004028 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32S, a, b)));
4029 }
4030 putCR0( crfD, getXER_SO() );
4031 break;
4032
4033 case 0x0A: // cmpli (Compare Logical Immediate, PPC32 p370)
4034 DIP("cmpli cr%u,%u,r%u,0x%x\n", crfD, flag_L, rA_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004035 b = mkSzImm( ty, uimm16 );
cerionbb01b7c2005-12-16 13:40:18 +00004036 if (flag_L == 1) {
cerion2831b002005-11-30 19:55:22 +00004037 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004038 } else {
sewardje9d8a262009-07-01 08:06:34 +00004039 a = mkNarrowTo32( ty, a );
4040 b = mkNarrowTo32( ty, b );
ceriond953ebb2005-11-29 13:27:20 +00004041 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
4042 }
4043 putCR0( crfD, getXER_SO() );
4044 break;
cerionb85e8bb2005-02-16 08:54:33 +00004045
4046 /* X Form */
4047 case 0x1F:
4048 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00004049 vex_printf("dis_int_cmp(ppc)(0x1F,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004050 return False;
4051 }
cerionbb01b7c2005-12-16 13:40:18 +00004052 b = getIReg(rB_addr);
cerion7aa4bbc2005-01-29 09:32:07 +00004053
cerionb85e8bb2005-02-16 08:54:33 +00004054 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00004055 case 0x000: // cmp (Compare, PPC32 p367)
4056 DIP("cmp cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
sewardja9cb67b2006-08-19 18:31:53 +00004057 /* Comparing a reg with itself produces a result which
4058 doesn't depend on the contents of the reg. Therefore
4059 remove the false dependency, which has been known to cause
4060 memcheck to produce false errors. */
sewardj9195aa12006-08-19 22:18:53 +00004061 if (rA_addr == rB_addr)
sewardjdd40fdf2006-12-24 02:20:24 +00004062 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
sewardj9195aa12006-08-19 22:18:53 +00004063 ? mkU64(0) : mkU32(0);
cerionbb01b7c2005-12-16 13:40:18 +00004064 if (flag_L == 1) {
4065 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64S, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004066 } else {
sewardje9d8a262009-07-01 08:06:34 +00004067 a = mkNarrowTo32( ty, a );
4068 b = mkNarrowTo32( ty, b );
cerionbb01b7c2005-12-16 13:40:18 +00004069 putCR321(crfD, unop(Iop_32to8,binop(Iop_CmpORD32S, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004070 }
4071 putCR0( crfD, getXER_SO() );
4072 break;
cerionb85e8bb2005-02-16 08:54:33 +00004073
ceriond953ebb2005-11-29 13:27:20 +00004074 case 0x020: // cmpl (Compare Logical, PPC32 p369)
4075 DIP("cmpl cr%u,%u,r%u,r%u\n", crfD, flag_L, rA_addr, rB_addr);
sewardja9cb67b2006-08-19 18:31:53 +00004076 /* Comparing a reg with itself produces a result which
4077 doesn't depend on the contents of the reg. Therefore
4078 remove the false dependency, which has been known to cause
4079 memcheck to produce false errors. */
sewardj9195aa12006-08-19 22:18:53 +00004080 if (rA_addr == rB_addr)
sewardjdd40fdf2006-12-24 02:20:24 +00004081 a = b = typeOfIRExpr(irsb->tyenv,a) == Ity_I64
sewardj9195aa12006-08-19 22:18:53 +00004082 ? mkU64(0) : mkU32(0);
cerionbb01b7c2005-12-16 13:40:18 +00004083 if (flag_L == 1) {
4084 putCR321(crfD, unop(Iop_64to8, binop(Iop_CmpORD64U, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004085 } else {
sewardje9d8a262009-07-01 08:06:34 +00004086 a = mkNarrowTo32( ty, a );
4087 b = mkNarrowTo32( ty, b );
cerionbb01b7c2005-12-16 13:40:18 +00004088 putCR321(crfD, unop(Iop_32to8, binop(Iop_CmpORD32U, a, b)));
ceriond953ebb2005-11-29 13:27:20 +00004089 }
4090 putCR0( crfD, getXER_SO() );
4091 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004092
ceriond953ebb2005-11-29 13:27:20 +00004093 default:
cerion5b2325f2005-12-23 00:55:09 +00004094 vex_printf("dis_int_cmp(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00004095 return False;
cerionb85e8bb2005-02-16 08:54:33 +00004096 }
4097 break;
ceriond953ebb2005-11-29 13:27:20 +00004098
cerionb85e8bb2005-02-16 08:54:33 +00004099 default:
cerion5b2325f2005-12-23 00:55:09 +00004100 vex_printf("dis_int_cmp(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004101 return False;
4102 }
4103
cerionb85e8bb2005-02-16 08:54:33 +00004104 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00004105}
4106
4107
cerion3d870a32005-03-18 12:23:33 +00004108/*
4109 Integer Logical Instructions
4110*/
cerion7aa4bbc2005-01-29 09:32:07 +00004111static Bool dis_int_logic ( UInt theInstr )
4112{
cerion76de5cf2005-11-18 18:25:12 +00004113 /* D-Form, X-Form */
4114 UChar opc1 = ifieldOPC(theInstr);
4115 UChar rS_addr = ifieldRegDS(theInstr);
4116 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00004117 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004118 UChar rB_addr = ifieldRegB(theInstr);
4119 UInt opc2 = ifieldOPClo10(theInstr);
4120 UChar flag_rC = ifieldBIT0(theInstr);
cerionb85e8bb2005-02-16 08:54:33 +00004121
ceriond953ebb2005-11-29 13:27:20 +00004122 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4123 IRTemp rS = newTemp(ty);
4124 IRTemp rA = newTemp(ty);
4125 IRTemp rB = newTemp(ty);
cerione9d361a2005-03-04 17:35:29 +00004126 IRExpr* irx;
ceriond953ebb2005-11-29 13:27:20 +00004127 Bool do_rc = False;
4128
cerion76de5cf2005-11-18 18:25:12 +00004129 assign( rS, getIReg(rS_addr) );
4130 assign( rB, getIReg(rB_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00004131
4132 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00004133 case 0x1C: // andi. (AND Immediate, PPC32 p358)
ceriond953ebb2005-11-29 13:27:20 +00004134 DIP("andi. r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004135 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
4136 mkSzImm(ty, uimm16)) );
cerion70e24122005-03-16 00:27:37 +00004137 do_rc = True; // Always record to CR
cerion76de5cf2005-11-18 18:25:12 +00004138 flag_rC = 1;
cerionb85e8bb2005-02-16 08:54:33 +00004139 break;
4140
cerione9d361a2005-03-04 17:35:29 +00004141 case 0x1D: // andis. (AND Immediate Shifted, PPC32 p359)
ceriond953ebb2005-11-29 13:27:20 +00004142 DIP("andis r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004143 assign( rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
4144 mkSzImm(ty, uimm16 << 16)) );
cerion70e24122005-03-16 00:27:37 +00004145 do_rc = True; // Always record to CR
cerion76de5cf2005-11-18 18:25:12 +00004146 flag_rC = 1;
cerionb85e8bb2005-02-16 08:54:33 +00004147 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004148
cerione9d361a2005-03-04 17:35:29 +00004149 case 0x18: // ori (OR Immediate, PPC32 p497)
ceriond953ebb2005-11-29 13:27:20 +00004150 DIP("ori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004151 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
4152 mkSzImm(ty, uimm16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004153 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004154
cerione9d361a2005-03-04 17:35:29 +00004155 case 0x19: // oris (OR Immediate Shifted, PPC32 p498)
ceriond953ebb2005-11-29 13:27:20 +00004156 DIP("oris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004157 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
4158 mkSzImm(ty, uimm16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004159 break;
cerionaabdfbf2005-01-29 12:56:15 +00004160
cerione9d361a2005-03-04 17:35:29 +00004161 case 0x1A: // xori (XOR Immediate, PPC32 p550)
ceriond953ebb2005-11-29 13:27:20 +00004162 DIP("xori r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004163 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
4164 mkSzImm(ty, uimm16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004165 break;
cerion38674602005-02-08 02:19:25 +00004166
cerione9d361a2005-03-04 17:35:29 +00004167 case 0x1B: // xoris (XOR Immediate Shifted, PPC32 p551)
ceriond953ebb2005-11-29 13:27:20 +00004168 DIP("xoris r%u,r%u,0x%x\n", rA_addr, rS_addr, uimm16);
cerion2831b002005-11-30 19:55:22 +00004169 assign( rA, binop( mkSzOp(ty, Iop_Xor8), mkexpr(rS),
4170 mkSzImm(ty, uimm16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00004171 break;
cerionaabdfbf2005-01-29 12:56:15 +00004172
cerionb85e8bb2005-02-16 08:54:33 +00004173 /* X Form */
4174 case 0x1F:
sewardj4aa412a2011-07-24 14:13:21 +00004175 do_rc = True; // All below record to CR, except for where we return at case end.
cerion70e24122005-03-16 00:27:37 +00004176
cerionb85e8bb2005-02-16 08:54:33 +00004177 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00004178 case 0x01C: // and (AND, PPC32 p356)
4179 DIP("and%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004180 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004181 assign(rA, binop( mkSzOp(ty, Iop_And8),
ceriond953ebb2005-11-29 13:27:20 +00004182 mkexpr(rS), mkexpr(rB)));
4183 break;
4184
4185 case 0x03C: // andc (AND with Complement, PPC32 p357)
4186 DIP("andc%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004187 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004188 assign(rA, binop( mkSzOp(ty, Iop_And8), mkexpr(rS),
4189 unop( mkSzOp(ty, Iop_Not8),
ceriond953ebb2005-11-29 13:27:20 +00004190 mkexpr(rB))));
4191 break;
4192
4193 case 0x01A: { // cntlzw (Count Leading Zeros Word, PPC32 p371)
4194 IRExpr* lo32;
4195 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004196 vex_printf("dis_int_logic(ppc)(cntlzw,rB_addr)\n");
ceriond953ebb2005-11-29 13:27:20 +00004197 return False;
4198 }
4199 DIP("cntlzw%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004200 flag_rC ? ".":"", rA_addr, rS_addr);
ceriond953ebb2005-11-29 13:27:20 +00004201
4202 // mode64: count in low word only
4203 lo32 = mode64 ? unop(Iop_64to32, mkexpr(rS)) : mkexpr(rS);
4204
4205 // Iop_Clz32 undefined for arg==0, so deal with that case:
4206 irx = binop(Iop_CmpNE32, lo32, mkU32(0));
sewardje9d8a262009-07-01 08:06:34 +00004207 assign(rA, mkWidenFrom32(ty,
florian99dd03e2013-01-29 03:56:06 +00004208 IRExpr_ITE( irx,
4209 unop(Iop_Clz32, lo32),
4210 mkU32(32)),
cerion5b2325f2005-12-23 00:55:09 +00004211 False));
4212
ceriond953ebb2005-11-29 13:27:20 +00004213 // TODO: alternatively: assign(rA, verbose_Clz32(rS));
4214 break;
4215 }
4216
4217 case 0x11C: // eqv (Equivalent, PPC32 p396)
4218 DIP("eqv%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004219 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004220 assign( rA, unop( mkSzOp(ty, Iop_Not8),
4221 binop( mkSzOp(ty, Iop_Xor8),
ceriond953ebb2005-11-29 13:27:20 +00004222 mkexpr(rS), mkexpr(rB))) );
sewardj20ef5472005-07-21 14:48:31 +00004223 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004224
cerione9d361a2005-03-04 17:35:29 +00004225 case 0x3BA: // extsb (Extend Sign Byte, PPC32 p397
cerion76de5cf2005-11-18 18:25:12 +00004226 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004227 vex_printf("dis_int_logic(ppc)(extsb,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004228 return False;
4229 }
ceriond953ebb2005-11-29 13:27:20 +00004230 DIP("extsb%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004231 flag_rC ? ".":"", rA_addr, rS_addr);
ceriond953ebb2005-11-29 13:27:20 +00004232 if (mode64)
4233 assign( rA, unop(Iop_8Sto64, unop(Iop_64to8, mkexpr(rS))) );
4234 else
4235 assign( rA, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rS))) );
cerionb85e8bb2005-02-16 08:54:33 +00004236 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004237
cerione9d361a2005-03-04 17:35:29 +00004238 case 0x39A: // extsh (Extend Sign Half Word, PPC32 p398)
cerion76de5cf2005-11-18 18:25:12 +00004239 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004240 vex_printf("dis_int_logic(ppc)(extsh,rB_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004241 return False;
4242 }
ceriond953ebb2005-11-29 13:27:20 +00004243 DIP("extsh%s r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004244 flag_rC ? ".":"", rA_addr, rS_addr);
ceriond953ebb2005-11-29 13:27:20 +00004245 if (mode64)
cerion5b2325f2005-12-23 00:55:09 +00004246 assign( rA, unop(Iop_16Sto64,
4247 unop(Iop_64to16, mkexpr(rS))) );
ceriond953ebb2005-11-29 13:27:20 +00004248 else
cerion5b2325f2005-12-23 00:55:09 +00004249 assign( rA, unop(Iop_16Sto32,
4250 unop(Iop_32to16, mkexpr(rS))) );
cerionb85e8bb2005-02-16 08:54:33 +00004251 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004252
cerione9d361a2005-03-04 17:35:29 +00004253 case 0x1DC: // nand (NAND, PPC32 p492)
ceriond953ebb2005-11-29 13:27:20 +00004254 DIP("nand%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004255 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004256 assign( rA, unop( mkSzOp(ty, Iop_Not8),
4257 binop( mkSzOp(ty, Iop_And8),
ceriond953ebb2005-11-29 13:27:20 +00004258 mkexpr(rS), mkexpr(rB))) );
cerionb85e8bb2005-02-16 08:54:33 +00004259 break;
4260
cerione9d361a2005-03-04 17:35:29 +00004261 case 0x07C: // nor (NOR, PPC32 p494)
ceriond953ebb2005-11-29 13:27:20 +00004262 DIP("nor%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004263 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004264 assign( rA, unop( mkSzOp(ty, Iop_Not8),
4265 binop( mkSzOp(ty, Iop_Or8),
ceriond953ebb2005-11-29 13:27:20 +00004266 mkexpr(rS), mkexpr(rB))) );
cerionb85e8bb2005-02-16 08:54:33 +00004267 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004268
cerione9d361a2005-03-04 17:35:29 +00004269 case 0x1BC: // or (OR, PPC32 p495)
cerion76de5cf2005-11-18 18:25:12 +00004270 if ((!flag_rC) && rS_addr == rB_addr) {
ceriond953ebb2005-11-29 13:27:20 +00004271 DIP("mr r%u,r%u\n", rA_addr, rS_addr);
cerion76de5cf2005-11-18 18:25:12 +00004272 assign( rA, mkexpr(rS) );
sewardjb51f0f42005-07-18 11:38:02 +00004273 } else {
ceriond953ebb2005-11-29 13:27:20 +00004274 DIP("or%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004275 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004276 assign( rA, binop( mkSzOp(ty, Iop_Or8),
ceriond953ebb2005-11-29 13:27:20 +00004277 mkexpr(rS), mkexpr(rB)) );
sewardjb51f0f42005-07-18 11:38:02 +00004278 }
cerionb85e8bb2005-02-16 08:54:33 +00004279 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004280
cerione9d361a2005-03-04 17:35:29 +00004281 case 0x19C: // orc (OR with Complement, PPC32 p496)
ceriond953ebb2005-11-29 13:27:20 +00004282 DIP("orc%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004283 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004284 assign( rA, binop( mkSzOp(ty, Iop_Or8), mkexpr(rS),
4285 unop(mkSzOp(ty, Iop_Not8), mkexpr(rB))));
cerionb85e8bb2005-02-16 08:54:33 +00004286 break;
4287
cerione9d361a2005-03-04 17:35:29 +00004288 case 0x13C: // xor (XOR, PPC32 p549)
ceriond953ebb2005-11-29 13:27:20 +00004289 DIP("xor%s r%u,r%u,r%u\n",
cerion5b2325f2005-12-23 00:55:09 +00004290 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerion2831b002005-11-30 19:55:22 +00004291 assign( rA, binop( mkSzOp(ty, Iop_Xor8),
ceriond953ebb2005-11-29 13:27:20 +00004292 mkexpr(rS), mkexpr(rB)) );
cerionb85e8bb2005-02-16 08:54:33 +00004293 break;
cerion7aa4bbc2005-01-29 09:32:07 +00004294
cerionf0de28c2005-12-13 20:21:11 +00004295
4296 /* 64bit Integer Logical Instructions */
4297 case 0x3DA: // extsw (Extend Sign Word, PPC64 p430)
4298 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004299 vex_printf("dis_int_logic(ppc)(extsw,rB_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00004300 return False;
4301 }
cerion5b2325f2005-12-23 00:55:09 +00004302 DIP("extsw%s r%u,r%u\n", flag_rC ? ".":"", rA_addr, rS_addr);
cerionf0de28c2005-12-13 20:21:11 +00004303 assign(rA, unop(Iop_32Sto64, unop(Iop_64to32, mkexpr(rS))));
4304 break;
4305
cerion5b2325f2005-12-23 00:55:09 +00004306 case 0x03A: // cntlzd (Count Leading Zeros DWord, PPC64 p401)
cerionf0de28c2005-12-13 20:21:11 +00004307 if (rB_addr!=0) {
cerion5b2325f2005-12-23 00:55:09 +00004308 vex_printf("dis_int_logic(ppc)(cntlzd,rB_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00004309 return False;
4310 }
cerion5b2325f2005-12-23 00:55:09 +00004311 DIP("cntlzd%s r%u,r%u\n",
4312 flag_rC ? ".":"", rA_addr, rS_addr);
cerion07b07a92005-12-22 14:32:35 +00004313 // Iop_Clz64 undefined for arg==0, so deal with that case:
4314 irx = binop(Iop_CmpNE64, mkexpr(rS), mkU64(0));
florian99dd03e2013-01-29 03:56:06 +00004315 assign(rA, IRExpr_ITE( irx,
4316 unop(Iop_Clz64, mkexpr(rS)),
4317 mkU64(64) ));
cerion5b2325f2005-12-23 00:55:09 +00004318 // TODO: alternatively: assign(rA, verbose_Clz64(rS));
cerion07b07a92005-12-22 14:32:35 +00004319 break;
cerionf0de28c2005-12-13 20:21:11 +00004320
sewardj7e846302010-09-03 23:37:02 +00004321 case 0x1FC: // cmpb (Power6: compare bytes)
4322 DIP("cmpb r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
4323
4324 if (mode64)
4325 assign( rA, unop( Iop_V128to64,
4326 binop( Iop_CmpEQ8x16,
4327 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rS) ),
4328 binop( Iop_64HLtoV128, mkU64(0), mkexpr(rB) )
4329 )) );
4330 else
4331 assign( rA, unop( Iop_V128to32,
4332 binop( Iop_CmpEQ8x16,
4333 unop( Iop_32UtoV128, mkexpr(rS) ),
4334 unop( Iop_32UtoV128, mkexpr(rB) )
4335 )) );
4336 break;
4337
4338 case 0x2DF: { // mftgpr (move floating-point to general purpose register)
4339 IRTemp frB = newTemp(Ity_F64);
4340 DIP("mftgpr r%u,fr%u\n", rS_addr, rB_addr);
4341
4342 assign( frB, getFReg(rB_addr)); // always F64
4343 if (mode64)
4344 assign( rA, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
4345 else
4346 assign( rA, unop( Iop_64to32, unop( Iop_ReinterpF64asI64, mkexpr(frB))) );
4347
4348 putIReg( rS_addr, mkexpr(rA));
4349 return True;
4350 }
4351
4352 case 0x25F: { // mffgpr (move floating-point from general purpose register)
4353 IRTemp frA = newTemp(Ity_F64);
4354 DIP("mffgpr fr%u,r%u\n", rS_addr, rB_addr);
4355
4356 if (mode64)
4357 assign( frA, unop( Iop_ReinterpI64asF64, mkexpr(rB)) );
4358 else
4359 assign( frA, unop( Iop_ReinterpI64asF64, unop( Iop_32Uto64, mkexpr(rB))) );
4360
4361 putFReg( rS_addr, mkexpr(frA));
4362 return True;
4363 }
sewardj66d5ef22011-04-15 11:55:00 +00004364 case 0x1FA: // popcntd (population count doubleword
4365 {
4366 DIP("popcntd r%u,r%u\n", rA_addr, rS_addr);
carll7deaf952013-10-15 18:11:20 +00004367 IRTemp result = gen_POPCOUNT(ty, rS, DWORD);
sewardj66d5ef22011-04-15 11:55:00 +00004368 putIReg( rA_addr, mkexpr(result) );
4369 return True;
4370 }
sewardje71e56a2011-09-05 12:11:06 +00004371 case 0x17A: // popcntw (Population Count Words)
4372 {
4373 DIP("popcntw r%u,r%u\n", rA_addr, rS_addr);
4374 if (mode64) {
4375 IRTemp resultHi, resultLo;
4376 IRTemp argLo = newTemp(Ity_I32);
4377 IRTemp argHi = newTemp(Ity_I32);
4378 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
4379 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
carll7deaf952013-10-15 18:11:20 +00004380 resultLo = gen_POPCOUNT(Ity_I32, argLo, WORD);
4381 resultHi = gen_POPCOUNT(Ity_I32, argHi, WORD);
sewardje71e56a2011-09-05 12:11:06 +00004382 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi), mkexpr(resultLo)));
4383 } else {
carll7deaf952013-10-15 18:11:20 +00004384 IRTemp result = gen_POPCOUNT(ty, rS, WORD);
philippe738d9dd2012-07-06 21:56:53 +00004385 putIReg( rA_addr, mkexpr(result) );
4386 }
4387 return True;
4388 }
4389 case 0x7A: // popcntb (Population Count Byte)
4390 {
4391 DIP("popcntb r%u,r%u\n", rA_addr, rS_addr);
4392
4393 if (mode64) {
4394 IRTemp resultHi, resultLo;
4395 IRTemp argLo = newTemp(Ity_I32);
4396 IRTemp argHi = newTemp(Ity_I32);
4397 assign(argLo, unop(Iop_64to32, mkexpr(rS)));
4398 assign(argHi, unop(Iop_64HIto32, mkexpr(rS)));
carll7deaf952013-10-15 18:11:20 +00004399 resultLo = gen_POPCOUNT(Ity_I32, argLo, BYTE);
4400 resultHi = gen_POPCOUNT(Ity_I32, argHi, BYTE);
philippe738d9dd2012-07-06 21:56:53 +00004401 putIReg( rA_addr, binop(Iop_32HLto64, mkexpr(resultHi),
4402 mkexpr(resultLo)));
4403 } else {
carll7deaf952013-10-15 18:11:20 +00004404 IRTemp result = gen_POPCOUNT(ty, rS, BYTE);
sewardje71e56a2011-09-05 12:11:06 +00004405 putIReg( rA_addr, mkexpr(result) );
4406 }
4407 return True;
4408 }
sewardj4aa412a2011-07-24 14:13:21 +00004409 case 0x0FC: // bpermd (Bit Permute Doubleword)
4410 {
4411 /* This is a lot of rigmarole to emulate bpermd like this, as it
4412 * could be done much faster by implementing a call to the native
4413 * instruction. However, where possible I want to avoid using new
4414 * native instructions so that we can use valgrind to emulate those
4415 * instructions on older PPC64 hardware.
4416 */
4417 #define BPERMD_IDX_MASK 0x00000000000000FFULL
4418 #define BPERMD_BIT_MASK 0x8000000000000000ULL
4419 int i;
4420 IRExpr * rS_expr = mkexpr(rS);
4421 IRExpr * res = binop(Iop_And64, mkU64(0), mkU64(0));
4422 DIP("bpermd r%u,r%u,r%u\n", rA_addr, rS_addr, rB_addr);
4423 for (i = 0; i < 8; i++) {
4424 IRTemp idx_tmp = newTemp( Ity_I64 );
4425 IRTemp perm_bit = newTemp( Ity_I64 );
4426 IRTemp idx = newTemp( Ity_I8 );
4427 IRTemp idx_LT64 = newTemp( Ity_I1 );
4428 IRTemp idx_LT64_ity64 = newTemp( Ity_I64 );
4429
4430 assign( idx_tmp,
4431 binop( Iop_And64, mkU64( BPERMD_IDX_MASK ), rS_expr ) );
4432 assign( idx_LT64,
4433 binop( Iop_CmpLT64U, mkexpr( idx_tmp ), mkU64( 64 ) ) );
4434 assign( idx,
4435 binop( Iop_And8,
4436 unop( Iop_1Sto8,
4437 mkexpr(idx_LT64) ),
4438 unop( Iop_64to8, mkexpr( idx_tmp ) ) ) );
4439 /* If idx_LT64 == 0, we must force the perm bit to '0'. Below, we se idx
4440 * to determine which bit of rB to use for the perm bit, and then we shift
4441 * that bit to the MSB position. We AND that with a 64-bit-ized idx_LT64
4442 * to set the final perm bit.
4443 */
4444 assign( idx_LT64_ity64,
4445 unop( Iop_32Uto64, unop( Iop_1Uto32, mkexpr(idx_LT64 ) ) ) );
4446 assign( perm_bit,
4447 binop( Iop_And64,
4448 mkexpr( idx_LT64_ity64 ),
4449 binop( Iop_Shr64,
4450 binop( Iop_And64,
4451 mkU64( BPERMD_BIT_MASK ),
4452 binop( Iop_Shl64,
4453 mkexpr( rB ),
4454 mkexpr( idx ) ) ),
4455 mkU8( 63 ) ) ) );
4456 res = binop( Iop_Or64,
4457 res,
4458 binop( Iop_Shl64,
4459 mkexpr( perm_bit ),
4460 mkU8( i ) ) );
4461 rS_expr = binop( Iop_Shr64, rS_expr, mkU8( 8 ) );
4462 }
4463 putIReg(rA_addr, res);
4464 return True;
4465 }
4466
cerionb85e8bb2005-02-16 08:54:33 +00004467 default:
cerion5b2325f2005-12-23 00:55:09 +00004468 vex_printf("dis_int_logic(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004469 return False;
4470 }
cerionb85e8bb2005-02-16 08:54:33 +00004471 break;
4472
4473 default:
cerion5b2325f2005-12-23 00:55:09 +00004474 vex_printf("dis_int_logic(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004475 return False;
4476 }
cerion70e24122005-03-16 00:27:37 +00004477
cerion76de5cf2005-11-18 18:25:12 +00004478 putIReg( rA_addr, mkexpr(rA) );
4479
4480 if (do_rc && flag_rC) {
4481 set_CR0( mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00004482 }
4483 return True;
cerion645c9302005-01-31 10:09:59 +00004484}
4485
sewardj7e846302010-09-03 23:37:02 +00004486/*
4487 Integer Parity Instructions
4488*/
4489static Bool dis_int_parity ( UInt theInstr )
4490{
4491 /* X-Form */
4492 UChar opc1 = ifieldOPC(theInstr);
4493 UChar rS_addr = ifieldRegDS(theInstr);
4494 UChar rA_addr = ifieldRegA(theInstr);
4495 UChar rB_addr = ifieldRegB(theInstr);
4496 UInt opc2 = ifieldOPClo10(theInstr);
4497 UChar b0 = ifieldBIT0(theInstr);
4498 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4499
4500 IRTemp rS = newTemp(ty);
4501 IRTemp rA = newTemp(ty);
4502 IRTemp iTot1 = newTemp(Ity_I32);
4503 IRTemp iTot2 = newTemp(Ity_I32);
4504 IRTemp iTot3 = newTemp(Ity_I32);
4505 IRTemp iTot4 = newTemp(Ity_I32);
4506 IRTemp iTot5 = newTemp(Ity_I32);
4507 IRTemp iTot6 = newTemp(Ity_I32);
4508 IRTemp iTot7 = newTemp(Ity_I32);
4509 IRTemp iTot8 = newTemp(Ity_I32);
4510 IRTemp rS1 = newTemp(ty);
4511 IRTemp rS2 = newTemp(ty);
4512 IRTemp rS3 = newTemp(ty);
4513 IRTemp rS4 = newTemp(ty);
4514 IRTemp rS5 = newTemp(ty);
4515 IRTemp rS6 = newTemp(ty);
4516 IRTemp rS7 = newTemp(ty);
4517 IRTemp iHi = newTemp(Ity_I32);
4518 IRTemp iLo = newTemp(Ity_I32);
4519 IROp to_bit = (mode64 ? Iop_64to1 : Iop_32to1);
4520 IROp shr_op = (mode64 ? Iop_Shr64 : Iop_Shr32);
4521
4522 if (opc1 != 0x1f || rB_addr || b0) {
4523 vex_printf("dis_int_parity(ppc)(0x1F,opc1:rB|b0)\n");
4524 return False;
4525 }
4526
4527 assign( rS, getIReg(rS_addr) );
4528
4529 switch (opc2) {
4530 case 0xba: // prtyd (Parity Doubleword, ISA 2.05 p320)
4531 DIP("prtyd r%u,r%u\n", rA_addr, rS_addr);
4532 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
4533 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
4534 assign( iTot2, binop(Iop_Add32,
4535 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
4536 mkexpr(iTot1)) );
4537 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
4538 assign( iTot3, binop(Iop_Add32,
4539 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
4540 mkexpr(iTot2)) );
4541 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
4542 assign( iTot4, binop(Iop_Add32,
4543 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
4544 mkexpr(iTot3)) );
4545 if (mode64) {
4546 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
4547 assign( iTot5, binop(Iop_Add32,
4548 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))),
4549 mkexpr(iTot4)) );
4550 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
4551 assign( iTot6, binop(Iop_Add32,
4552 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
4553 mkexpr(iTot5)) );
4554 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
4555 assign( iTot7, binop(Iop_Add32,
4556 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
4557 mkexpr(iTot6)) );
4558 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)) );
4559 assign( iTot8, binop(Iop_Add32,
4560 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
4561 mkexpr(iTot7)) );
4562 assign( rA, unop(Iop_32Uto64,
4563 binop(Iop_And32, mkexpr(iTot8), mkU32(1))) );
4564 } else
4565 assign( rA, mkexpr(iTot4) );
4566
4567 break;
4568 case 0x9a: // prtyw (Parity Word, ISA 2.05 p320)
4569 assign( iTot1, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS))) );
4570 assign( rS1, binop(shr_op, mkexpr(rS), mkU8(8)) );
4571 assign( iTot2, binop(Iop_Add32,
4572 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS1))),
4573 mkexpr(iTot1)) );
4574 assign( rS2, binop(shr_op, mkexpr(rS1), mkU8(8)) );
4575 assign( iTot3, binop(Iop_Add32,
4576 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS2))),
4577 mkexpr(iTot2)) );
4578 assign( rS3, binop(shr_op, mkexpr(rS2), mkU8(8)) );
4579 assign( iTot4, binop(Iop_Add32,
4580 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS3))),
4581 mkexpr(iTot3)) );
4582 assign( iLo, unop(Iop_1Uto32, unop(Iop_32to1, mkexpr(iTot4) )) );
4583
4584 if (mode64) {
4585 assign( rS4, binop(shr_op, mkexpr(rS3), mkU8(8)) );
4586 assign( iTot5, unop(Iop_1Uto32, unop(to_bit, mkexpr(rS4))) );
4587 assign( rS5, binop(shr_op, mkexpr(rS4), mkU8(8)) );
4588 assign( iTot6, binop(Iop_Add32,
4589 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS5))),
4590 mkexpr(iTot5)) );
4591 assign( rS6, binop(shr_op, mkexpr(rS5), mkU8(8)) );
4592 assign( iTot7, binop(Iop_Add32,
4593 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS6))),
4594 mkexpr(iTot6)) );
4595 assign( rS7, binop(shr_op, mkexpr(rS6), mkU8(8)));
4596 assign( iTot8, binop(Iop_Add32,
4597 unop(Iop_1Uto32, unop(to_bit, mkexpr(rS7))),
4598 mkexpr(iTot7)) );
4599 assign( iHi, binop(Iop_And32, mkU32(1), mkexpr(iTot8)) ),
4600 assign( rA, binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo)) );
4601 } else
4602 assign( rA, binop(Iop_Or32, mkU32(0), mkexpr(iLo)) );
4603 break;
4604 default:
4605 vex_printf("dis_int_parity(ppc)(opc2)\n");
4606 return False;
4607 }
4608
4609 putIReg( rA_addr, mkexpr(rA) );
4610
4611 return True;
4612}
cerion645c9302005-01-31 10:09:59 +00004613
4614
cerion3d870a32005-03-18 12:23:33 +00004615/*
4616 Integer Rotate Instructions
4617*/
cerion645c9302005-01-31 10:09:59 +00004618static Bool dis_int_rot ( UInt theInstr )
4619{
cerionf0de28c2005-12-13 20:21:11 +00004620 /* M-Form, MDS-Form */
ceriond953ebb2005-11-29 13:27:20 +00004621 UChar opc1 = ifieldOPC(theInstr);
4622 UChar rS_addr = ifieldRegDS(theInstr);
4623 UChar rA_addr = ifieldRegA(theInstr);
4624 UChar rB_addr = ifieldRegB(theInstr);
4625 UChar sh_imm = rB_addr;
4626 UChar MaskBeg = toUChar( IFIELD( theInstr, 6, 5 ) );
4627 UChar MaskEnd = toUChar( IFIELD( theInstr, 1, 5 ) );
cerionf0de28c2005-12-13 20:21:11 +00004628 UChar msk_imm = toUChar( IFIELD( theInstr, 5, 6 ) );
4629 UChar opc2 = toUChar( IFIELD( theInstr, 2, 3 ) );
4630 UChar b1 = ifieldBIT1(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00004631 UChar flag_rC = ifieldBIT0(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004632
ceriond953ebb2005-11-29 13:27:20 +00004633 IRType ty = mode64 ? Ity_I64 : Ity_I32;
4634 IRTemp rS = newTemp(ty);
4635 IRTemp rA = newTemp(ty);
4636 IRTemp rB = newTemp(ty);
cerionbb01b7c2005-12-16 13:40:18 +00004637 IRTemp rot = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00004638 IRExpr *r;
cerionf0de28c2005-12-13 20:21:11 +00004639 UInt mask32;
4640 ULong mask64;
ceriond953ebb2005-11-29 13:27:20 +00004641
cerion76de5cf2005-11-18 18:25:12 +00004642 assign( rS, getIReg(rS_addr) );
4643 assign( rB, getIReg(rB_addr) );
ceriond953ebb2005-11-29 13:27:20 +00004644
cerionb85e8bb2005-02-16 08:54:33 +00004645 switch (opc1) {
ceriond953ebb2005-11-29 13:27:20 +00004646 case 0x14: {
cerion5b2325f2005-12-23 00:55:09 +00004647 // rlwimi (Rotate Left Word Imm then Mask Insert, PPC32 p500)
4648 DIP("rlwimi%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004649 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
4650 if (mode64) {
4651 // tmp32 = (ROTL(rS_Lo32, Imm)
4652 // rA = ((tmp32 || tmp32) & mask64) | (rA & ~mask64)
cerionf0de28c2005-12-13 20:21:11 +00004653 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
ceriond953ebb2005-11-29 13:27:20 +00004654 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
4655 r = unop(Iop_32Uto64, r);
cerion5b2325f2005-12-23 00:55:09 +00004656 assign( rot, binop(Iop_Or64, r,
4657 binop(Iop_Shl64, r, mkU8(32))) );
ceriond953ebb2005-11-29 13:27:20 +00004658 assign( rA,
4659 binop(Iop_Or64,
cerionbb01b7c2005-12-16 13:40:18 +00004660 binop(Iop_And64, mkexpr(rot), mkU64(mask64)),
cerionf0de28c2005-12-13 20:21:11 +00004661 binop(Iop_And64, getIReg(rA_addr), mkU64(~mask64))) );
sewardj26b33202005-10-07 09:45:16 +00004662 }
4663 else {
ceriond953ebb2005-11-29 13:27:20 +00004664 // rA = (ROTL(rS, Imm) & mask) | (rA & ~mask);
cerionf0de28c2005-12-13 20:21:11 +00004665 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
4666 r = ROTL(mkexpr(rS), mkU8(sh_imm));
ceriond953ebb2005-11-29 13:27:20 +00004667 assign( rA,
4668 binop(Iop_Or32,
cerionf0de28c2005-12-13 20:21:11 +00004669 binop(Iop_And32, mkU32(mask32), r),
4670 binop(Iop_And32, getIReg(rA_addr), mkU32(~mask32))) );
sewardj26b33202005-10-07 09:45:16 +00004671 }
cerionb85e8bb2005-02-16 08:54:33 +00004672 break;
ceriond953ebb2005-11-29 13:27:20 +00004673 }
cerion45b70ff2005-01-31 17:03:25 +00004674
ceriond953ebb2005-11-29 13:27:20 +00004675 case 0x15: {
cerion5b2325f2005-12-23 00:55:09 +00004676 // rlwinm (Rotate Left Word Imm then AND with Mask, PPC32 p501)
ceriond953ebb2005-11-29 13:27:20 +00004677 vassert(MaskBeg < 32);
4678 vassert(MaskEnd < 32);
4679 vassert(sh_imm < 32);
4680
4681 if (mode64) {
sewardjef4433b2006-10-19 03:01:09 +00004682 IRTemp rTmp = newTemp(Ity_I64);
cerionf0de28c2005-12-13 20:21:11 +00004683 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
cerion5b2325f2005-12-23 00:55:09 +00004684 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004685 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
4686 // tmp32 = (ROTL(rS_Lo32, Imm)
4687 // rA = ((tmp32 || tmp32) & mask64)
4688 r = ROTL( unop(Iop_64to32, mkexpr(rS) ), mkU8(sh_imm) );
4689 r = unop(Iop_32Uto64, r);
sewardjef4433b2006-10-19 03:01:09 +00004690 assign( rTmp, r );
4691 r = NULL;
4692 assign( rot, binop(Iop_Or64, mkexpr(rTmp),
4693 binop(Iop_Shl64, mkexpr(rTmp), mkU8(32))) );
cerionbb01b7c2005-12-16 13:40:18 +00004694 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
ceriond953ebb2005-11-29 13:27:20 +00004695 }
4696 else {
4697 if (MaskBeg == 0 && sh_imm+MaskEnd == 31) {
4698 /* Special-case the ,n,0,31-n form as that is just n-bit
cerion5b2325f2005-12-23 00:55:09 +00004699 shift left, PPC32 p501 */
4700 DIP("slwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004701 rA_addr, rS_addr, sh_imm);
4702 assign( rA, binop(Iop_Shl32, mkexpr(rS), mkU8(sh_imm)) );
4703 }
cerion2831b002005-11-30 19:55:22 +00004704 else if (MaskEnd == 31 && sh_imm+MaskBeg == 32) {
4705 /* Special-case the ,32-n,n,31 form as that is just n-bit
cerion5b2325f2005-12-23 00:55:09 +00004706 unsigned shift right, PPC32 p501 */
4707 DIP("srwi%s r%u,r%u,%d\n", flag_rC ? ".":"",
sewardjee4a8592006-10-19 00:15:25 +00004708 rA_addr, rS_addr, MaskBeg);
cerion2831b002005-11-30 19:55:22 +00004709 assign( rA, binop(Iop_Shr32, mkexpr(rS), mkU8(MaskBeg)) );
4710 }
4711 else {
4712 /* General case. */
cerionf0de28c2005-12-13 20:21:11 +00004713 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
cerion5b2325f2005-12-23 00:55:09 +00004714 DIP("rlwinm%s r%u,r%u,%d,%d,%d\n", flag_rC ? ".":"",
cerion2831b002005-11-30 19:55:22 +00004715 rA_addr, rS_addr, sh_imm, MaskBeg, MaskEnd);
4716 // rA = ROTL(rS, Imm) & mask
cerion5b2325f2005-12-23 00:55:09 +00004717 assign( rA, binop(Iop_And32,
4718 ROTL(mkexpr(rS), mkU8(sh_imm)),
cerionf0de28c2005-12-13 20:21:11 +00004719 mkU32(mask32)) );
cerion2831b002005-11-30 19:55:22 +00004720 }
ceriond953ebb2005-11-29 13:27:20 +00004721 }
sewardjc9659532005-07-21 21:33:57 +00004722 break;
ceriond953ebb2005-11-29 13:27:20 +00004723 }
4724
4725 case 0x17: {
4726 // rlwnm (Rotate Left Word then AND with Mask, PPC32 p503
cerion5b2325f2005-12-23 00:55:09 +00004727 DIP("rlwnm%s r%u,r%u,r%u,%d,%d\n", flag_rC ? ".":"",
ceriond953ebb2005-11-29 13:27:20 +00004728 rA_addr, rS_addr, rB_addr, MaskBeg, MaskEnd);
4729 if (mode64) {
cerionf0de28c2005-12-13 20:21:11 +00004730 mask64 = MASK64(31-MaskEnd, 31-MaskBeg);
cerionbb01b7c2005-12-16 13:40:18 +00004731 /* weird insn alert!
4732 tmp32 = (ROTL(rS_Lo32, rB[0-4])
4733 rA = ((tmp32 || tmp32) & mask64)
4734 */
ceriond953ebb2005-11-29 13:27:20 +00004735 // note, ROTL does the masking, so we don't do it here
4736 r = ROTL( unop(Iop_64to32, mkexpr(rS)),
cerionbb01b7c2005-12-16 13:40:18 +00004737 unop(Iop_64to8, mkexpr(rB)) );
ceriond953ebb2005-11-29 13:27:20 +00004738 r = unop(Iop_32Uto64, r);
cerionbb01b7c2005-12-16 13:40:18 +00004739 assign(rot, binop(Iop_Or64, r, binop(Iop_Shl64, r, mkU8(32))));
4740 assign( rA, binop(Iop_And64, mkexpr(rot), mkU64(mask64)) );
ceriond953ebb2005-11-29 13:27:20 +00004741 } else {
cerionf0de28c2005-12-13 20:21:11 +00004742 mask32 = MASK32(31-MaskEnd, 31-MaskBeg);
ceriond953ebb2005-11-29 13:27:20 +00004743 // rA = ROTL(rS, rB[0-4]) & mask
4744 // note, ROTL does the masking, so we don't do it here
4745 assign( rA, binop(Iop_And32,
cerion5b2325f2005-12-23 00:55:09 +00004746 ROTL(mkexpr(rS),
4747 unop(Iop_32to8, mkexpr(rB))),
cerionf0de28c2005-12-13 20:21:11 +00004748 mkU32(mask32)) );
ceriond953ebb2005-11-29 13:27:20 +00004749 }
4750 break;
4751 }
cerion45b70ff2005-01-31 17:03:25 +00004752
cerionf0de28c2005-12-13 20:21:11 +00004753 /* 64bit Integer Rotates */
4754 case 0x1E: {
4755 msk_imm = ((msk_imm & 1) << 5) | (msk_imm >> 1);
4756 sh_imm |= b1 << 5;
4757
4758 vassert( msk_imm < 64 );
4759 vassert( sh_imm < 64 );
4760
4761 switch (opc2) {
cerion07b07a92005-12-22 14:32:35 +00004762 case 0x4: {
4763 /* r = ROTL64( rS, rB_lo6) */
4764 r = ROTL( mkexpr(rS), unop(Iop_64to8, mkexpr(rB)) );
4765
cerion5b2325f2005-12-23 00:55:09 +00004766 if (b1 == 0) { // rldcl (Rotl DWord, Clear Left, PPC64 p555)
4767 DIP("rldcl%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004768 rA_addr, rS_addr, rB_addr, msk_imm);
cerion07b07a92005-12-22 14:32:35 +00004769 // note, ROTL does the masking, so we don't do it here
cerionf0de28c2005-12-13 20:21:11 +00004770 mask64 = MASK64(0, 63-msk_imm);
4771 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4772 break;
cerion5b2325f2005-12-23 00:55:09 +00004773 } else { // rldcr (Rotl DWord, Clear Right, PPC64 p556)
4774 DIP("rldcr%s r%u,r%u,r%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004775 rA_addr, rS_addr, rB_addr, msk_imm);
cerionf0de28c2005-12-13 20:21:11 +00004776 mask64 = MASK64(63-msk_imm, 63);
4777 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4778 break;
4779 }
4780 break;
cerion07b07a92005-12-22 14:32:35 +00004781 }
cerion5b2325f2005-12-23 00:55:09 +00004782 case 0x2: // rldic (Rotl DWord Imm, Clear, PPC64 p557)
4783 DIP("rldic%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004784 rA_addr, rS_addr, sh_imm, msk_imm);
4785 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4786 mask64 = MASK64(sh_imm, 63-msk_imm);
4787 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4788 break;
4789 // later: deal with special case: (msk_imm==0) => SHL(sh_imm)
4790 /*
4791 Hmm... looks like this'll do the job more simply:
4792 r = SHL(rS, sh_imm)
4793 m = ~(1 << (63-msk_imm))
4794 assign(rA, r & m);
4795 */
4796
cerion5b2325f2005-12-23 00:55:09 +00004797 case 0x0: // rldicl (Rotl DWord Imm, Clear Left, PPC64 p558)
sewardjee4a8592006-10-19 00:15:25 +00004798 if (mode64
4799 && sh_imm + msk_imm == 64 && msk_imm >= 1 && msk_imm <= 63) {
4800 /* special-case the ,64-n,n form as that is just
4801 unsigned shift-right by n */
4802 DIP("srdi%s r%u,r%u,%u\n",
4803 flag_rC ? ".":"", rA_addr, rS_addr, msk_imm);
4804 assign( rA, binop(Iop_Shr64, mkexpr(rS), mkU8(msk_imm)) );
4805 } else {
4806 DIP("rldicl%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
4807 rA_addr, rS_addr, sh_imm, msk_imm);
4808 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4809 mask64 = MASK64(0, 63-msk_imm);
4810 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4811 }
cerionf0de28c2005-12-13 20:21:11 +00004812 break;
cerionf0de28c2005-12-13 20:21:11 +00004813
cerion5b2325f2005-12-23 00:55:09 +00004814 case 0x1: // rldicr (Rotl DWord Imm, Clear Right, PPC64 p559)
sewardjee4a8592006-10-19 00:15:25 +00004815 if (mode64
4816 && sh_imm + msk_imm == 63 && sh_imm >= 1 && sh_imm <= 63) {
4817 /* special-case the ,n,63-n form as that is just
4818 shift-left by n */
4819 DIP("sldi%s r%u,r%u,%u\n",
4820 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
4821 assign( rA, binop(Iop_Shl64, mkexpr(rS), mkU8(sh_imm)) );
4822 } else {
4823 DIP("rldicr%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
4824 rA_addr, rS_addr, sh_imm, msk_imm);
4825 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4826 mask64 = MASK64(63-msk_imm, 63);
4827 assign( rA, binop(Iop_And64, r, mkU64(mask64)) );
4828 }
cerionf0de28c2005-12-13 20:21:11 +00004829 break;
cerionf0de28c2005-12-13 20:21:11 +00004830
cerion5b2325f2005-12-23 00:55:09 +00004831 case 0x3: { // rldimi (Rotl DWord Imm, Mask Insert, PPC64 p560)
cerion07b07a92005-12-22 14:32:35 +00004832 IRTemp rA_orig = newTemp(ty);
cerion5b2325f2005-12-23 00:55:09 +00004833 DIP("rldimi%s r%u,r%u,%u,%u\n", flag_rC ? ".":"",
cerionf0de28c2005-12-13 20:21:11 +00004834 rA_addr, rS_addr, sh_imm, msk_imm);
4835 r = ROTL(mkexpr(rS), mkU8(sh_imm));
4836 mask64 = MASK64(sh_imm, 63-msk_imm);
cerion07b07a92005-12-22 14:32:35 +00004837 assign( rA_orig, getIReg(rA_addr) );
cerionf0de28c2005-12-13 20:21:11 +00004838 assign( rA, binop(Iop_Or64,
4839 binop(Iop_And64, mkU64(mask64), r),
cerion5b2325f2005-12-23 00:55:09 +00004840 binop(Iop_And64, mkU64(~mask64),
4841 mkexpr(rA_orig))) );
cerionf0de28c2005-12-13 20:21:11 +00004842 break;
cerion07b07a92005-12-22 14:32:35 +00004843 }
cerionf0de28c2005-12-13 20:21:11 +00004844 default:
cerion5b2325f2005-12-23 00:55:09 +00004845 vex_printf("dis_int_rot(ppc)(opc2)\n");
cerionf0de28c2005-12-13 20:21:11 +00004846 return False;
4847 }
4848 break;
4849 }
4850
cerionb85e8bb2005-02-16 08:54:33 +00004851 default:
cerion5b2325f2005-12-23 00:55:09 +00004852 vex_printf("dis_int_rot(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004853 return False;
4854 }
cerion645c9302005-01-31 10:09:59 +00004855
cerion76de5cf2005-11-18 18:25:12 +00004856 putIReg( rA_addr, mkexpr(rA) );
4857
4858 if (flag_rC) {
4859 set_CR0( mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00004860 }
4861 return True;
cerion645c9302005-01-31 10:09:59 +00004862}
4863
4864
cerion3d870a32005-03-18 12:23:33 +00004865/*
4866 Integer Load Instructions
4867*/
cerion645c9302005-01-31 10:09:59 +00004868static Bool dis_int_load ( UInt theInstr )
4869{
cerionf0de28c2005-12-13 20:21:11 +00004870 /* D-Form, X-Form, DS-Form */
cerion76de5cf2005-11-18 18:25:12 +00004871 UChar opc1 = ifieldOPC(theInstr);
4872 UChar rD_addr = ifieldRegDS(theInstr);
4873 UChar rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00004874 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004875 UChar rB_addr = ifieldRegB(theInstr);
4876 UInt opc2 = ifieldOPClo10(theInstr);
cerionf0de28c2005-12-13 20:21:11 +00004877 UChar b1 = ifieldBIT1(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00004878 UChar b0 = ifieldBIT0(theInstr);
4879
ceriond953ebb2005-11-29 13:27:20 +00004880 Int simm16 = extend_s_16to32(uimm16);
4881 IRType ty = mode64 ? Ity_I64 : Ity_I32;
ceriond953ebb2005-11-29 13:27:20 +00004882 IRTemp EA = newTemp(ty);
4883 IRExpr* val;
cerionedf7fc52005-11-18 20:57:41 +00004884
cerionf0de28c2005-12-13 20:21:11 +00004885 switch (opc1) {
4886 case 0x1F: // register offset
ceriond953ebb2005-11-29 13:27:20 +00004887 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
cerionf0de28c2005-12-13 20:21:11 +00004888 break;
carll78850ae2013-09-10 18:46:40 +00004889 case 0x38: // immediate offset: 64bit: lq: maskoff
4890 // lowest 4 bits of immediate before forming EA
4891 simm16 = simm16 & 0xFFFFFFF0;
4892 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
4893 break;
sewardj6d834222007-03-09 14:24:38 +00004894 case 0x3A: // immediate offset: 64bit: ld/ldu/lwa: mask off
4895 // lowest 2 bits of immediate before forming EA
cerionf0de28c2005-12-13 20:21:11 +00004896 simm16 = simm16 & 0xFFFFFFFC;
carll78850ae2013-09-10 18:46:40 +00004897 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
4898 break;
cerionf0de28c2005-12-13 20:21:11 +00004899 default: // immediate offset
4900 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
4901 break;
ceriond953ebb2005-11-29 13:27:20 +00004902 }
cerione9d361a2005-03-04 17:35:29 +00004903
cerionb85e8bb2005-02-16 08:54:33 +00004904 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00004905 case 0x22: // lbz (Load B & Zero, PPC32 p433)
ceriond953ebb2005-11-29 13:27:20 +00004906 DIP("lbz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004907 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004908 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004909 break;
4910
cerion5b2325f2005-12-23 00:55:09 +00004911 case 0x23: // lbzu (Load B & Zero, Update, PPC32 p434)
cerion76de5cf2005-11-18 18:25:12 +00004912 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004913 vex_printf("dis_int_load(ppc)(lbzu,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004914 return False;
4915 }
ceriond953ebb2005-11-29 13:27:20 +00004916 DIP("lbzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004917 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004918 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004919 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00004920 break;
4921
cerion5b2325f2005-12-23 00:55:09 +00004922 case 0x2A: // lha (Load HW Alg, PPC32 p445)
ceriond953ebb2005-11-29 13:27:20 +00004923 DIP("lha r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004924 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004925 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
cerionb85e8bb2005-02-16 08:54:33 +00004926 break;
cerion645c9302005-01-31 10:09:59 +00004927
cerion5b2325f2005-12-23 00:55:09 +00004928 case 0x2B: // lhau (Load HW Alg, Update, PPC32 p446)
cerion76de5cf2005-11-18 18:25:12 +00004929 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004930 vex_printf("dis_int_load(ppc)(lhau,rA_addr|rD_addr)\n");
cerioncb14e732005-09-09 16:38:19 +00004931 return False;
4932 }
ceriond953ebb2005-11-29 13:27:20 +00004933 DIP("lhau r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004934 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004935 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
ceriond953ebb2005-11-29 13:27:20 +00004936 putIReg( rA_addr, mkexpr(EA) );
cerioncb14e732005-09-09 16:38:19 +00004937 break;
cerionb85e8bb2005-02-16 08:54:33 +00004938
cerione9d361a2005-03-04 17:35:29 +00004939 case 0x28: // lhz (Load HW & Zero, PPC32 p450)
ceriond953ebb2005-11-29 13:27:20 +00004940 DIP("lhz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004941 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004942 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004943 break;
4944
cerion5b2325f2005-12-23 00:55:09 +00004945 case 0x29: // lhzu (Load HW & and Zero, Update, PPC32 p451)
cerion76de5cf2005-11-18 18:25:12 +00004946 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004947 vex_printf("dis_int_load(ppc)(lhzu,rA_addr|rD_addr)\n");
sewardj0e2cc672005-07-29 21:58:51 +00004948 return False;
4949 }
ceriond953ebb2005-11-29 13:27:20 +00004950 DIP("lhzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004951 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004952 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004953 putIReg( rA_addr, mkexpr(EA) );
sewardj0e2cc672005-07-29 21:58:51 +00004954 break;
cerion645c9302005-01-31 10:09:59 +00004955
cerione9d361a2005-03-04 17:35:29 +00004956 case 0x20: // lwz (Load W & Zero, PPC32 p460)
ceriond953ebb2005-11-29 13:27:20 +00004957 DIP("lwz r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004958 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004959 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004960 break;
4961
cerion5b2325f2005-12-23 00:55:09 +00004962 case 0x21: // lwzu (Load W & Zero, Update, PPC32 p461))
cerion76de5cf2005-11-18 18:25:12 +00004963 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004964 vex_printf("dis_int_load(ppc)(lwzu,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004965 return False;
4966 }
ceriond953ebb2005-11-29 13:27:20 +00004967 DIP("lwzu r%u,%d(r%u)\n", rD_addr, (Int)simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004968 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004969 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004970 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00004971 break;
4972
4973 /* X Form */
4974 case 0x1F:
4975 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00004976 vex_printf("dis_int_load(ppc)(Ox1F,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004977 return False;
4978 }
cerion645c9302005-01-31 10:09:59 +00004979
cerionb85e8bb2005-02-16 08:54:33 +00004980 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00004981 case 0x077: // lbzux (Load B & Zero, Update Indexed, PPC32 p435)
ceriond953ebb2005-11-29 13:27:20 +00004982 DIP("lbzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
cerion76de5cf2005-11-18 18:25:12 +00004983 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00004984 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00004985 return False;
4986 }
carll1f5fe1f2014-08-07 23:25:23 +00004987 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004988 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00004989 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00004990 break;
4991
cerion5b2325f2005-12-23 00:55:09 +00004992 case 0x057: // lbzx (Load B & Zero, Indexed, PPC32 p436)
ceriond953ebb2005-11-29 13:27:20 +00004993 DIP("lbzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00004994 val = load(Ity_I8, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00004995 putIReg( rD_addr, mkWidenFrom8(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00004996 break;
4997
cerion5b2325f2005-12-23 00:55:09 +00004998 case 0x177: // lhaux (Load HW Alg, Update Indexed, PPC32 p447)
cerion76de5cf2005-11-18 18:25:12 +00004999 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005000 vex_printf("dis_int_load(ppc)(lhaux,rA_addr|rD_addr)\n");
cerioncb14e732005-09-09 16:38:19 +00005001 return False;
5002 }
ceriond953ebb2005-11-29 13:27:20 +00005003 DIP("lhaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005004 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005005 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
ceriond953ebb2005-11-29 13:27:20 +00005006 putIReg( rA_addr, mkexpr(EA) );
cerioncb14e732005-09-09 16:38:19 +00005007 break;
cerionb85e8bb2005-02-16 08:54:33 +00005008
cerion5b2325f2005-12-23 00:55:09 +00005009 case 0x157: // lhax (Load HW Alg, Indexed, PPC32 p448)
ceriond953ebb2005-11-29 13:27:20 +00005010 DIP("lhax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005011 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005012 putIReg( rD_addr, mkWidenFrom16(ty, val, True) );
cerionb85e8bb2005-02-16 08:54:33 +00005013 break;
5014
cerion5b2325f2005-12-23 00:55:09 +00005015 case 0x137: // lhzux (Load HW & Zero, Update Indexed, PPC32 p452)
cerion76de5cf2005-11-18 18:25:12 +00005016 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005017 vex_printf("dis_int_load(ppc)(lhzux,rA_addr|rD_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005018 return False;
5019 }
ceriond953ebb2005-11-29 13:27:20 +00005020 DIP("lhzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005021 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005022 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00005023 putIReg( rA_addr, mkexpr(EA) );
cerionb85e8bb2005-02-16 08:54:33 +00005024 break;
5025
cerion5b2325f2005-12-23 00:55:09 +00005026 case 0x117: // lhzx (Load HW & Zero, Indexed, PPC32 p453)
ceriond953ebb2005-11-29 13:27:20 +00005027 DIP("lhzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005028 val = load(Ity_I16, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005029 putIReg( rD_addr, mkWidenFrom16(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00005030 break;
cerion44997f22005-01-31 18:45:59 +00005031
cerion5b2325f2005-12-23 00:55:09 +00005032 case 0x037: // lwzux (Load W & Zero, Update Indexed, PPC32 p462)
cerion76de5cf2005-11-18 18:25:12 +00005033 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005034 vex_printf("dis_int_load(ppc)(lwzux,rA_addr|rD_addr)\n");
sewardj7787af42005-08-04 18:32:19 +00005035 return False;
5036 }
ceriond953ebb2005-11-29 13:27:20 +00005037 DIP("lwzux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005038 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005039 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
ceriond953ebb2005-11-29 13:27:20 +00005040 putIReg( rA_addr, mkexpr(EA) );
sewardj7787af42005-08-04 18:32:19 +00005041 break;
cerionb85e8bb2005-02-16 08:54:33 +00005042
cerion5b2325f2005-12-23 00:55:09 +00005043 case 0x017: // lwzx (Load W & Zero, Indexed, PPC32 p463)
ceriond953ebb2005-11-29 13:27:20 +00005044 DIP("lwzx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005045 val = load(Ity_I32, mkexpr(EA));
sewardje9d8a262009-07-01 08:06:34 +00005046 putIReg( rD_addr, mkWidenFrom32(ty, val, False) );
cerionb85e8bb2005-02-16 08:54:33 +00005047 break;
cerion44997f22005-01-31 18:45:59 +00005048
cerionf0de28c2005-12-13 20:21:11 +00005049
5050 /* 64bit Loads */
cerion5b2325f2005-12-23 00:55:09 +00005051 case 0x035: // ldux (Load DWord, Update Indexed, PPC64 p475)
cerionf0de28c2005-12-13 20:21:11 +00005052 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005053 vex_printf("dis_int_load(ppc)(ldux,rA_addr|rD_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005054 return False;
5055 }
5056 DIP("ldux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005057 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005058 putIReg( rA_addr, mkexpr(EA) );
5059 break;
5060
cerion5b2325f2005-12-23 00:55:09 +00005061 case 0x015: // ldx (Load DWord, Indexed, PPC64 p476)
cerionf0de28c2005-12-13 20:21:11 +00005062 DIP("ldx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005063 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005064 break;
5065
cerion5b2325f2005-12-23 00:55:09 +00005066 case 0x175: // lwaux (Load W Alg, Update Indexed, PPC64 p501)
cerionf0de28c2005-12-13 20:21:11 +00005067 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005068 vex_printf("dis_int_load(ppc)(lwaux,rA_addr|rD_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005069 return False;
5070 }
5071 DIP("lwaux r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
cerion5b2325f2005-12-23 00:55:09 +00005072 putIReg( rD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00005073 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
cerionf0de28c2005-12-13 20:21:11 +00005074 putIReg( rA_addr, mkexpr(EA) );
5075 break;
5076
cerion5b2325f2005-12-23 00:55:09 +00005077 case 0x155: // lwax (Load W Alg, Indexed, PPC64 p502)
cerionf0de28c2005-12-13 20:21:11 +00005078 DIP("lwax r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
cerion5b2325f2005-12-23 00:55:09 +00005079 putIReg( rD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00005080 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
cerionf0de28c2005-12-13 20:21:11 +00005081 break;
5082
cerionb85e8bb2005-02-16 08:54:33 +00005083 default:
cerion5b2325f2005-12-23 00:55:09 +00005084 vex_printf("dis_int_load(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005085 return False;
5086 }
5087 break;
cerionf0de28c2005-12-13 20:21:11 +00005088
sewardj6d834222007-03-09 14:24:38 +00005089 /* DS Form - 64bit Loads. In each case EA will have been formed
5090 with the lowest 2 bits masked off the immediate offset. */
cerionf0de28c2005-12-13 20:21:11 +00005091 case 0x3A:
sewardj6d834222007-03-09 14:24:38 +00005092 switch ((b1<<1) | b0) {
cerion5b2325f2005-12-23 00:55:09 +00005093 case 0x0: // ld (Load DWord, PPC64 p472)
cerionf0de28c2005-12-13 20:21:11 +00005094 DIP("ld r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005095 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005096 break;
5097
cerion5b2325f2005-12-23 00:55:09 +00005098 case 0x1: // ldu (Load DWord, Update, PPC64 p474)
cerionf0de28c2005-12-13 20:21:11 +00005099 if (rA_addr == 0 || rA_addr == rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005100 vex_printf("dis_int_load(ppc)(ldu,rA_addr|rD_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005101 return False;
5102 }
5103 DIP("ldu r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005104 putIReg( rD_addr, load(Ity_I64, mkexpr(EA)) );
cerionf0de28c2005-12-13 20:21:11 +00005105 putIReg( rA_addr, mkexpr(EA) );
5106 break;
5107
cerion5b2325f2005-12-23 00:55:09 +00005108 case 0x2: // lwa (Load Word Alg, PPC64 p499)
cerionf0de28c2005-12-13 20:21:11 +00005109 DIP("lwa r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
cerion5b2325f2005-12-23 00:55:09 +00005110 putIReg( rD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00005111 unop(Iop_32Sto64, load(Ity_I32, mkexpr(EA))) );
cerionf0de28c2005-12-13 20:21:11 +00005112 break;
5113
5114 default:
cerion5b2325f2005-12-23 00:55:09 +00005115 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
cerionf0de28c2005-12-13 20:21:11 +00005116 return False;
5117 }
5118 break;
5119
carll78850ae2013-09-10 18:46:40 +00005120 case 0x38: {
5121 IRTemp high = newTemp(ty);
5122 IRTemp low = newTemp(ty);
5123 /* DQ Form - 128bit Loads. Lowest bits [1:0] are the PT field. */
5124 DIP("lq r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
5125 /* NOTE: there are some changes to XER[41:42] that have not been
5126 * implemented.
5127 */
5128 // trap if EA misaligned on 16 byte address
5129 if (mode64) {
carll1f5fe1f2014-08-07 23:25:23 +00005130 assign(high, load(ty, mkexpr( EA ) ) );
5131 assign(low, load(ty, binop( Iop_Add64,
5132 mkexpr( EA ),
5133 mkU64( 8 ) ) ) );
carll78850ae2013-09-10 18:46:40 +00005134 } else {
carll1f5fe1f2014-08-07 23:25:23 +00005135 assign(high, load(ty, binop( Iop_Add32,
5136 mkexpr( EA ),
5137 mkU32( 4 ) ) ) );
5138 assign(low, load(ty, binop( Iop_Add32,
5139 mkexpr( EA ),
5140 mkU32( 12 ) ) ) );
carll78850ae2013-09-10 18:46:40 +00005141 }
5142 gen_SIGBUS_if_misaligned( EA, 16 );
5143 putIReg( rD_addr, mkexpr( high) );
5144 putIReg( rD_addr+1, mkexpr( low) );
5145 break;
5146 }
cerionb85e8bb2005-02-16 08:54:33 +00005147 default:
cerion5b2325f2005-12-23 00:55:09 +00005148 vex_printf("dis_int_load(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005149 return False;
5150 }
5151 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00005152}
5153
5154
5155
cerion3d870a32005-03-18 12:23:33 +00005156/*
5157 Integer Store Instructions
5158*/
sewardjdd40fdf2006-12-24 02:20:24 +00005159static Bool dis_int_store ( UInt theInstr, VexAbiInfo* vbi )
ceriond23be4e2005-01-31 07:23:07 +00005160{
cerionf0de28c2005-12-13 20:21:11 +00005161 /* D-Form, X-Form, DS-Form */
cerionedf7fc52005-11-18 20:57:41 +00005162 UChar opc1 = ifieldOPC(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00005163 UInt rS_addr = ifieldRegDS(theInstr);
5164 UInt rA_addr = ifieldRegA(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00005165 UInt uimm16 = ifieldUIMM16(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00005166 UInt rB_addr = ifieldRegB(theInstr);
5167 UInt opc2 = ifieldOPClo10(theInstr);
cerionf0de28c2005-12-13 20:21:11 +00005168 UChar b1 = ifieldBIT1(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00005169 UChar b0 = ifieldBIT0(theInstr);
5170
ceriond953ebb2005-11-29 13:27:20 +00005171 Int simm16 = extend_s_16to32(uimm16);
5172 IRType ty = mode64 ? Ity_I64 : Ity_I32;
5173 IRTemp rS = newTemp(ty);
5174 IRTemp rB = newTemp(ty);
5175 IRTemp EA = newTemp(ty);
cerionb85e8bb2005-02-16 08:54:33 +00005176
cerion76de5cf2005-11-18 18:25:12 +00005177 assign( rB, getIReg(rB_addr) );
5178 assign( rS, getIReg(rS_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00005179
cerionf0de28c2005-12-13 20:21:11 +00005180 switch (opc1) {
5181 case 0x1F: // register offset
ceriond953ebb2005-11-29 13:27:20 +00005182 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
cerionf0de28c2005-12-13 20:21:11 +00005183 break;
carll78850ae2013-09-10 18:46:40 +00005184 case 0x3E: // immediate offset: 64bit: std/stdu/stq: mask off
sewardj6d834222007-03-09 14:24:38 +00005185 // lowest 2 bits of immediate before forming EA
cerionf0de28c2005-12-13 20:21:11 +00005186 simm16 = simm16 & 0xFFFFFFFC;
5187 default: // immediate offset
5188 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
5189 break;
ceriond953ebb2005-11-29 13:27:20 +00005190 }
5191
cerionb85e8bb2005-02-16 08:54:33 +00005192 switch (opc1) {
sewardjafe85832005-09-09 10:25:39 +00005193 case 0x26: // stb (Store B, PPC32 p509)
cerion76de5cf2005-11-18 18:25:12 +00005194 DIP("stb r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005195 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
sewardjafe85832005-09-09 10:25:39 +00005196 break;
sewardjb51f0f42005-07-18 11:38:02 +00005197
cerion5b2325f2005-12-23 00:55:09 +00005198 case 0x27: // stbu (Store B, Update, PPC32 p510)
cerion76de5cf2005-11-18 18:25:12 +00005199 if (rA_addr == 0 ) {
cerion5b2325f2005-12-23 00:55:09 +00005200 vex_printf("dis_int_store(ppc)(stbu,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005201 return False;
5202 }
cerion76de5cf2005-11-18 18:25:12 +00005203 DIP("stbu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00005204 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005205 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005206 break;
ceriond23be4e2005-01-31 07:23:07 +00005207
cerione9d361a2005-03-04 17:35:29 +00005208 case 0x2C: // sth (Store HW, PPC32 p522)
cerion76de5cf2005-11-18 18:25:12 +00005209 DIP("sth r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005210 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005211 break;
5212
cerion5b2325f2005-12-23 00:55:09 +00005213 case 0x2D: // sthu (Store HW, Update, PPC32 p524)
cerion76de5cf2005-11-18 18:25:12 +00005214 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005215 vex_printf("dis_int_store(ppc)(sthu,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005216 return False;
5217 }
cerion76de5cf2005-11-18 18:25:12 +00005218 DIP("sthu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00005219 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005220 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005221 break;
ceriond23be4e2005-01-31 07:23:07 +00005222
cerione9d361a2005-03-04 17:35:29 +00005223 case 0x24: // stw (Store W, PPC32 p530)
cerion76de5cf2005-11-18 18:25:12 +00005224 DIP("stw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005225 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005226 break;
ceriond23be4e2005-01-31 07:23:07 +00005227
cerion5b2325f2005-12-23 00:55:09 +00005228 case 0x25: // stwu (Store W, Update, PPC32 p534)
cerion76de5cf2005-11-18 18:25:12 +00005229 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005230 vex_printf("dis_int_store(ppc)(stwu,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005231 return False;
5232 }
cerion76de5cf2005-11-18 18:25:12 +00005233 DIP("stwu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
ceriond953ebb2005-11-29 13:27:20 +00005234 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005235 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005236 break;
5237
cerionf0de28c2005-12-13 20:21:11 +00005238 /* X Form : all these use EA_indexed */
cerionb85e8bb2005-02-16 08:54:33 +00005239 case 0x1F:
5240 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00005241 vex_printf("dis_int_store(ppc)(0x1F,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005242 return False;
5243 }
cerion44997f22005-01-31 18:45:59 +00005244
cerionb85e8bb2005-02-16 08:54:33 +00005245 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00005246 case 0x0F7: // stbux (Store B, Update Indexed, PPC32 p511)
cerion76de5cf2005-11-18 18:25:12 +00005247 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005248 vex_printf("dis_int_store(ppc)(stbux,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005249 return False;
5250 }
cerion76de5cf2005-11-18 18:25:12 +00005251 DIP("stbux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00005252 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005253 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005254 break;
5255
cerione9d361a2005-03-04 17:35:29 +00005256 case 0x0D7: // stbx (Store B Indexed, PPC32 p512)
cerion76de5cf2005-11-18 18:25:12 +00005257 DIP("stbx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005258 store( mkexpr(EA), mkNarrowTo8(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005259 break;
5260
cerion5b2325f2005-12-23 00:55:09 +00005261 case 0x1B7: // sthux (Store HW, Update Indexed, PPC32 p525)
cerion76de5cf2005-11-18 18:25:12 +00005262 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005263 vex_printf("dis_int_store(ppc)(sthux,rA_addr)\n");
cerioncb14e732005-09-09 16:38:19 +00005264 return False;
5265 }
cerion76de5cf2005-11-18 18:25:12 +00005266 DIP("sthux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00005267 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005268 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerioncb14e732005-09-09 16:38:19 +00005269 break;
cerionb85e8bb2005-02-16 08:54:33 +00005270
cerione9d361a2005-03-04 17:35:29 +00005271 case 0x197: // sthx (Store HW Indexed, PPC32 p526)
cerion76de5cf2005-11-18 18:25:12 +00005272 DIP("sthx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005273 store( mkexpr(EA), mkNarrowTo16(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005274 break;
5275
cerion5b2325f2005-12-23 00:55:09 +00005276 case 0x0B7: // stwux (Store W, Update Indexed, PPC32 p535)
cerion76de5cf2005-11-18 18:25:12 +00005277 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005278 vex_printf("dis_int_store(ppc)(stwux,rA_addr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005279 return False;
5280 }
cerion76de5cf2005-11-18 18:25:12 +00005281 DIP("stwux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
ceriond953ebb2005-11-29 13:27:20 +00005282 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005283 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005284 break;
cerion44997f22005-01-31 18:45:59 +00005285
cerione9d361a2005-03-04 17:35:29 +00005286 case 0x097: // stwx (Store W Indexed, PPC32 p536)
cerion76de5cf2005-11-18 18:25:12 +00005287 DIP("stwx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005288 store( mkexpr(EA), mkNarrowTo32(ty, mkexpr(rS)) );
cerionb85e8bb2005-02-16 08:54:33 +00005289 break;
5290
cerionf0de28c2005-12-13 20:21:11 +00005291
5292 /* 64bit Stores */
cerion5b2325f2005-12-23 00:55:09 +00005293 case 0x0B5: // stdux (Store DWord, Update Indexed, PPC64 p584)
cerionf0de28c2005-12-13 20:21:11 +00005294 if (rA_addr == 0) {
cerion5b2325f2005-12-23 00:55:09 +00005295 vex_printf("dis_int_store(ppc)(stdux,rA_addr)\n");
cerionf0de28c2005-12-13 20:21:11 +00005296 return False;
5297 }
5298 DIP("stdux r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
5299 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005300 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005301 break;
5302
cerion5b2325f2005-12-23 00:55:09 +00005303 case 0x095: // stdx (Store DWord Indexed, PPC64 p585)
cerionf0de28c2005-12-13 20:21:11 +00005304 DIP("stdx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005305 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005306 break;
5307
cerionb85e8bb2005-02-16 08:54:33 +00005308 default:
cerion5b2325f2005-12-23 00:55:09 +00005309 vex_printf("dis_int_store(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005310 return False;
5311 }
5312 break;
cerionf0de28c2005-12-13 20:21:11 +00005313
sewardj6d834222007-03-09 14:24:38 +00005314 /* DS Form - 64bit Stores. In each case EA will have been formed
5315 with the lowest 2 bits masked off the immediate offset. */
cerionf0de28c2005-12-13 20:21:11 +00005316 case 0x3E:
sewardj6d834222007-03-09 14:24:38 +00005317 switch ((b1<<1) | b0) {
cerion5b2325f2005-12-23 00:55:09 +00005318 case 0x0: // std (Store DWord, PPC64 p580)
carll0c74bb52013-08-12 18:01:40 +00005319 if (!mode64)
5320 return False;
5321
cerionf0de28c2005-12-13 20:21:11 +00005322 DIP("std r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
carll1f5fe1f2014-08-07 23:25:23 +00005323 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005324 break;
5325
cerion5b2325f2005-12-23 00:55:09 +00005326 case 0x1: // stdu (Store DWord, Update, PPC64 p583)
carll0c74bb52013-08-12 18:01:40 +00005327 if (!mode64)
5328 return False;
5329
cerionf0de28c2005-12-13 20:21:11 +00005330 DIP("stdu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
5331 putIReg( rA_addr, mkexpr(EA) );
carll1f5fe1f2014-08-07 23:25:23 +00005332 store( mkexpr(EA), mkexpr(rS) );
cerionf0de28c2005-12-13 20:21:11 +00005333 break;
5334
carll78850ae2013-09-10 18:46:40 +00005335 case 0x2: { // stq (Store QuadWord, Update, PPC64 p583)
5336 IRTemp EA_hi = newTemp(ty);
5337 IRTemp EA_lo = newTemp(ty);
5338 DIP("stq r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
5339
5340 if (mode64) {
5341 /* upper 64-bits */
5342 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
5343
5344 /* lower 64-bits */
5345 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+8 ) );
5346 } else {
5347 /* upper half of upper 64-bits */
5348 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16+4 ) );
5349
5350 /* lower half of upper 64-bits */
5351 assign( EA_lo, ea_rAor0_simm( rA_addr, simm16+12 ) );
5352 }
carll1f5fe1f2014-08-07 23:25:23 +00005353 store( mkexpr(EA_hi), mkexpr(rS) );
carll1f5fe1f2014-08-07 23:25:23 +00005354 store( mkexpr(EA_lo), getIReg( rS_addr+1 ) );
carll78850ae2013-09-10 18:46:40 +00005355 break;
5356 }
cerionf0de28c2005-12-13 20:21:11 +00005357 default:
cerion5b2325f2005-12-23 00:55:09 +00005358 vex_printf("dis_int_load(ppc)(0x3A, opc2)\n");
cerionf0de28c2005-12-13 20:21:11 +00005359 return False;
5360 }
5361 break;
5362
cerionb85e8bb2005-02-16 08:54:33 +00005363 default:
cerion5b2325f2005-12-23 00:55:09 +00005364 vex_printf("dis_int_store(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005365 return False;
5366 }
5367 return True;
ceriond23be4e2005-01-31 07:23:07 +00005368}
5369
5370
5371
sewardj7787af42005-08-04 18:32:19 +00005372/*
5373 Integer Load/Store Multiple Instructions
5374*/
5375static Bool dis_int_ldst_mult ( UInt theInstr )
5376{
5377 /* D-Form */
cerion76de5cf2005-11-18 18:25:12 +00005378 UChar opc1 = ifieldOPC(theInstr);
5379 UChar rD_addr = ifieldRegDS(theInstr);
5380 UChar rS_addr = rD_addr;
5381 UChar rA_addr = ifieldRegA(theInstr);
cerion2831b002005-11-30 19:55:22 +00005382 UInt uimm16 = ifieldUIMM16(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00005383
ceriond953ebb2005-11-29 13:27:20 +00005384 Int simm16 = extend_s_16to32(uimm16);
5385 IRType ty = mode64 ? Ity_I64 : Ity_I32;
carll9fcbb9a2014-01-24 16:42:26 +00005386 IROp mkAdd = mode64 ? Iop_Add64 : Iop_Add32;
ceriond953ebb2005-11-29 13:27:20 +00005387 IRTemp EA = newTemp(ty);
5388 UInt r = 0;
5389 UInt ea_off = 0;
sewardj7787af42005-08-04 18:32:19 +00005390 IRExpr* irx_addr;
cerionedf7fc52005-11-18 20:57:41 +00005391
ceriond953ebb2005-11-29 13:27:20 +00005392 assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
5393
sewardj7787af42005-08-04 18:32:19 +00005394 switch (opc1) {
ceriond953ebb2005-11-29 13:27:20 +00005395 case 0x2E: // lmw (Load Multiple Word, PPC32 p454)
5396 if (rA_addr >= rD_addr) {
cerion5b2325f2005-12-23 00:55:09 +00005397 vex_printf("dis_int_ldst_mult(ppc)(lmw,rA_addr)\n");
sewardj7787af42005-08-04 18:32:19 +00005398 return False;
ceriond953ebb2005-11-29 13:27:20 +00005399 }
5400 DIP("lmw r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
5401 for (r = rD_addr; r <= 31; r++) {
carll9fcbb9a2014-01-24 16:42:26 +00005402 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
carll1f5fe1f2014-08-07 23:25:23 +00005403 putIReg( r, mkWidenFrom32(ty, load(Ity_I32, irx_addr ),
sewardje9d8a262009-07-01 08:06:34 +00005404 False) );
ceriond953ebb2005-11-29 13:27:20 +00005405 ea_off += 4;
5406 }
5407 break;
5408
5409 case 0x2F: // stmw (Store Multiple Word, PPC32 p527)
5410 DIP("stmw r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
5411 for (r = rS_addr; r <= 31; r++) {
carll9fcbb9a2014-01-24 16:42:26 +00005412 irx_addr = binop(mkAdd, mkexpr(EA), mode64 ? mkU64(ea_off) : mkU32(ea_off));
carll1f5fe1f2014-08-07 23:25:23 +00005413 store( irx_addr, mkNarrowTo32(ty, getIReg(r)) );
ceriond953ebb2005-11-29 13:27:20 +00005414 ea_off += 4;
5415 }
5416 break;
5417
5418 default:
cerion5b2325f2005-12-23 00:55:09 +00005419 vex_printf("dis_int_ldst_mult(ppc)(opc1)\n");
ceriond953ebb2005-11-29 13:27:20 +00005420 return False;
sewardj7787af42005-08-04 18:32:19 +00005421 }
5422 return True;
5423}
5424
5425
5426
sewardj87e651f2005-09-09 08:31:18 +00005427/*
5428 Integer Load/Store String Instructions
5429*/
5430static
5431void generate_lsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
5432 IRTemp EA, // EA
5433 Int rD, // first dst register
ceriond953ebb2005-11-29 13:27:20 +00005434 Int maxBytes ) // 32 or 128
sewardj87e651f2005-09-09 08:31:18 +00005435{
5436 Int i, shift = 24;
5437 IRExpr* e_nbytes = mkexpr(tNBytes);
ceriond953ebb2005-11-29 13:27:20 +00005438 IRExpr* e_EA = mkexpr(EA);
5439 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardj87e651f2005-09-09 08:31:18 +00005440
sewardj5876fa12005-09-09 09:35:29 +00005441 vassert(rD >= 0 && rD < 32);
sewardj87e651f2005-09-09 08:31:18 +00005442 rD--; if (rD < 0) rD = 31;
5443
5444 for (i = 0; i < maxBytes; i++) {
sewardj87e651f2005-09-09 08:31:18 +00005445 /* if (nBytes < (i+1)) goto NIA; */
5446 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
5447 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005448 mkSzConst( ty, nextInsnAddr()), OFFB_CIA ));
sewardj87e651f2005-09-09 08:31:18 +00005449 /* when crossing into a new dest register, set it to zero. */
5450 if ((i % 4) == 0) {
5451 rD++; if (rD == 32) rD = 0;
cerion2831b002005-11-30 19:55:22 +00005452 putIReg(rD, mkSzImm(ty, 0));
sewardj87e651f2005-09-09 08:31:18 +00005453 shift = 24;
5454 }
5455 /* rD |= (8Uto32(*(EA+i))) << shift */
5456 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
sewardj2ef8a372006-01-28 17:07:19 +00005457 putIReg(
5458 rD,
sewardje9d8a262009-07-01 08:06:34 +00005459 mkWidenFrom32(
sewardj2ef8a372006-01-28 17:07:19 +00005460 ty,
5461 binop(
5462 Iop_Or32,
sewardje9d8a262009-07-01 08:06:34 +00005463 mkNarrowTo32(ty, getIReg(rD)),
sewardj2ef8a372006-01-28 17:07:19 +00005464 binop(
5465 Iop_Shl32,
5466 unop(
5467 Iop_8Uto32,
carll1f5fe1f2014-08-07 23:25:23 +00005468 load( Ity_I8,
5469 binop( mkSzOp(ty,Iop_Add8),
5470 e_EA, mkSzImm(ty,i)))
sewardj2ef8a372006-01-28 17:07:19 +00005471 ),
5472 mkU8(toUChar(shift))
5473 )
5474 ),
5475 /*Signed*/False
5476 )
5477 );
sewardj87e651f2005-09-09 08:31:18 +00005478 shift -= 8;
5479 }
5480}
5481
sewardj5876fa12005-09-09 09:35:29 +00005482static
5483void generate_stsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
5484 IRTemp EA, // EA
5485 Int rS, // first src register
ceriond953ebb2005-11-29 13:27:20 +00005486 Int maxBytes ) // 32 or 128
sewardj5876fa12005-09-09 09:35:29 +00005487{
5488 Int i, shift = 24;
5489 IRExpr* e_nbytes = mkexpr(tNBytes);
ceriond953ebb2005-11-29 13:27:20 +00005490 IRExpr* e_EA = mkexpr(EA);
5491 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardj5876fa12005-09-09 09:35:29 +00005492
5493 vassert(rS >= 0 && rS < 32);
5494 rS--; if (rS < 0) rS = 31;
5495
5496 for (i = 0; i < maxBytes; i++) {
5497 /* if (nBytes < (i+1)) goto NIA; */
5498 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
5499 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005500 mkSzConst( ty, nextInsnAddr() ), OFFB_CIA ));
sewardj5876fa12005-09-09 09:35:29 +00005501 /* check for crossing into a new src register. */
5502 if ((i % 4) == 0) {
5503 rS++; if (rS == 32) rS = 0;
5504 shift = 24;
5505 }
5506 /* *(EA+i) = 32to8(rS >> shift) */
5507 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
carll1f5fe1f2014-08-07 23:25:23 +00005508 store(
5509 binop( mkSzOp(ty,Iop_Add8), e_EA, mkSzImm(ty,i)),
5510 unop( Iop_32to8,
5511 binop( Iop_Shr32,
5512 mkNarrowTo32( ty, getIReg(rS) ),
5513 mkU8( toUChar(shift) )))
sewardj5876fa12005-09-09 09:35:29 +00005514 );
5515 shift -= 8;
5516 }
5517}
5518
sewardj87e651f2005-09-09 08:31:18 +00005519static Bool dis_int_ldst_str ( UInt theInstr, /*OUT*/Bool* stopHere )
5520{
5521 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00005522 UChar opc1 = ifieldOPC(theInstr);
5523 UChar rD_addr = ifieldRegDS(theInstr);
5524 UChar rS_addr = rD_addr;
5525 UChar rA_addr = ifieldRegA(theInstr);
5526 UChar rB_addr = ifieldRegB(theInstr);
5527 UChar NumBytes = rB_addr;
5528 UInt opc2 = ifieldOPClo10(theInstr);
5529 UChar b0 = ifieldBIT0(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00005530
ceriond953ebb2005-11-29 13:27:20 +00005531 IRType ty = mode64 ? Ity_I64 : Ity_I32;
5532 IRTemp t_EA = newTemp(ty);
sewardj87e651f2005-09-09 08:31:18 +00005533 IRTemp t_nbytes = IRTemp_INVALID;
cerionedf7fc52005-11-18 20:57:41 +00005534
sewardj87e651f2005-09-09 08:31:18 +00005535 *stopHere = False;
cerionedf7fc52005-11-18 20:57:41 +00005536
sewardj87e651f2005-09-09 08:31:18 +00005537 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00005538 vex_printf("dis_int_ldst_str(ppc)(opc1)\n");
sewardj87e651f2005-09-09 08:31:18 +00005539 return False;
5540 }
5541
5542 switch (opc2) {
5543 case 0x255: // lswi (Load String Word Immediate, PPC32 p455)
5544 /* NB: does not reject the case where RA is in the range of
5545 registers to be loaded. It should. */
ceriond953ebb2005-11-29 13:27:20 +00005546 DIP("lswi r%u,r%u,%d\n", rD_addr, rA_addr, NumBytes);
5547 assign( t_EA, ea_rAor0(rA_addr) );
sewardj2ef8a372006-01-28 17:07:19 +00005548 if (NumBytes == 8 && !mode64) {
sewardj87e651f2005-09-09 08:31:18 +00005549 /* Special case hack */
cerion76de5cf2005-11-18 18:25:12 +00005550 /* rD = Mem[EA]; (rD+1)%32 = Mem[EA+4] */
5551 putIReg( rD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00005552 load(Ity_I32, mkexpr(t_EA)) );
cerion76de5cf2005-11-18 18:25:12 +00005553 putIReg( (rD_addr+1) % 32,
carll1f5fe1f2014-08-07 23:25:23 +00005554 load(Ity_I32,
5555 binop(Iop_Add32, mkexpr(t_EA), mkU32(4))) );
sewardj87e651f2005-09-09 08:31:18 +00005556 } else {
5557 t_nbytes = newTemp(Ity_I32);
cerion76de5cf2005-11-18 18:25:12 +00005558 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
ceriond953ebb2005-11-29 13:27:20 +00005559 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
sewardj87e651f2005-09-09 08:31:18 +00005560 *stopHere = True;
5561 }
5562 return True;
5563
5564 case 0x215: // lswx (Load String Word Indexed, PPC32 p456)
5565 /* NB: does not reject the case where RA is in the range of
5566 registers to be loaded. It should. Although considering
5567 that that can only be detected at run time, it's not easy to
5568 do so. */
cerion76de5cf2005-11-18 18:25:12 +00005569 if (rD_addr == rA_addr || rD_addr == rB_addr)
sewardj87e651f2005-09-09 08:31:18 +00005570 return False;
cerion76de5cf2005-11-18 18:25:12 +00005571 if (rD_addr == 0 && rA_addr == 0)
sewardj87e651f2005-09-09 08:31:18 +00005572 return False;
ceriond953ebb2005-11-29 13:27:20 +00005573 DIP("lswx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
sewardj87e651f2005-09-09 08:31:18 +00005574 t_nbytes = newTemp(Ity_I32);
ceriond953ebb2005-11-29 13:27:20 +00005575 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
cerionedf7fc52005-11-18 20:57:41 +00005576 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
ceriond953ebb2005-11-29 13:27:20 +00005577 generate_lsw_sequence( t_nbytes, t_EA, rD_addr, 128 );
sewardj87e651f2005-09-09 08:31:18 +00005578 *stopHere = True;
5579 return True;
5580
sewardj5876fa12005-09-09 09:35:29 +00005581 case 0x2D5: // stswi (Store String Word Immediate, PPC32 p528)
ceriond953ebb2005-11-29 13:27:20 +00005582 DIP("stswi r%u,r%u,%d\n", rS_addr, rA_addr, NumBytes);
5583 assign( t_EA, ea_rAor0(rA_addr) );
sewardj2ef8a372006-01-28 17:07:19 +00005584 if (NumBytes == 8 && !mode64) {
sewardj5876fa12005-09-09 09:35:29 +00005585 /* Special case hack */
cerion76de5cf2005-11-18 18:25:12 +00005586 /* Mem[EA] = rD; Mem[EA+4] = (rD+1)%32 */
carll1f5fe1f2014-08-07 23:25:23 +00005587 store( mkexpr(t_EA),
5588 getIReg(rD_addr) );
5589 store( binop(Iop_Add32, mkexpr(t_EA), mkU32(4)),
5590 getIReg((rD_addr+1) % 32) );
sewardj5876fa12005-09-09 09:35:29 +00005591 } else {
5592 t_nbytes = newTemp(Ity_I32);
cerion76de5cf2005-11-18 18:25:12 +00005593 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
ceriond953ebb2005-11-29 13:27:20 +00005594 generate_stsw_sequence( t_nbytes, t_EA, rD_addr, 32 );
sewardj5876fa12005-09-09 09:35:29 +00005595 *stopHere = True;
5596 }
5597 return True;
5598
sewardj5876fa12005-09-09 09:35:29 +00005599 case 0x295: // stswx (Store String Word Indexed, PPC32 p529)
ceriond953ebb2005-11-29 13:27:20 +00005600 DIP("stswx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardj5876fa12005-09-09 09:35:29 +00005601 t_nbytes = newTemp(Ity_I32);
ceriond953ebb2005-11-29 13:27:20 +00005602 assign( t_EA, ea_rAor0_idxd(rA_addr,rB_addr) );
cerionedf7fc52005-11-18 20:57:41 +00005603 assign( t_nbytes, unop( Iop_8Uto32, getXER_BC() ) );
ceriond953ebb2005-11-29 13:27:20 +00005604 generate_stsw_sequence( t_nbytes, t_EA, rS_addr, 128 );
sewardj5876fa12005-09-09 09:35:29 +00005605 *stopHere = True;
5606 return True;
sewardj87e651f2005-09-09 08:31:18 +00005607
5608 default:
cerion5b2325f2005-12-23 00:55:09 +00005609 vex_printf("dis_int_ldst_str(ppc)(opc2)\n");
sewardj87e651f2005-09-09 08:31:18 +00005610 return False;
5611 }
5612 return True;
5613}
5614
cerion094d1392005-06-20 13:45:57 +00005615
sewardjb51f0f42005-07-18 11:38:02 +00005616/* ------------------------------------------------------------------
5617 Integer Branch Instructions
5618 ------------------------------------------------------------------ */
cerion645c9302005-01-31 10:09:59 +00005619
cerion45552a92005-02-03 18:20:22 +00005620/*
5621 Branch helper function
5622 ok = BO[2] | ((CTR[0] != 0) ^ BO[1])
sewardjb51f0f42005-07-18 11:38:02 +00005623 Returns an I32 which is 0x00000000 if the ctr condition failed
5624 and 0xFFFFFFFF otherwise.
cerion45552a92005-02-03 18:20:22 +00005625*/
sewardjb51f0f42005-07-18 11:38:02 +00005626static IRExpr* /* :: Ity_I32 */ branch_ctr_ok( UInt BO )
cerion45552a92005-02-03 18:20:22 +00005627{
ceriond953ebb2005-11-29 13:27:20 +00005628 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardjb51f0f42005-07-18 11:38:02 +00005629 IRTemp ok = newTemp(Ity_I32);
cerioned623db2005-06-20 12:42:04 +00005630
cerionf0de28c2005-12-13 20:21:11 +00005631 if ((BO >> 2) & 1) { // independent of ctr
sewardjb51f0f42005-07-18 11:38:02 +00005632 assign( ok, mkU32(0xFFFFFFFF) );
cerionb85e8bb2005-02-16 08:54:33 +00005633 } else {
cerionf0de28c2005-12-13 20:21:11 +00005634 if ((BO >> 1) & 1) { // ctr == 0 ?
ceriond953ebb2005-11-29 13:27:20 +00005635 assign( ok, unop( Iop_1Sto32,
cerion4e2c2b32006-01-02 13:35:51 +00005636 binop( mkSzOp(ty, Iop_CmpEQ8),
5637 getGST( PPC_GST_CTR ),
5638 mkSzImm(ty,0))) );
cerionf0de28c2005-12-13 20:21:11 +00005639 } else { // ctr != 0 ?
sewardjb51f0f42005-07-18 11:38:02 +00005640 assign( ok, unop( Iop_1Sto32,
cerion4e2c2b32006-01-02 13:35:51 +00005641 binop( mkSzOp(ty, Iop_CmpNE8),
5642 getGST( PPC_GST_CTR ),
5643 mkSzImm(ty,0))) );
cerionb85e8bb2005-02-16 08:54:33 +00005644 }
5645 }
5646 return mkexpr(ok);
cerion45552a92005-02-03 18:20:22 +00005647}
5648
sewardjb51f0f42005-07-18 11:38:02 +00005649
cerion45552a92005-02-03 18:20:22 +00005650/*
sewardjb51f0f42005-07-18 11:38:02 +00005651 Branch helper function cond_ok = BO[4] | (CR[BI] == BO[3])
5652 Returns an I32 which is either 0 if the condition failed or
5653 some arbitrary nonzero value otherwise. */
5654
5655static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
cerion45552a92005-02-03 18:20:22 +00005656{
sewardjb51f0f42005-07-18 11:38:02 +00005657 Int where;
5658 IRTemp res = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00005659 IRTemp cr_bi = newTemp(Ity_I32);
5660
sewardjb51f0f42005-07-18 11:38:02 +00005661 if ((BO >> 4) & 1) {
5662 assign( res, mkU32(1) );
cerionb85e8bb2005-02-16 08:54:33 +00005663 } else {
sewardjb51f0f42005-07-18 11:38:02 +00005664 // ok = (CR[BI] == BO[3]) Note, the following relies on
5665 // getCRbit_anywhere returning a value which
5666 // is either zero or has exactly 1 bit set.
5667 assign( cr_bi, getCRbit_anywhere( BI, &where ) );
cerione9d361a2005-03-04 17:35:29 +00005668
5669 if ((BO >> 3) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00005670 /* We can use cr_bi as-is. */
5671 assign( res, mkexpr(cr_bi) );
cerione9d361a2005-03-04 17:35:29 +00005672 } else {
sewardjb51f0f42005-07-18 11:38:02 +00005673 /* We have to invert the sense of the information held in
5674 cr_bi. For that we need to know which bit
cerion76de5cf2005-11-18 18:25:12 +00005675 getCRbit_anywhere regards as significant. */
cerion5b2325f2005-12-23 00:55:09 +00005676 assign( res, binop(Iop_Xor32, mkexpr(cr_bi),
5677 mkU32(1<<where)) );
cerionb85e8bb2005-02-16 08:54:33 +00005678 }
5679 }
sewardjb51f0f42005-07-18 11:38:02 +00005680 return mkexpr(res);
cerion45552a92005-02-03 18:20:22 +00005681}
5682
5683
cerion3d870a32005-03-18 12:23:33 +00005684/*
5685 Integer Branch Instructions
5686*/
sewardj9d540e52005-10-08 11:28:16 +00005687static Bool dis_branch ( UInt theInstr,
sewardjdd40fdf2006-12-24 02:20:24 +00005688 VexAbiInfo* vbi,
sewardj9d540e52005-10-08 11:28:16 +00005689 /*OUT*/DisResult* dres,
sewardjc716aea2006-01-17 01:48:46 +00005690 Bool (*resteerOkFn)(void*,Addr64),
5691 void* callback_opaque )
cerion91ad5362005-01-27 23:02:41 +00005692{
ceriond953ebb2005-11-29 13:27:20 +00005693 UChar opc1 = ifieldOPC(theInstr);
5694 UChar BO = ifieldRegDS(theInstr);
5695 UChar BI = ifieldRegA(theInstr);
5696 UInt BD_u16 = ifieldUIMM16(theInstr) & 0xFFFFFFFC; /* mask off */
5697 UChar b11to15 = ifieldRegB(theInstr);
5698 UInt opc2 = ifieldOPClo10(theInstr);
5699 UInt LI_u26 = ifieldUIMM26(theInstr) & 0xFFFFFFFC; /* mask off */
5700 UChar flag_AA = ifieldBIT1(theInstr);
5701 UChar flag_LK = ifieldBIT0(theInstr);
5702
cerion2831b002005-11-30 19:55:22 +00005703 IRType ty = mode64 ? Ity_I64 : Ity_I32;
ceriond953ebb2005-11-29 13:27:20 +00005704 Addr64 tgt = 0;
5705 Int BD = extend_s_16to32(BD_u16);
cerion2831b002005-11-30 19:55:22 +00005706 IRTemp do_branch = newTemp(Ity_I32);
5707 IRTemp ctr_ok = newTemp(Ity_I32);
5708 IRTemp cond_ok = newTemp(Ity_I32);
5709 IRExpr* e_nia = mkSzImm(ty, nextInsnAddr());
5710 IRConst* c_nia = mkSzConst(ty, nextInsnAddr());
sewardjdf07b882005-11-29 18:19:11 +00005711 IRTemp lr_old = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00005712
cerionb85e8bb2005-02-16 08:54:33 +00005713 /* Hack to pass through code that just wants to read the PC */
5714 if (theInstr == 0x429F0005) {
sewardjb51f0f42005-07-18 11:38:02 +00005715 DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
ceriond953ebb2005-11-29 13:27:20 +00005716 putGST( PPC_GST_LR, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005717 return True;
sewardjb51f0f42005-07-18 11:38:02 +00005718 }
sewardj9d540e52005-10-08 11:28:16 +00005719
5720 /* The default what-next. Individual cases can override it. */
5721 dres->whatNext = Dis_StopHere;
sewardj3dee8492012-04-20 00:13:28 +00005722 vassert(dres->jk_StopHere == Ijk_INVALID);
sewardj9d540e52005-10-08 11:28:16 +00005723
cerionb85e8bb2005-02-16 08:54:33 +00005724 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00005725 case 0x12: // b (Branch, PPC32 p360)
cerion4561acb2005-02-21 14:07:48 +00005726 if (flag_AA) {
cerion2831b002005-11-30 19:55:22 +00005727 tgt = mkSzAddr( ty, extend_s_26to64(LI_u26) );
cerion4561acb2005-02-21 14:07:48 +00005728 } else {
cerion2831b002005-11-30 19:55:22 +00005729 tgt = mkSzAddr( ty, guest_CIA_curr_instr +
5730 (Long)extend_s_26to64(LI_u26) );
cerionb85e8bb2005-02-16 08:54:33 +00005731 }
ceriond953ebb2005-11-29 13:27:20 +00005732 if (mode64) {
5733 DIP("b%s%s 0x%llx\n",
5734 flag_LK ? "l" : "", flag_AA ? "a" : "", tgt);
5735 } else {
5736 DIP("b%s%s 0x%x\n",
5737 flag_LK ? "l" : "", flag_AA ? "a" : "", (Addr32)tgt);
sewardj9d540e52005-10-08 11:28:16 +00005738 }
5739
sewardjcf8986c2006-01-18 04:14:52 +00005740 if (flag_LK) {
ceriond953ebb2005-11-29 13:27:20 +00005741 putGST( PPC_GST_LR, e_nia );
sewardjdd40fdf2006-12-24 02:20:24 +00005742 if (vbi->guest_ppc_zap_RZ_at_bl
sewardj478646f2008-05-01 20:13:04 +00005743 && vbi->guest_ppc_zap_RZ_at_bl( (ULong)tgt) ) {
5744 IRTemp t_tgt = newTemp(ty);
5745 assign(t_tgt, mode64 ? mkU64(tgt) : mkU32(tgt) );
5746 make_redzone_AbiHint( vbi, t_tgt,
sewardjaca070a2006-10-17 00:28:22 +00005747 "branch-and-link (unconditional call)" );
sewardj478646f2008-05-01 20:13:04 +00005748 }
sewardjcf8986c2006-01-18 04:14:52 +00005749 }
ceriond953ebb2005-11-29 13:27:20 +00005750
sewardjc716aea2006-01-17 01:48:46 +00005751 if (resteerOkFn( callback_opaque, tgt )) {
sewardj984d9b12010-01-15 10:53:21 +00005752 dres->whatNext = Dis_ResteerU;
ceriond953ebb2005-11-29 13:27:20 +00005753 dres->continueAt = tgt;
sewardj9d540e52005-10-08 11:28:16 +00005754 } else {
sewardj3dee8492012-04-20 00:13:28 +00005755 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring; ;
5756 putGST( PPC_GST_CIA, mkSzImm(ty, tgt) );
sewardj9d540e52005-10-08 11:28:16 +00005757 }
cerionb85e8bb2005-02-16 08:54:33 +00005758 break;
5759
cerione9d361a2005-03-04 17:35:29 +00005760 case 0x10: // bc (Branch Conditional, PPC32 p361)
cerionb85e8bb2005-02-16 08:54:33 +00005761 DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
ceriond953ebb2005-11-29 13:27:20 +00005762 flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, BD);
cerionb85e8bb2005-02-16 08:54:33 +00005763
5764 if (!(BO & 0x4)) {
ceriond953ebb2005-11-29 13:27:20 +00005765 putGST( PPC_GST_CTR,
cerion2831b002005-11-30 19:55:22 +00005766 binop(mkSzOp(ty, Iop_Sub8),
5767 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
cerionb85e8bb2005-02-16 08:54:33 +00005768 }
sewardjb51f0f42005-07-18 11:38:02 +00005769
5770 /* This is a bit subtle. ctr_ok is either all 0s or all 1s.
cerion76de5cf2005-11-18 18:25:12 +00005771 cond_ok is either zero or nonzero, since that's the cheapest
5772 way to compute it. Anding them together gives a value which
5773 is either zero or non zero and so that's what we must test
5774 for in the IRStmt_Exit. */
sewardjb51f0f42005-07-18 11:38:02 +00005775 assign( ctr_ok, branch_ctr_ok( BO ) );
cerionb85e8bb2005-02-16 08:54:33 +00005776 assign( cond_ok, branch_cond_ok( BO, BI ) );
sewardjb51f0f42005-07-18 11:38:02 +00005777 assign( do_branch,
5778 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
5779
cerion4561acb2005-02-21 14:07:48 +00005780 if (flag_AA) {
cerion2831b002005-11-30 19:55:22 +00005781 tgt = mkSzAddr(ty, extend_s_16to64(BD_u16));
cerion4561acb2005-02-21 14:07:48 +00005782 } else {
cerion2831b002005-11-30 19:55:22 +00005783 tgt = mkSzAddr(ty, guest_CIA_curr_instr +
5784 (Long)extend_s_16to64(BD_u16));
cerionb85e8bb2005-02-16 08:54:33 +00005785 }
ceriond953ebb2005-11-29 13:27:20 +00005786 if (flag_LK)
5787 putGST( PPC_GST_LR, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005788
ceriond953ebb2005-11-29 13:27:20 +00005789 stmt( IRStmt_Exit(
5790 binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
5791 flag_LK ? Ijk_Call : Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005792 mkSzConst(ty, tgt), OFFB_CIA ) );
5793
5794 dres->jk_StopHere = Ijk_Boring;
5795 putGST( PPC_GST_CIA, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005796 break;
5797
5798 case 0x13:
sewardj6be67232006-01-24 19:00:05 +00005799 /* For bclr and bcctr, it appears that the lowest two bits of
5800 b11to15 are a branch hint, and so we only need to ensure it's
5801 of the form 000XX. */
5802 if ((b11to15 & ~3) != 0) {
5803 vex_printf("dis_int_branch(ppc)(0x13,b11to15)(%d)\n", (Int)b11to15);
cerionb85e8bb2005-02-16 08:54:33 +00005804 return False;
5805 }
cerion91ad5362005-01-27 23:02:41 +00005806
cerionb85e8bb2005-02-16 08:54:33 +00005807 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00005808 case 0x210: // bcctr (Branch Cond. to Count Register, PPC32 p363)
cerion5b2325f2005-12-23 00:55:09 +00005809 if ((BO & 0x4) == 0) { // "decr and test CTR" option invalid
5810 vex_printf("dis_int_branch(ppc)(bcctr,BO)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005811 return False;
5812 }
ceriona31e8b52005-02-21 16:30:45 +00005813 DIP("bcctr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
cerionb85e8bb2005-02-16 08:54:33 +00005814
5815 assign( cond_ok, branch_cond_ok( BO, BI ) );
ceriond953ebb2005-11-29 13:27:20 +00005816
sewardj478646f2008-05-01 20:13:04 +00005817 /* FIXME: this is confusing. lr_old holds the old value
5818 of ctr, not lr :-) */
cerion2831b002005-11-30 19:55:22 +00005819 assign( lr_old, addr_align( getGST( PPC_GST_CTR ), 4 ));
sewardjdf07b882005-11-29 18:19:11 +00005820
ceriond953ebb2005-11-29 13:27:20 +00005821 if (flag_LK)
5822 putGST( PPC_GST_LR, e_nia );
cerionb85e8bb2005-02-16 08:54:33 +00005823
sewardjb51f0f42005-07-18 11:38:02 +00005824 stmt( IRStmt_Exit(
5825 binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
5826 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005827 c_nia, OFFB_CIA ));
sewardj478646f2008-05-01 20:13:04 +00005828
5829 if (flag_LK && vbi->guest_ppc_zap_RZ_at_bl) {
5830 make_redzone_AbiHint( vbi, lr_old,
5831 "b-ctr-l (indirect call)" );
5832 }
5833
sewardj3dee8492012-04-20 00:13:28 +00005834 dres->jk_StopHere = flag_LK ? Ijk_Call : Ijk_Boring;;
5835 putGST( PPC_GST_CIA, mkexpr(lr_old) );
cerionb85e8bb2005-02-16 08:54:33 +00005836 break;
5837
sewardjcf8986c2006-01-18 04:14:52 +00005838 case 0x010: { // bclr (Branch Cond. to Link Register, PPC32 p365)
5839 Bool vanilla_return = False;
sewardjb51f0f42005-07-18 11:38:02 +00005840 if ((BO & 0x14 /* 1z1zz */) == 0x14 && flag_LK == 0) {
cerion225a0342005-09-12 20:49:09 +00005841 DIP("blr\n");
sewardjcf8986c2006-01-18 04:14:52 +00005842 vanilla_return = True;
sewardjb51f0f42005-07-18 11:38:02 +00005843 } else {
5844 DIP("bclr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
5845 }
cerion91ad5362005-01-27 23:02:41 +00005846
cerionb85e8bb2005-02-16 08:54:33 +00005847 if (!(BO & 0x4)) {
ceriond953ebb2005-11-29 13:27:20 +00005848 putGST( PPC_GST_CTR,
cerion2831b002005-11-30 19:55:22 +00005849 binop(mkSzOp(ty, Iop_Sub8),
5850 getGST( PPC_GST_CTR ), mkSzImm(ty, 1)) );
cerionb85e8bb2005-02-16 08:54:33 +00005851 }
5852
sewardjb51f0f42005-07-18 11:38:02 +00005853 /* See comments above for 'bc' about this */
5854 assign( ctr_ok, branch_ctr_ok( BO ) );
5855 assign( cond_ok, branch_cond_ok( BO, BI ) );
5856 assign( do_branch,
5857 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
cerion2831b002005-11-30 19:55:22 +00005858
sewardjdf07b882005-11-29 18:19:11 +00005859 assign( lr_old, addr_align( getGST( PPC_GST_LR ), 4 ));
5860
ceriond953ebb2005-11-29 13:27:20 +00005861 if (flag_LK)
5862 putGST( PPC_GST_LR, e_nia );
sewardjb51f0f42005-07-18 11:38:02 +00005863
5864 stmt( IRStmt_Exit(
5865 binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
5866 Ijk_Boring,
sewardj3dee8492012-04-20 00:13:28 +00005867 c_nia, OFFB_CIA ));
sewardjb51f0f42005-07-18 11:38:02 +00005868
sewardj478646f2008-05-01 20:13:04 +00005869 if (vanilla_return && vbi->guest_ppc_zap_RZ_at_blr) {
5870 make_redzone_AbiHint( vbi, lr_old,
5871 "branch-to-lr (unconditional return)" );
5872 }
sewardjcf8986c2006-01-18 04:14:52 +00005873
sewardjd37be032005-11-12 12:56:31 +00005874 /* blrl is pretty strange; it's like a return that sets the
5875 return address of its caller to the insn following this
5876 one. Mark it as a return. */
sewardj3dee8492012-04-20 00:13:28 +00005877 dres->jk_StopHere = Ijk_Ret; /* was flag_LK ? Ijk_Call : Ijk_Ret; */
5878 putGST( PPC_GST_CIA, mkexpr(lr_old) );
cerionb85e8bb2005-02-16 08:54:33 +00005879 break;
sewardjcf8986c2006-01-18 04:14:52 +00005880 }
cerionb85e8bb2005-02-16 08:54:33 +00005881 default:
cerion5b2325f2005-12-23 00:55:09 +00005882 vex_printf("dis_int_branch(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005883 return False;
5884 }
5885 break;
cerion2831b002005-11-30 19:55:22 +00005886
cerionb85e8bb2005-02-16 08:54:33 +00005887 default:
cerion5b2325f2005-12-23 00:55:09 +00005888 vex_printf("dis_int_branch(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00005889 return False;
5890 }
cerion2831b002005-11-30 19:55:22 +00005891
cerionb85e8bb2005-02-16 08:54:33 +00005892 return True;
cerion91ad5362005-01-27 23:02:41 +00005893}
5894
5895
5896
cerion3d870a32005-03-18 12:23:33 +00005897/*
5898 Condition Register Logical Instructions
5899*/
cerion3007c7f2005-02-23 23:13:29 +00005900static Bool dis_cond_logic ( UInt theInstr )
5901{
5902 /* XL-Form */
cerion76de5cf2005-11-18 18:25:12 +00005903 UChar opc1 = ifieldOPC(theInstr);
5904 UChar crbD_addr = ifieldRegDS(theInstr);
5905 UChar crfD_addr = toUChar( IFIELD(theInstr, 23, 3) );
5906 UChar crbA_addr = ifieldRegA(theInstr);
5907 UChar crfS_addr = toUChar( IFIELD(theInstr, 18, 3) );
5908 UChar crbB_addr = ifieldRegB(theInstr);
5909 UInt opc2 = ifieldOPClo10(theInstr);
5910 UChar b0 = ifieldBIT0(theInstr);
cerion3007c7f2005-02-23 23:13:29 +00005911
cerionf0de28c2005-12-13 20:21:11 +00005912 IRTemp crbD = newTemp(Ity_I32);
5913 IRTemp crbA = newTemp(Ity_I32);
5914 IRTemp crbB = newTemp(Ity_I32);
cerion3007c7f2005-02-23 23:13:29 +00005915
5916 if (opc1 != 19 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00005917 vex_printf("dis_cond_logic(ppc)(opc1)\n");
cerion3007c7f2005-02-23 23:13:29 +00005918 return False;
5919 }
5920
cerione9d361a2005-03-04 17:35:29 +00005921 if (opc2 == 0) { // mcrf (Move Cond Reg Field, PPC32 p464)
cerion3007c7f2005-02-23 23:13:29 +00005922 if (((crbD_addr & 0x3) != 0) ||
cerion76de5cf2005-11-18 18:25:12 +00005923 ((crbA_addr & 0x3) != 0) || (crbB_addr != 0)) {
cerion5b2325f2005-12-23 00:55:09 +00005924 vex_printf("dis_cond_logic(ppc)(crbD|crbA|crbB != 0)\n");
cerion3007c7f2005-02-23 23:13:29 +00005925 return False;
cerion76de5cf2005-11-18 18:25:12 +00005926 }
ceriond953ebb2005-11-29 13:27:20 +00005927 DIP("mcrf cr%u,cr%u\n", crfD_addr, crfS_addr);
sewardjb51f0f42005-07-18 11:38:02 +00005928 putCR0( crfD_addr, getCR0( crfS_addr) );
5929 putCR321( crfD_addr, getCR321(crfS_addr) );
cerion3007c7f2005-02-23 23:13:29 +00005930 } else {
sewardjb51f0f42005-07-18 11:38:02 +00005931 assign( crbA, getCRbit(crbA_addr) );
ceriona50fde52005-07-01 21:16:10 +00005932 if (crbA_addr == crbB_addr)
sewardjb51f0f42005-07-18 11:38:02 +00005933 crbB = crbA;
ceriona50fde52005-07-01 21:16:10 +00005934 else
sewardjb51f0f42005-07-18 11:38:02 +00005935 assign( crbB, getCRbit(crbB_addr) );
cerion3007c7f2005-02-23 23:13:29 +00005936
5937 switch (opc2) {
sewardj7c2dc712005-09-08 17:33:27 +00005938 case 0x101: // crand (Cond Reg AND, PPC32 p372)
5939 DIP("crand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5940 assign( crbD, binop(Iop_And32, mkexpr(crbA), mkexpr(crbB)) );
5941 break;
sewardj7787af42005-08-04 18:32:19 +00005942 case 0x081: // crandc (Cond Reg AND w. Complement, PPC32 p373)
5943 DIP("crandc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5944 assign( crbD, binop(Iop_And32,
5945 mkexpr(crbA),
5946 unop(Iop_Not32, mkexpr(crbB))) );
5947 break;
sewardje14bb9f2005-07-22 09:39:02 +00005948 case 0x121: // creqv (Cond Reg Equivalent, PPC32 p374)
5949 DIP("creqv crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5950 assign( crbD, unop(Iop_Not32,
5951 binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB))) );
5952 break;
sewardj7c2dc712005-09-08 17:33:27 +00005953 case 0x0E1: // crnand (Cond Reg NAND, PPC32 p375)
5954 DIP("crnand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5955 assign( crbD, unop(Iop_Not32,
5956 binop(Iop_And32, mkexpr(crbA), mkexpr(crbB))) );
5957 break;
cerione9d361a2005-03-04 17:35:29 +00005958 case 0x021: // crnor (Cond Reg NOR, PPC32 p376)
cerion3007c7f2005-02-23 23:13:29 +00005959 DIP("crnor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5960 assign( crbD, unop(Iop_Not32,
5961 binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB))) );
5962 break;
cerione9d361a2005-03-04 17:35:29 +00005963 case 0x1C1: // cror (Cond Reg OR, PPC32 p377)
cerion3007c7f2005-02-23 23:13:29 +00005964 DIP("cror crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5965 assign( crbD, binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB)) );
5966 break;
sewardj7c2dc712005-09-08 17:33:27 +00005967 case 0x1A1: // crorc (Cond Reg OR w. Complement, PPC32 p378)
5968 DIP("crorc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5969 assign( crbD, binop(Iop_Or32,
5970 mkexpr(crbA),
5971 unop(Iop_Not32, mkexpr(crbB))) );
5972 break;
cerione9d361a2005-03-04 17:35:29 +00005973 case 0x0C1: // crxor (Cond Reg XOR, PPC32 p379)
cerion3007c7f2005-02-23 23:13:29 +00005974 DIP("crxor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
5975 assign( crbD, binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB)) );
5976 break;
cerion3007c7f2005-02-23 23:13:29 +00005977 default:
cerion5b2325f2005-12-23 00:55:09 +00005978 vex_printf("dis_cond_logic(ppc)(opc2)\n");
cerion3007c7f2005-02-23 23:13:29 +00005979 return False;
5980 }
5981
sewardjb51f0f42005-07-18 11:38:02 +00005982 putCRbit( crbD_addr, mkexpr(crbD) );
cerion3007c7f2005-02-23 23:13:29 +00005983 }
5984 return True;
5985}
5986
5987
sewardj334870d2006-02-07 16:42:39 +00005988/*
5989 Trap instructions
5990*/
5991
5992/* Do the code generation for a trap. Returned Bool is true iff
sewardj59c0d8f2007-08-28 14:48:35 +00005993 this is an unconditional trap. If the two arg IRExpr*s are
5994 Ity_I32s then the comparison is 32-bit. If they are Ity_I64s
5995 then they are 64-bit, and we must be disassembling 64-bit
5996 instructions. */
5997static Bool do_trap ( UChar TO,
5998 IRExpr* argL0, IRExpr* argR0, Addr64 cia )
sewardj334870d2006-02-07 16:42:39 +00005999{
6000 IRTemp argL, argR;
6001 IRExpr *argLe, *argRe, *cond, *tmp;
6002
sewardj59c0d8f2007-08-28 14:48:35 +00006003 Bool is32bit = typeOfIRExpr(irsb->tyenv, argL0 ) == Ity_I32;
6004
6005 IROp opAND = is32bit ? Iop_And32 : Iop_And64;
6006 IROp opOR = is32bit ? Iop_Or32 : Iop_Or64;
6007 IROp opCMPORDS = is32bit ? Iop_CmpORD32S : Iop_CmpORD64S;
6008 IROp opCMPORDU = is32bit ? Iop_CmpORD32U : Iop_CmpORD64U;
6009 IROp opCMPNE = is32bit ? Iop_CmpNE32 : Iop_CmpNE64;
6010 IROp opCMPEQ = is32bit ? Iop_CmpEQ32 : Iop_CmpEQ64;
6011 IRExpr* const0 = is32bit ? mkU32(0) : mkU64(0);
6012 IRExpr* const2 = is32bit ? mkU32(2) : mkU64(2);
6013 IRExpr* const4 = is32bit ? mkU32(4) : mkU64(4);
6014 IRExpr* const8 = is32bit ? mkU32(8) : mkU64(8);
sewardj334870d2006-02-07 16:42:39 +00006015
6016 const UChar b11100 = 0x1C;
6017 const UChar b00111 = 0x07;
6018
sewardj59c0d8f2007-08-28 14:48:35 +00006019 if (is32bit) {
6020 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I32 );
6021 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I32 );
6022 } else {
6023 vassert( typeOfIRExpr(irsb->tyenv, argL0) == Ity_I64 );
6024 vassert( typeOfIRExpr(irsb->tyenv, argR0) == Ity_I64 );
6025 vassert( mode64 );
6026 }
6027
sewardj334870d2006-02-07 16:42:39 +00006028 if ((TO & b11100) == b11100 || (TO & b00111) == b00111) {
6029 /* Unconditional trap. Just do the exit without
6030 testing the arguments. */
6031 stmt( IRStmt_Exit(
6032 binop(opCMPEQ, const0, const0),
sewardj0f500042007-08-29 09:09:17 +00006033 Ijk_SigTRAP,
sewardj3dee8492012-04-20 00:13:28 +00006034 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
6035 OFFB_CIA
sewardj334870d2006-02-07 16:42:39 +00006036 ));
6037 return True; /* unconditional trap */
6038 }
6039
sewardj59c0d8f2007-08-28 14:48:35 +00006040 if (is32bit) {
sewardj2d19fe32006-02-07 20:55:08 +00006041 argL = newTemp(Ity_I32);
6042 argR = newTemp(Ity_I32);
sewardj334870d2006-02-07 16:42:39 +00006043 } else {
sewardj2d19fe32006-02-07 20:55:08 +00006044 argL = newTemp(Ity_I64);
6045 argR = newTemp(Ity_I64);
sewardj334870d2006-02-07 16:42:39 +00006046 }
sewardj59c0d8f2007-08-28 14:48:35 +00006047
6048 assign( argL, argL0 );
6049 assign( argR, argR0 );
6050
sewardj334870d2006-02-07 16:42:39 +00006051 argLe = mkexpr(argL);
6052 argRe = mkexpr(argR);
sewardj59c0d8f2007-08-28 14:48:35 +00006053
sewardj334870d2006-02-07 16:42:39 +00006054 cond = const0;
6055 if (TO & 16) { // L <s R
6056 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const8);
6057 cond = binop(opOR, tmp, cond);
6058 }
6059 if (TO & 8) { // L >s R
6060 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const4);
6061 cond = binop(opOR, tmp, cond);
6062 }
6063 if (TO & 4) { // L == R
6064 tmp = binop(opAND, binop(opCMPORDS, argLe, argRe), const2);
6065 cond = binop(opOR, tmp, cond);
6066 }
6067 if (TO & 2) { // L <u R
6068 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const8);
6069 cond = binop(opOR, tmp, cond);
6070 }
6071 if (TO & 1) { // L >u R
6072 tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const4);
6073 cond = binop(opOR, tmp, cond);
6074 }
6075 stmt( IRStmt_Exit(
6076 binop(opCMPNE, cond, const0),
sewardj0f500042007-08-29 09:09:17 +00006077 Ijk_SigTRAP,
sewardj3dee8492012-04-20 00:13:28 +00006078 mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia),
6079 OFFB_CIA
sewardj334870d2006-02-07 16:42:39 +00006080 ));
6081 return False; /* not an unconditional trap */
6082}
6083
6084static Bool dis_trapi ( UInt theInstr,
6085 /*OUT*/DisResult* dres )
6086{
6087 /* D-Form */
6088 UChar opc1 = ifieldOPC(theInstr);
6089 UChar TO = ifieldRegDS(theInstr);
6090 UChar rA_addr = ifieldRegA(theInstr);
6091 UInt uimm16 = ifieldUIMM16(theInstr);
6092 ULong simm16 = extend_s_16to64(uimm16);
6093 Addr64 cia = guest_CIA_curr_instr;
6094 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6095 Bool uncond = False;
6096
6097 switch (opc1) {
6098 case 0x03: // twi (Trap Word Immediate, PPC32 p548)
sewardj59c0d8f2007-08-28 14:48:35 +00006099 uncond = do_trap( TO,
6100 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
6101 : getIReg(rA_addr),
sewardjb4f6d6b2007-08-28 16:39:52 +00006102 mkU32( (UInt)simm16 ),
sewardj59c0d8f2007-08-28 14:48:35 +00006103 cia );
sewardj334870d2006-02-07 16:42:39 +00006104 if (TO == 4) {
6105 DIP("tweqi r%u,%d\n", (UInt)rA_addr, (Int)simm16);
6106 } else {
6107 DIP("tw%di r%u,%d\n", (Int)TO, (UInt)rA_addr, (Int)simm16);
6108 }
6109 break;
6110 case 0x02: // tdi
6111 if (!mode64)
6112 return False;
sewardj59c0d8f2007-08-28 14:48:35 +00006113 uncond = do_trap( TO, getIReg(rA_addr), mkU64( (ULong)simm16 ), cia );
sewardj2d19fe32006-02-07 20:55:08 +00006114 if (TO == 4) {
6115 DIP("tdeqi r%u,%d\n", (UInt)rA_addr, (Int)simm16);
6116 } else {
6117 DIP("td%di r%u,%d\n", (Int)TO, (UInt)rA_addr, (Int)simm16);
6118 }
sewardj334870d2006-02-07 16:42:39 +00006119 break;
6120 default:
6121 return False;
6122 }
6123
6124 if (uncond) {
6125 /* If the trap shows signs of being unconditional, don't
6126 continue decoding past it. */
sewardj3dee8492012-04-20 00:13:28 +00006127 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
6128 dres->jk_StopHere = Ijk_Boring;
6129 dres->whatNext = Dis_StopHere;
sewardj334870d2006-02-07 16:42:39 +00006130 }
6131
6132 return True;
6133}
6134
sewardj59c0d8f2007-08-28 14:48:35 +00006135static Bool dis_trap ( UInt theInstr,
6136 /*OUT*/DisResult* dres )
6137{
6138 /* X-Form */
6139 UInt opc2 = ifieldOPClo10(theInstr);
6140 UChar TO = ifieldRegDS(theInstr);
6141 UChar rA_addr = ifieldRegA(theInstr);
6142 UChar rB_addr = ifieldRegB(theInstr);
6143 Addr64 cia = guest_CIA_curr_instr;
6144 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6145 Bool uncond = False;
6146
6147 if (ifieldBIT0(theInstr) != 0)
6148 return False;
6149
6150 switch (opc2) {
6151 case 0x004: // tw (Trap Word, PPC64 p540)
6152 uncond = do_trap( TO,
6153 mode64 ? unop(Iop_64to32, getIReg(rA_addr))
6154 : getIReg(rA_addr),
6155 mode64 ? unop(Iop_64to32, getIReg(rB_addr))
6156 : getIReg(rB_addr),
6157 cia );
6158 if (TO == 4) {
6159 DIP("tweq r%u,r%u\n", (UInt)rA_addr, (UInt)rB_addr);
6160 } else {
6161 DIP("tw%d r%u,r%u\n", (Int)TO, (UInt)rA_addr, (UInt)rB_addr);
6162 }
6163 break;
sewardjb4f6d6b2007-08-28 16:39:52 +00006164 case 0x044: // td (Trap Doubleword, PPC64 p534)
6165 if (!mode64)
6166 return False;
6167 uncond = do_trap( TO, getIReg(rA_addr), getIReg(rB_addr), cia );
6168 if (TO == 4) {
6169 DIP("tdeq r%u,r%u\n", (UInt)rA_addr, (UInt)rB_addr);
6170 } else {
6171 DIP("td%d r%u,r%u\n", (Int)TO, (UInt)rA_addr, (UInt)rB_addr);
6172 }
6173 break;
sewardj59c0d8f2007-08-28 14:48:35 +00006174 default:
6175 return False;
6176 }
6177
6178 if (uncond) {
6179 /* If the trap shows signs of being unconditional, don't
6180 continue decoding past it. */
sewardj3dee8492012-04-20 00:13:28 +00006181 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
6182 dres->jk_StopHere = Ijk_Boring;
6183 dres->whatNext = Dis_StopHere;
sewardj59c0d8f2007-08-28 14:48:35 +00006184 }
6185
6186 return True;
6187}
6188
sewardj334870d2006-02-07 16:42:39 +00006189
cerion3d870a32005-03-18 12:23:33 +00006190/*
6191 System Linkage Instructions
6192*/
sewardjaca070a2006-10-17 00:28:22 +00006193static Bool dis_syslink ( UInt theInstr,
sewardjdd40fdf2006-12-24 02:20:24 +00006194 VexAbiInfo* abiinfo, DisResult* dres )
cerion8c3adda2005-01-31 11:54:05 +00006195{
ceriond953ebb2005-11-29 13:27:20 +00006196 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6197
cerionb85e8bb2005-02-16 08:54:33 +00006198 if (theInstr != 0x44000002) {
cerion5b2325f2005-12-23 00:55:09 +00006199 vex_printf("dis_syslink(ppc)(theInstr)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006200 return False;
6201 }
cerione1d857b2005-02-04 18:29:05 +00006202
cerione9d361a2005-03-04 17:35:29 +00006203 // sc (System Call, PPC32 p504)
cerionb85e8bb2005-02-16 08:54:33 +00006204 DIP("sc\n");
sewardjaca070a2006-10-17 00:28:22 +00006205
sewardje86310f2009-03-19 22:21:40 +00006206 /* Copy CIA into the IP_AT_SYSCALL pseudo-register, so that on AIX
sewardjaca070a2006-10-17 00:28:22 +00006207 Valgrind can back the guest up to this instruction if it needs
6208 to restart the syscall. */
sewardje86310f2009-03-19 22:21:40 +00006209 putGST( PPC_GST_IP_AT_SYSCALL, getGST( PPC_GST_CIA ) );
sewardjaca070a2006-10-17 00:28:22 +00006210
cerionb85e8bb2005-02-16 08:54:33 +00006211 /* It's important that all ArchRegs carry their up-to-date value
6212 at this point. So we declare an end-of-block here, which
6213 forces any TempRegs caching ArchRegs to be flushed. */
sewardjd1526f22014-07-16 23:14:33 +00006214 putGST( PPC_GST_CIA, mkSzImm( ty, nextInsnAddr() ));
ceriond953ebb2005-11-29 13:27:20 +00006215
sewardj3dee8492012-04-20 00:13:28 +00006216 dres->whatNext = Dis_StopHere;
6217 dres->jk_StopHere = Ijk_Sys_syscall;
cerionb85e8bb2005-02-16 08:54:33 +00006218 return True;
cerion8c3adda2005-01-31 11:54:05 +00006219}
6220
cerion3d870a32005-03-18 12:23:33 +00006221
6222/*
6223 Memory Synchronization Instructions
cerion07b07a92005-12-22 14:32:35 +00006224
6225 Note on Reservations:
6226 We rely on the assumption that V will in fact only allow one thread at
6227 once to run. In effect, a thread can make a reservation, but we don't
6228 check any stores it does. Instead, the reservation is cancelled when
6229 the scheduler switches to another thread (run_thread_for_a_while()).
cerion3d870a32005-03-18 12:23:33 +00006230*/
cerion8c3adda2005-01-31 11:54:05 +00006231static Bool dis_memsync ( UInt theInstr )
6232{
cerionb85e8bb2005-02-16 08:54:33 +00006233 /* X-Form, XL-Form */
ceriond953ebb2005-11-29 13:27:20 +00006234 UChar opc1 = ifieldOPC(theInstr);
6235 UInt b11to25 = IFIELD(theInstr, 11, 15);
cerione43bc882006-01-05 13:11:59 +00006236 UChar flag_L = ifieldRegDS(theInstr);
6237 UInt b11to20 = IFIELD(theInstr, 11, 10);
ceriond953ebb2005-11-29 13:27:20 +00006238 UChar rD_addr = ifieldRegDS(theInstr);
6239 UChar rS_addr = rD_addr;
6240 UChar rA_addr = ifieldRegA(theInstr);
6241 UChar rB_addr = ifieldRegB(theInstr);
6242 UInt opc2 = ifieldOPClo10(theInstr);
6243 UChar b0 = ifieldBIT0(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00006244
ceriond953ebb2005-11-29 13:27:20 +00006245 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6246 IRTemp EA = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00006247
6248 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
6249
cerionb85e8bb2005-02-16 08:54:33 +00006250 switch (opc1) {
sewardjafe85832005-09-09 10:25:39 +00006251 /* XL-Form */
cerione9d361a2005-03-04 17:35:29 +00006252 case 0x13: // isync (Instruction Synchronize, PPC32 p432)
cerionb85e8bb2005-02-16 08:54:33 +00006253 if (opc2 != 0x096) {
cerion5b2325f2005-12-23 00:55:09 +00006254 vex_printf("dis_memsync(ppc)(0x13,opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006255 return False;
6256 }
6257 if (b11to25 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006258 vex_printf("dis_memsync(ppc)(0x13,b11to25|b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006259 return False;
6260 }
6261 DIP("isync\n");
sewardjc4356f02007-11-09 21:15:04 +00006262 stmt( IRStmt_MBE(Imbe_Fence) );
cerionb85e8bb2005-02-16 08:54:33 +00006263 break;
cerion8c3adda2005-01-31 11:54:05 +00006264
cerionb85e8bb2005-02-16 08:54:33 +00006265 /* X-Form */
6266 case 0x1F:
6267 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00006268 case 0x356: // eieio (Enforce In-Order Exec of I/O, PPC32 p394)
sewardj7787af42005-08-04 18:32:19 +00006269 if (b11to25 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006270 vex_printf("dis_memsync(ppc)(eiei0,b11to25|b0)\n");
sewardj7787af42005-08-04 18:32:19 +00006271 return False;
6272 }
6273 DIP("eieio\n");
6274 /* Insert a memory fence, just to be on the safe side. */
sewardjc4356f02007-11-09 21:15:04 +00006275 stmt( IRStmt_MBE(Imbe_Fence) );
sewardj7787af42005-08-04 18:32:19 +00006276 break;
cerion8c3adda2005-01-31 11:54:05 +00006277
sewardje768e922009-11-26 17:17:37 +00006278 case 0x014: { // lwarx (Load Word and Reserve Indexed, PPC32 p458)
6279 IRTemp res;
sewardjfe397a22008-08-06 19:13:42 +00006280 /* According to the PowerPC ISA version 2.05, b0 (called EH
6281 in the documentation) is merely a hint bit to the
6282 hardware, I think as to whether or not contention is
6283 likely. So we can just ignore it. */
6284 DIP("lwarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, (UInt)b0);
sewardje9d8a262009-07-01 08:06:34 +00006285
6286 // trap if misaligned
6287 gen_SIGBUS_if_misaligned( EA, 4 );
6288
6289 // and actually do the load
sewardje768e922009-11-26 17:17:37 +00006290 res = newTemp(Ity_I32);
carll1f5fe1f2014-08-07 23:25:23 +00006291 stmt( stmt_load(res, mkexpr(EA), NULL/*this is a load*/) );
sewardje768e922009-11-26 17:17:37 +00006292
6293 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(res), False) );
cerionb85e8bb2005-02-16 08:54:33 +00006294 break;
sewardje768e922009-11-26 17:17:37 +00006295 }
6296
sewardj7787af42005-08-04 18:32:19 +00006297 case 0x096: {
6298 // stwcx. (Store Word Conditional Indexed, PPC32 p532)
sewardje9d8a262009-07-01 08:06:34 +00006299 // Note this has to handle stwcx. in both 32- and 64-bit modes,
6300 // so isn't quite as straightforward as it might otherwise be.
6301 IRTemp rS = newTemp(Ity_I32);
6302 IRTemp resSC;
cerionb85e8bb2005-02-16 08:54:33 +00006303 if (b0 != 1) {
cerion5b2325f2005-12-23 00:55:09 +00006304 vex_printf("dis_memsync(ppc)(stwcx.,b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006305 return False;
6306 }
ceriond953ebb2005-11-29 13:27:20 +00006307 DIP("stwcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardjafe85832005-09-09 10:25:39 +00006308
sewardje9d8a262009-07-01 08:06:34 +00006309 // trap if misaligned
6310 gen_SIGBUS_if_misaligned( EA, 4 );
6311
6312 // Get the data to be stored, and narrow to 32 bits if necessary
6313 assign( rS, mkNarrowTo32(ty, getIReg(rS_addr)) );
6314
6315 // Do the store, and get success/failure bit into resSC
6316 resSC = newTemp(Ity_I1);
carll1f5fe1f2014-08-07 23:25:23 +00006317 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
sewardje9d8a262009-07-01 08:06:34 +00006318
6319 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
6320 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
6321 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
sewardj7787af42005-08-04 18:32:19 +00006322 putCR0(0, getXER_SO());
6323
sewardje9d8a262009-07-01 08:06:34 +00006324 /* Note:
ceriond953ebb2005-11-29 13:27:20 +00006325 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
6326 whether rS is stored is dependent on that value. */
sewardje9d8a262009-07-01 08:06:34 +00006327 /* So I guess we can just ignore this case? */
cerionb85e8bb2005-02-16 08:54:33 +00006328 break;
sewardj7787af42005-08-04 18:32:19 +00006329 }
6330
sewardjb029a612005-12-30 15:04:29 +00006331 case 0x256: // sync (Synchronize, PPC32 p543),
cerione43bc882006-01-05 13:11:59 +00006332 // also lwsync (L==1), ptesync (L==2)
sewardjb029a612005-12-30 15:04:29 +00006333 /* http://sources.redhat.com/ml/binutils/2000-12/msg00311.html
6334
6335 The PowerPC architecture used in IBM chips has expanded
6336 the sync instruction into two variants: lightweight sync
6337 and heavyweight sync. The original sync instruction is
6338 the new heavyweight sync and lightweight sync is a strict
6339 subset of the heavyweight sync functionality. This allows
6340 the programmer to specify a less expensive operation on
6341 high-end systems when the full sync functionality is not
6342 necessary.
6343
6344 The basic "sync" mnemonic now utilizes an operand. "sync"
6345 without an operand now becomes a extended mnemonic for
6346 heavyweight sync. Processors without the lwsync
6347 instruction will not decode the L field and will perform a
6348 heavyweight sync. Everything is backward compatible.
6349
6350 sync = sync 0
6351 lwsync = sync 1
cerione43bc882006-01-05 13:11:59 +00006352 ptesync = sync 2 *** TODO - not implemented ***
cerion4e2c2b32006-01-02 13:35:51 +00006353 */
cerione43bc882006-01-05 13:11:59 +00006354 if (b11to20 != 0 || b0 != 0) {
6355 vex_printf("dis_memsync(ppc)(sync/lwsync,b11to20|b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006356 return False;
6357 }
cerione43bc882006-01-05 13:11:59 +00006358 if (flag_L != 0/*sync*/ && flag_L != 1/*lwsync*/) {
6359 vex_printf("dis_memsync(ppc)(sync/lwsync,flag_L)\n");
6360 return False;
6361 }
6362 DIP("%ssync\n", flag_L == 1 ? "lw" : "");
cerionb85e8bb2005-02-16 08:54:33 +00006363 /* Insert a memory fence. It's sometimes important that these
6364 are carried through to the generated code. */
sewardjc4356f02007-11-09 21:15:04 +00006365 stmt( IRStmt_MBE(Imbe_Fence) );
cerionb85e8bb2005-02-16 08:54:33 +00006366 break;
cerionf0de28c2005-12-13 20:21:11 +00006367
cerionf0de28c2005-12-13 20:21:11 +00006368 /* 64bit Memsync */
sewardje768e922009-11-26 17:17:37 +00006369 case 0x054: { // ldarx (Load DWord and Reserve Indexed, PPC64 p473)
6370 IRTemp res;
sewardjfe397a22008-08-06 19:13:42 +00006371 /* According to the PowerPC ISA version 2.05, b0 (called EH
6372 in the documentation) is merely a hint bit to the
6373 hardware, I think as to whether or not contention is
6374 likely. So we can just ignore it. */
sewardje9d8a262009-07-01 08:06:34 +00006375 if (!mode64)
6376 return False;
sewardjfe397a22008-08-06 19:13:42 +00006377 DIP("ldarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, (UInt)b0);
sewardje9d8a262009-07-01 08:06:34 +00006378
6379 // trap if misaligned
6380 gen_SIGBUS_if_misaligned( EA, 8 );
6381
6382 // and actually do the load
sewardje768e922009-11-26 17:17:37 +00006383 res = newTemp(Ity_I64);
carll1f5fe1f2014-08-07 23:25:23 +00006384 stmt( stmt_load( res, mkexpr(EA), NULL/*this is a load*/) );
sewardje768e922009-11-26 17:17:37 +00006385
6386 putIReg( rD_addr, mkexpr(res) );
cerion07b07a92005-12-22 14:32:35 +00006387 break;
sewardje768e922009-11-26 17:17:37 +00006388 }
6389
cerion5b2325f2005-12-23 00:55:09 +00006390 case 0x0D6: { // stdcx. (Store DWord Condition Indexd, PPC64 p581)
sewardje9d8a262009-07-01 08:06:34 +00006391 // A marginally simplified version of the stwcx. case
6392 IRTemp rS = newTemp(Ity_I64);
6393 IRTemp resSC;
cerionf0de28c2005-12-13 20:21:11 +00006394 if (b0 != 1) {
cerion5b2325f2005-12-23 00:55:09 +00006395 vex_printf("dis_memsync(ppc)(stdcx.,b0)\n");
cerionf0de28c2005-12-13 20:21:11 +00006396 return False;
6397 }
sewardje9d8a262009-07-01 08:06:34 +00006398 if (!mode64)
6399 return False;
cerionf0de28c2005-12-13 20:21:11 +00006400 DIP("stdcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardje9d8a262009-07-01 08:06:34 +00006401
6402 // trap if misaligned
6403 gen_SIGBUS_if_misaligned( EA, 8 );
6404
6405 // Get the data to be stored
cerion07b07a92005-12-22 14:32:35 +00006406 assign( rS, getIReg(rS_addr) );
cerionf0de28c2005-12-13 20:21:11 +00006407
sewardje9d8a262009-07-01 08:06:34 +00006408 // Do the store, and get success/failure bit into resSC
6409 resSC = newTemp(Ity_I1);
carll1f5fe1f2014-08-07 23:25:23 +00006410 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS)) );
sewardje9d8a262009-07-01 08:06:34 +00006411
6412 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
6413 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
6414 putCR321(0, binop(Iop_Shl8, unop(Iop_1Uto8, mkexpr(resSC)), mkU8(1)));
cerion07b07a92005-12-22 14:32:35 +00006415 putCR0(0, getXER_SO());
cerionf0de28c2005-12-13 20:21:11 +00006416
sewardje9d8a262009-07-01 08:06:34 +00006417 /* Note:
6418 If resaddr != lwarx_resaddr, CR0[EQ] is undefined, and
6419 whether rS is stored is dependent on that value. */
6420 /* So I guess we can just ignore this case? */
cerion07b07a92005-12-22 14:32:35 +00006421 break;
6422 }
6423
carll78850ae2013-09-10 18:46:40 +00006424 /* 128bit Memsync */
6425 case 0x114: { // lqarx (Load QuadWord and Reserve Indexed)
6426 IRTemp res_hi = newTemp(ty);
6427 IRTemp res_lo = newTemp(ty);
6428
6429 /* According to the PowerPC ISA version 2.07, b0 (called EH
6430 in the documentation) is merely a hint bit to the
6431 hardware, I think as to whether or not contention is
6432 likely. So we can just ignore it. */
6433 DIP("lqarx r%u,r%u,r%u,EH=%u\n", rD_addr, rA_addr, rB_addr, (UInt)b0);
6434
6435 // trap if misaligned
6436 gen_SIGBUS_if_misaligned( EA, 16 );
6437
6438 // and actually do the load
6439 if (mode64) {
carll1f5fe1f2014-08-07 23:25:23 +00006440 stmt( stmt_load( res_hi,
6441 mkexpr(EA), NULL/*this is a load*/) );
6442 stmt( stmt_load( res_lo,
6443 binop(Iop_Add64, mkexpr(EA), mkU64(8) ),
6444 NULL/*this is a load*/) );
carll78850ae2013-09-10 18:46:40 +00006445 } else {
carll1f5fe1f2014-08-07 23:25:23 +00006446 stmt( stmt_load( res_hi,
6447 binop( Iop_Add32, mkexpr(EA), mkU32(4) ),
6448 NULL/*this is a load*/) );
6449 stmt( stmt_load( res_lo,
6450 binop( Iop_Add32, mkexpr(EA), mkU32(12) ),
6451 NULL/*this is a load*/) );
carll78850ae2013-09-10 18:46:40 +00006452 }
6453 putIReg( rD_addr, mkexpr(res_hi) );
6454 putIReg( rD_addr+1, mkexpr(res_lo) );
6455 break;
6456 }
6457
6458 case 0x0B6: { // stqcx. (Store QuadWord Condition Indexd, PPC64)
6459 // A marginally simplified version of the stwcx. case
6460 IRTemp rS_hi = newTemp(ty);
6461 IRTemp rS_lo = newTemp(ty);
6462 IRTemp resSC;
6463 if (b0 != 1) {
6464 vex_printf("dis_memsync(ppc)(stqcx.,b0)\n");
6465 return False;
6466 }
6467
6468 DIP("stqcx. r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
6469
6470 // trap if misaligned
6471 gen_SIGBUS_if_misaligned( EA, 16 );
6472 // Get the data to be stored
6473 assign( rS_hi, getIReg(rS_addr) );
6474 assign( rS_lo, getIReg(rS_addr+1) );
6475
6476 // Do the store, and get success/failure bit into resSC
6477 resSC = newTemp(Ity_I1);
6478
6479 if (mode64) {
carll1f5fe1f2014-08-07 23:25:23 +00006480 stmt( stmt_load( resSC, mkexpr(EA), mkexpr(rS_hi) ) );
6481 store( binop( Iop_Add64, mkexpr(EA), mkU64(8) ), mkexpr(rS_lo) );
carll78850ae2013-09-10 18:46:40 +00006482 } else {
carll1f5fe1f2014-08-07 23:25:23 +00006483 stmt( stmt_load( resSC, binop( Iop_Add32,
6484 mkexpr(EA),
6485 mkU32(4) ),
6486 mkexpr(rS_hi) ) );
6487 store( binop(Iop_Add32, mkexpr(EA), mkU32(12) ), mkexpr(rS_lo) );
carll78850ae2013-09-10 18:46:40 +00006488 }
6489
6490 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO] on failure
6491 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO] on success
6492 putCR321(0, binop( Iop_Shl8,
6493 unop(Iop_1Uto8, mkexpr(resSC) ),
6494 mkU8(1)));
6495 putCR0(0, getXER_SO());
6496 break;
6497 }
6498
cerionb85e8bb2005-02-16 08:54:33 +00006499 default:
cerion5b2325f2005-12-23 00:55:09 +00006500 vex_printf("dis_memsync(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006501 return False;
6502 }
6503 break;
cerion8c3adda2005-01-31 11:54:05 +00006504
cerionb85e8bb2005-02-16 08:54:33 +00006505 default:
cerion5b2325f2005-12-23 00:55:09 +00006506 vex_printf("dis_memsync(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006507 return False;
6508 }
6509 return True;
cerion8c3adda2005-01-31 11:54:05 +00006510}
6511
6512
6513
cerion3d870a32005-03-18 12:23:33 +00006514/*
6515 Integer Shift Instructions
6516*/
cerion645c9302005-01-31 10:09:59 +00006517static Bool dis_int_shift ( UInt theInstr )
6518{
cerionf0de28c2005-12-13 20:21:11 +00006519 /* X-Form, XS-Form */
cerion76de5cf2005-11-18 18:25:12 +00006520 UChar opc1 = ifieldOPC(theInstr);
6521 UChar rS_addr = ifieldRegDS(theInstr);
6522 UChar rA_addr = ifieldRegA(theInstr);
6523 UChar rB_addr = ifieldRegB(theInstr);
6524 UChar sh_imm = rB_addr;
6525 UInt opc2 = ifieldOPClo10(theInstr);
cerionf0de28c2005-12-13 20:21:11 +00006526 UChar b1 = ifieldBIT1(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00006527 UChar flag_rC = ifieldBIT0(theInstr);
6528
ceriond953ebb2005-11-29 13:27:20 +00006529 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6530 IRTemp rA = newTemp(ty);
cerion07b07a92005-12-22 14:32:35 +00006531 IRTemp rS = newTemp(ty);
6532 IRTemp rB = newTemp(ty);
sewardj009230b2013-01-26 11:47:55 +00006533 IRTemp outofrange = newTemp(Ity_I1);
ceriond953ebb2005-11-29 13:27:20 +00006534 IRTemp rS_lo32 = newTemp(Ity_I32);
6535 IRTemp rB_lo32 = newTemp(Ity_I32);
6536 IRExpr* e_tmp;
6537
cerion07b07a92005-12-22 14:32:35 +00006538 assign( rS, getIReg(rS_addr) );
6539 assign( rB, getIReg(rB_addr) );
sewardje9d8a262009-07-01 08:06:34 +00006540 assign( rS_lo32, mkNarrowTo32(ty, mkexpr(rS)) );
6541 assign( rB_lo32, mkNarrowTo32(ty, mkexpr(rB)) );
cerionb85e8bb2005-02-16 08:54:33 +00006542
6543 if (opc1 == 0x1F) {
6544 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00006545 case 0x018: { // slw (Shift Left Word, PPC32 p505)
cerion5b2325f2005-12-23 00:55:09 +00006546 DIP("slw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006547 rA_addr, rS_addr, rB_addr);
6548 /* rA = rS << rB */
6549 /* ppc32 semantics are:
sewardjdfb11442005-10-08 19:58:48 +00006550 slw(x,y) = (x << (y & 31)) -- primary result
6551 & ~((y << 26) >>s 31) -- make result 0
6552 for y in 32 .. 63
6553 */
ceriond953ebb2005-11-29 13:27:20 +00006554 e_tmp =
6555 binop( Iop_And32,
6556 binop( Iop_Shl32,
6557 mkexpr(rS_lo32),
6558 unop( Iop_32to8,
6559 binop(Iop_And32,
6560 mkexpr(rB_lo32), mkU32(31)))),
6561 unop( Iop_Not32,
6562 binop( Iop_Sar32,
6563 binop(Iop_Shl32, mkexpr(rB_lo32), mkU8(26)),
6564 mkU8(31))) );
sewardje9d8a262009-07-01 08:06:34 +00006565 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
cerionb85e8bb2005-02-16 08:54:33 +00006566 break;
ceriond953ebb2005-11-29 13:27:20 +00006567 }
6568
cerion5b2325f2005-12-23 00:55:09 +00006569 case 0x318: { // sraw (Shift Right Alg Word, PPC32 p506)
cerion07b07a92005-12-22 14:32:35 +00006570 IRTemp sh_amt = newTemp(Ity_I32);
cerion5b2325f2005-12-23 00:55:09 +00006571 DIP("sraw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006572 rA_addr, rS_addr, rB_addr);
cerion76de5cf2005-11-18 18:25:12 +00006573 /* JRS: my reading of the (poorly worded) PPC32 doc p506 is:
6574 amt = rB & 63
6575 rA = Sar32( rS, amt > 31 ? 31 : amt )
6576 XER.CA = amt > 31 ? sign-of-rS : (computation as per srawi)
6577 */
cerion5b2325f2005-12-23 00:55:09 +00006578 assign( sh_amt, binop(Iop_And32, mkU32(0x3F),
6579 mkexpr(rB_lo32)) );
cerion76de5cf2005-11-18 18:25:12 +00006580 assign( outofrange,
sewardj009230b2013-01-26 11:47:55 +00006581 binop(Iop_CmpLT32U, mkU32(31), mkexpr(sh_amt)) );
ceriond953ebb2005-11-29 13:27:20 +00006582 e_tmp = binop( Iop_Sar32,
6583 mkexpr(rS_lo32),
sewardj20ef5472005-07-21 14:48:31 +00006584 unop( Iop_32to8,
florian99dd03e2013-01-29 03:56:06 +00006585 IRExpr_ITE( mkexpr(outofrange),
6586 mkU32(31),
6587 mkexpr(sh_amt)) ) );
sewardje9d8a262009-07-01 08:06:34 +00006588 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */True) );
cerion2831b002005-11-30 19:55:22 +00006589
cerion5b2325f2005-12-23 00:55:09 +00006590 set_XER_CA( ty, PPCG_FLAG_OP_SRAW,
cerionf0de28c2005-12-13 20:21:11 +00006591 mkexpr(rA),
sewardje9d8a262009-07-01 08:06:34 +00006592 mkWidenFrom32(ty, mkexpr(rS_lo32), True),
6593 mkWidenFrom32(ty, mkexpr(sh_amt), True ),
6594 mkWidenFrom32(ty, getXER_CA32(), True) );
cerionb85e8bb2005-02-16 08:54:33 +00006595 break;
cerion07b07a92005-12-22 14:32:35 +00006596 }
cerionb85e8bb2005-02-16 08:54:33 +00006597
cerion5b2325f2005-12-23 00:55:09 +00006598 case 0x338: // srawi (Shift Right Alg Word Immediate, PPC32 p507)
6599 DIP("srawi%s r%u,r%u,%d\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006600 rA_addr, rS_addr, sh_imm);
6601 vassert(sh_imm < 32);
cerionf0de28c2005-12-13 20:21:11 +00006602 if (mode64) {
6603 assign( rA, binop(Iop_Sar64,
cerion5b2325f2005-12-23 00:55:09 +00006604 binop(Iop_Shl64, getIReg(rS_addr),
6605 mkU8(32)),
cerionf0de28c2005-12-13 20:21:11 +00006606 mkU8(32 + sh_imm)) );
6607 } else {
cerion5b2325f2005-12-23 00:55:09 +00006608 assign( rA, binop(Iop_Sar32, mkexpr(rS_lo32),
6609 mkU8(sh_imm)) );
cerionf0de28c2005-12-13 20:21:11 +00006610 }
cerion2831b002005-11-30 19:55:22 +00006611
cerion5b2325f2005-12-23 00:55:09 +00006612 set_XER_CA( ty, PPCG_FLAG_OP_SRAWI,
cerionf0de28c2005-12-13 20:21:11 +00006613 mkexpr(rA),
sewardje9d8a262009-07-01 08:06:34 +00006614 mkWidenFrom32(ty, mkexpr(rS_lo32), /* Syned */True),
cerionf0de28c2005-12-13 20:21:11 +00006615 mkSzImm(ty, sh_imm),
sewardje9d8a262009-07-01 08:06:34 +00006616 mkWidenFrom32(ty, getXER_CA32(), /* Syned */False) );
cerionb85e8bb2005-02-16 08:54:33 +00006617 break;
6618
cerione9d361a2005-03-04 17:35:29 +00006619 case 0x218: // srw (Shift Right Word, PPC32 p508)
cerion5b2325f2005-12-23 00:55:09 +00006620 DIP("srw%s r%u,r%u,r%u\n", flag_rC ? ".":"",
cerion76de5cf2005-11-18 18:25:12 +00006621 rA_addr, rS_addr, rB_addr);
6622 /* rA = rS >>u rB */
6623 /* ppc32 semantics are:
cerionf0de28c2005-12-13 20:21:11 +00006624 srw(x,y) = (x >>u (y & 31)) -- primary result
sewardjdfb11442005-10-08 19:58:48 +00006625 & ~((y << 26) >>s 31) -- make result 0
6626 for y in 32 .. 63
6627 */
ceriond953ebb2005-11-29 13:27:20 +00006628 e_tmp =
sewardjdfb11442005-10-08 19:58:48 +00006629 binop(
6630 Iop_And32,
6631 binop( Iop_Shr32,
ceriond953ebb2005-11-29 13:27:20 +00006632 mkexpr(rS_lo32),
sewardjdfb11442005-10-08 19:58:48 +00006633 unop( Iop_32to8,
cerion5b2325f2005-12-23 00:55:09 +00006634 binop(Iop_And32, mkexpr(rB_lo32),
6635 mkU32(31)))),
sewardjdfb11442005-10-08 19:58:48 +00006636 unop( Iop_Not32,
6637 binop( Iop_Sar32,
cerion5b2325f2005-12-23 00:55:09 +00006638 binop(Iop_Shl32, mkexpr(rB_lo32),
6639 mkU8(26)),
ceriond953ebb2005-11-29 13:27:20 +00006640 mkU8(31))));
sewardje9d8a262009-07-01 08:06:34 +00006641 assign( rA, mkWidenFrom32(ty, e_tmp, /* Signed */False) );
cerionb85e8bb2005-02-16 08:54:33 +00006642 break;
cerionf0de28c2005-12-13 20:21:11 +00006643
6644
6645 /* 64bit Shifts */
cerion5b2325f2005-12-23 00:55:09 +00006646 case 0x01B: // sld (Shift Left DWord, PPC64 p568)
6647 DIP("sld%s r%u,r%u,r%u\n",
6648 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00006649 /* rA = rS << rB */
cerion07b07a92005-12-22 14:32:35 +00006650 /* ppc64 semantics are:
cerionf0de28c2005-12-13 20:21:11 +00006651 slw(x,y) = (x << (y & 63)) -- primary result
6652 & ~((y << 57) >>s 63) -- make result 0
6653 for y in 64 ..
6654 */
cerionf0de28c2005-12-13 20:21:11 +00006655 assign( rA,
6656 binop(
6657 Iop_And64,
6658 binop( Iop_Shl64,
6659 mkexpr(rS),
6660 unop( Iop_64to8,
6661 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
6662 unop( Iop_Not64,
6663 binop( Iop_Sar64,
6664 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
6665 mkU8(63)))) );
cerion07b07a92005-12-22 14:32:35 +00006666 break;
cerionf0de28c2005-12-13 20:21:11 +00006667
cerion5b2325f2005-12-23 00:55:09 +00006668 case 0x31A: { // srad (Shift Right Alg DWord, PPC64 p570)
cerion07b07a92005-12-22 14:32:35 +00006669 IRTemp sh_amt = newTemp(Ity_I64);
cerion5b2325f2005-12-23 00:55:09 +00006670 DIP("srad%s r%u,r%u,r%u\n",
6671 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00006672 /* amt = rB & 127
6673 rA = Sar64( rS, amt > 63 ? 63 : amt )
6674 XER.CA = amt > 63 ? sign-of-rS : (computation as per srawi)
6675 */
cerion07b07a92005-12-22 14:32:35 +00006676 assign( sh_amt, binop(Iop_And64, mkU64(0x7F), mkexpr(rB)) );
cerionf0de28c2005-12-13 20:21:11 +00006677 assign( outofrange,
sewardj009230b2013-01-26 11:47:55 +00006678 binop(Iop_CmpLT64U, mkU64(63), mkexpr(sh_amt)) );
cerionf0de28c2005-12-13 20:21:11 +00006679 assign( rA,
6680 binop( Iop_Sar64,
6681 mkexpr(rS),
6682 unop( Iop_64to8,
florian99dd03e2013-01-29 03:56:06 +00006683 IRExpr_ITE( mkexpr(outofrange),
6684 mkU64(63),
6685 mkexpr(sh_amt)) ))
cerionf0de28c2005-12-13 20:21:11 +00006686 );
cerion5b2325f2005-12-23 00:55:09 +00006687 set_XER_CA( ty, PPCG_FLAG_OP_SRAD,
cerion07b07a92005-12-22 14:32:35 +00006688 mkexpr(rA), mkexpr(rS), mkexpr(sh_amt),
sewardje9d8a262009-07-01 08:06:34 +00006689 mkWidenFrom32(ty, getXER_CA32(), /* Syned */False) );
cerion07b07a92005-12-22 14:32:35 +00006690 break;
6691 }
6692
cerion5b2325f2005-12-23 00:55:09 +00006693 case 0x33A: case 0x33B: // sradi (Shr Alg DWord Imm, PPC64 p571)
cerionf0de28c2005-12-13 20:21:11 +00006694 sh_imm |= b1<<5;
6695 vassert(sh_imm < 64);
cerion5b2325f2005-12-23 00:55:09 +00006696 DIP("sradi%s r%u,r%u,%u\n",
6697 flag_rC ? ".":"", rA_addr, rS_addr, sh_imm);
cerionf0de28c2005-12-13 20:21:11 +00006698 assign( rA, binop(Iop_Sar64, getIReg(rS_addr), mkU8(sh_imm)) );
6699
cerion5b2325f2005-12-23 00:55:09 +00006700 set_XER_CA( ty, PPCG_FLAG_OP_SRADI,
cerionf0de28c2005-12-13 20:21:11 +00006701 mkexpr(rA),
6702 getIReg(rS_addr),
6703 mkU64(sh_imm),
sewardje9d8a262009-07-01 08:06:34 +00006704 mkWidenFrom32(ty, getXER_CA32(), /* Syned */False) );
cerionf0de28c2005-12-13 20:21:11 +00006705 break;
6706
cerion5b2325f2005-12-23 00:55:09 +00006707 case 0x21B: // srd (Shift Right DWord, PPC64 p574)
6708 DIP("srd%s r%u,r%u,r%u\n",
6709 flag_rC ? ".":"", rA_addr, rS_addr, rB_addr);
cerionf0de28c2005-12-13 20:21:11 +00006710 /* rA = rS >>u rB */
cerion07b07a92005-12-22 14:32:35 +00006711 /* ppc semantics are:
cerionf0de28c2005-12-13 20:21:11 +00006712 srw(x,y) = (x >>u (y & 63)) -- primary result
6713 & ~((y << 57) >>s 63) -- make result 0
6714 for y in 64 .. 127
6715 */
cerionf0de28c2005-12-13 20:21:11 +00006716 assign( rA,
6717 binop(
6718 Iop_And64,
6719 binop( Iop_Shr64,
6720 mkexpr(rS),
6721 unop( Iop_64to8,
6722 binop(Iop_And64, mkexpr(rB), mkU64(63)))),
6723 unop( Iop_Not64,
6724 binop( Iop_Sar64,
6725 binop(Iop_Shl64, mkexpr(rB), mkU8(57)),
6726 mkU8(63)))) );
cerion07b07a92005-12-22 14:32:35 +00006727 break;
cerionf0de28c2005-12-13 20:21:11 +00006728
cerionb85e8bb2005-02-16 08:54:33 +00006729 default:
cerion5b2325f2005-12-23 00:55:09 +00006730 vex_printf("dis_int_shift(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006731 return False;
6732 }
6733 } else {
cerion5b2325f2005-12-23 00:55:09 +00006734 vex_printf("dis_int_shift(ppc)(opc1)\n");
cerionb85e8bb2005-02-16 08:54:33 +00006735 return False;
6736 }
cerion0d330c52005-02-28 16:43:16 +00006737
cerion76de5cf2005-11-18 18:25:12 +00006738 putIReg( rA_addr, mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00006739
cerion76de5cf2005-11-18 18:25:12 +00006740 if (flag_rC) {
6741 set_CR0( mkexpr(rA) );
cerionb85e8bb2005-02-16 08:54:33 +00006742 }
6743 return True;
cerion645c9302005-01-31 10:09:59 +00006744}
6745
6746
6747
sewardj602857d2005-09-06 09:10:09 +00006748/*
6749 Integer Load/Store Reverse Instructions
6750*/
sewardj40d8c092006-05-05 13:26:14 +00006751/* Generates code to swap the byte order in an Ity_I32. */
sewardjfb957972005-09-08 17:53:03 +00006752static IRExpr* /* :: Ity_I32 */ gen_byterev32 ( IRTemp t )
6753{
sewardjdd40fdf2006-12-24 02:20:24 +00006754 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
sewardjfb957972005-09-08 17:53:03 +00006755 return
6756 binop(Iop_Or32,
6757 binop(Iop_Shl32, mkexpr(t), mkU8(24)),
6758 binop(Iop_Or32,
6759 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
6760 mkU32(0x00FF0000)),
6761 binop(Iop_Or32,
6762 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
6763 mkU32(0x0000FF00)),
6764 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(24)),
6765 mkU32(0x000000FF) )
6766 )));
6767}
6768
sewardj40d8c092006-05-05 13:26:14 +00006769/* Generates code to swap the byte order in the lower half of an Ity_I32,
6770 and zeroes the upper half. */
6771static IRExpr* /* :: Ity_I32 */ gen_byterev16 ( IRTemp t )
6772{
sewardjdd40fdf2006-12-24 02:20:24 +00006773 vassert(typeOfIRTemp(irsb->tyenv, t) == Ity_I32);
sewardj40d8c092006-05-05 13:26:14 +00006774 return
6775 binop(Iop_Or32,
6776 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
6777 mkU32(0x0000FF00)),
6778 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
6779 mkU32(0x000000FF))
6780 );
6781}
6782
sewardj602857d2005-09-06 09:10:09 +00006783static Bool dis_int_ldst_rev ( UInt theInstr )
6784{
6785 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00006786 UChar opc1 = ifieldOPC(theInstr);
6787 UChar rD_addr = ifieldRegDS(theInstr);
6788 UChar rS_addr = rD_addr;
6789 UChar rA_addr = ifieldRegA(theInstr);
6790 UChar rB_addr = ifieldRegB(theInstr);
6791 UInt opc2 = ifieldOPClo10(theInstr);
6792 UChar b0 = ifieldBIT0(theInstr);
cerionedf7fc52005-11-18 20:57:41 +00006793
ceriond953ebb2005-11-29 13:27:20 +00006794 IRType ty = mode64 ? Ity_I64 : Ity_I32;
6795 IRTemp EA = newTemp(ty);
cerionedf7fc52005-11-18 20:57:41 +00006796 IRTemp w1 = newTemp(Ity_I32);
6797 IRTemp w2 = newTemp(Ity_I32);
sewardj602857d2005-09-06 09:10:09 +00006798
6799 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006800 vex_printf("dis_int_ldst_rev(ppc)(opc1|b0)\n");
sewardj602857d2005-09-06 09:10:09 +00006801 return False;
6802 }
sewardjafe85832005-09-09 10:25:39 +00006803
ceriond953ebb2005-11-29 13:27:20 +00006804 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
sewardj602857d2005-09-06 09:10:09 +00006805
6806 switch (opc2) {
sewardj40d8c092006-05-05 13:26:14 +00006807
6808 case 0x316: // lhbrx (Load Halfword Byte-Reverse Indexed, PPC32 p449)
6809 DIP("lhbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00006810 assign( w1, unop(Iop_16Uto32, load(Ity_I16, mkexpr(EA))) );
sewardj40d8c092006-05-05 13:26:14 +00006811 assign( w2, gen_byterev16(w1) );
sewardje9d8a262009-07-01 08:06:34 +00006812 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
6813 /* Signed */False) );
sewardj40d8c092006-05-05 13:26:14 +00006814 break;
6815
sewardjfb957972005-09-08 17:53:03 +00006816 case 0x216: // lwbrx (Load Word Byte-Reverse Indexed, PPC32 p459)
ceriond953ebb2005-11-29 13:27:20 +00006817 DIP("lwbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00006818 assign( w1, load(Ity_I32, mkexpr(EA)) );
sewardjfb957972005-09-08 17:53:03 +00006819 assign( w2, gen_byterev32(w1) );
sewardje9d8a262009-07-01 08:06:34 +00006820 putIReg( rD_addr, mkWidenFrom32(ty, mkexpr(w2),
6821 /* Signed */False) );
sewardjfb957972005-09-08 17:53:03 +00006822 break;
sewardj66d5ef22011-04-15 11:55:00 +00006823
6824 case 0x214: // ldbrx (Load Doubleword Byte-Reverse Indexed)
6825 {
6826 IRExpr * nextAddr;
6827 IRTemp w3 = newTemp( Ity_I32 );
6828 IRTemp w4 = newTemp( Ity_I32 );
6829 DIP("ldbrx r%u,r%u,r%u\n", rD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +00006830 assign( w1, load( Ity_I32, mkexpr( EA ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00006831 assign( w2, gen_byterev32( w1 ) );
6832 nextAddr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
6833 ty == Ity_I64 ? mkU64( 4 ) : mkU32( 4 ) );
carll1f5fe1f2014-08-07 23:25:23 +00006834 assign( w3, load( Ity_I32, nextAddr ) );
sewardj66d5ef22011-04-15 11:55:00 +00006835 assign( w4, gen_byterev32( w3 ) );
carll1f5fe1f2014-08-07 23:25:23 +00006836 if (host_endness == VexEndnessLE)
6837 putIReg( rD_addr, binop( Iop_32HLto64, mkexpr( w2 ), mkexpr( w4 ) ) );
6838 else
6839 putIReg( rD_addr, binop( Iop_32HLto64, mkexpr( w4 ), mkexpr( w2 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00006840 break;
6841 }
6842
sewardj413a4682006-05-05 13:44:17 +00006843 case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
6844 DIP("sthbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardje9d8a262009-07-01 08:06:34 +00006845 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
carll1f5fe1f2014-08-07 23:25:23 +00006846 store( mkexpr(EA), unop(Iop_32to16, gen_byterev16(w1)) );
sewardj413a4682006-05-05 13:44:17 +00006847 break;
sewardj602857d2005-09-06 09:10:09 +00006848
cerion5b2325f2005-12-23 00:55:09 +00006849 case 0x296: // stwbrx (Store Word Byte-Reverse Indxd, PPC32 p531)
ceriond953ebb2005-11-29 13:27:20 +00006850 DIP("stwbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
sewardje9d8a262009-07-01 08:06:34 +00006851 assign( w1, mkNarrowTo32(ty, getIReg(rS_addr)) );
carll1f5fe1f2014-08-07 23:25:23 +00006852 store( mkexpr(EA), gen_byterev32(w1) );
sewardjfb957972005-09-08 17:53:03 +00006853 break;
sewardj4aa412a2011-07-24 14:13:21 +00006854
6855 case 0x294: // stdbrx (Store Doubleword Byte-Reverse Indexed)
6856 {
6857 IRTemp lo = newTemp(Ity_I32);
6858 IRTemp hi = newTemp(Ity_I32);
6859 IRTemp rS = newTemp(Ity_I64);
6860 assign( rS, getIReg( rS_addr ) );
6861 DIP("stdbrx r%u,r%u,r%u\n", rS_addr, rA_addr, rB_addr);
6862 assign(lo, unop(Iop_64HIto32, mkexpr(rS)));
6863 assign(hi, unop(Iop_64to32, mkexpr(rS)));
carll1f5fe1f2014-08-07 23:25:23 +00006864 store( mkexpr( EA ),
6865 binop( Iop_32HLto64, gen_byterev32( hi ),
6866 gen_byterev32( lo ) ) );
sewardj4aa412a2011-07-24 14:13:21 +00006867 break;
6868 }
6869
sewardjfb957972005-09-08 17:53:03 +00006870 default:
cerion5b2325f2005-12-23 00:55:09 +00006871 vex_printf("dis_int_ldst_rev(ppc)(opc2)\n");
sewardjfb957972005-09-08 17:53:03 +00006872 return False;
sewardj602857d2005-09-06 09:10:09 +00006873 }
6874 return True;
6875}
cerion645c9302005-01-31 10:09:59 +00006876
6877
6878
cerion3d870a32005-03-18 12:23:33 +00006879/*
6880 Processor Control Instructions
6881*/
sewardjdd40fdf2006-12-24 02:20:24 +00006882static Bool dis_proc_ctl ( VexAbiInfo* vbi, UInt theInstr )
cerion8c3adda2005-01-31 11:54:05 +00006883{
cerion76de5cf2005-11-18 18:25:12 +00006884 UChar opc1 = ifieldOPC(theInstr);
cerionb85e8bb2005-02-16 08:54:33 +00006885
6886 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00006887 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
6888 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
6889 UChar rD_addr = ifieldRegDS(theInstr);
6890 UInt b11to20 = IFIELD( theInstr, 11, 10 );
cerione9d361a2005-03-04 17:35:29 +00006891
cerion76de5cf2005-11-18 18:25:12 +00006892 /* XFX-Form */
6893 UChar rS_addr = rD_addr;
6894 UInt SPR = b11to20;
cerionedf7fc52005-11-18 20:57:41 +00006895 UInt TBR = b11to20;
cerion76de5cf2005-11-18 18:25:12 +00006896 UChar b20 = toUChar( IFIELD( theInstr, 20, 1 ) );
6897 UInt CRM = IFIELD( theInstr, 12, 8 );
6898 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
6899
6900 UInt opc2 = ifieldOPClo10(theInstr);
6901 UChar b0 = ifieldBIT0(theInstr);
6902
cerion2831b002005-11-30 19:55:22 +00006903 IRType ty = mode64 ? Ity_I64 : Ity_I32;
cerionf0de28c2005-12-13 20:21:11 +00006904 IRTemp rS = newTemp(ty);
ceriond953ebb2005-11-29 13:27:20 +00006905 assign( rS, getIReg(rS_addr) );
sewardj41a7b702005-11-18 22:18:23 +00006906
cerion76de5cf2005-11-18 18:25:12 +00006907 /* Reorder SPR field as per PPC32 p470 */
6908 SPR = ((SPR & 0x1F) << 5) | ((SPR >> 5) & 0x1F);
sewardj73a91972005-09-06 10:25:46 +00006909 /* Reorder TBR field as per PPC32 p475 */
6910 TBR = ((TBR & 31) << 5) | ((TBR >> 5) & 31);
cerionb85e8bb2005-02-16 08:54:33 +00006911
carll48ae46b2013-10-01 15:45:54 +00006912 /* b0 = 0, inst is treated as floating point inst for reservation purposes
6913 * b0 = 1, inst is treated as vector inst for reservation purposes
6914 */
6915 if (opc1 != 0x1F) {
6916 vex_printf("dis_proc_ctl(ppc)(opc1|b%d)\n", b0);
cerionb85e8bb2005-02-16 08:54:33 +00006917 return False;
6918 }
6919
6920 switch (opc2) {
cerioncb14e732005-09-09 16:38:19 +00006921 /* X-Form */
cerion5b2325f2005-12-23 00:55:09 +00006922 case 0x200: { // mcrxr (Move to Cond Register from XER, PPC32 p466)
cerioncb14e732005-09-09 16:38:19 +00006923 if (b21to22 != 0 || b11to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00006924 vex_printf("dis_proc_ctl(ppc)(mcrxr,b21to22|b11to20)\n");
cerioncb14e732005-09-09 16:38:19 +00006925 return False;
6926 }
6927 DIP("mcrxr crf%d\n", crfD);
cerionedf7fc52005-11-18 20:57:41 +00006928 /* Move XER[0-3] (the top 4 bits of XER) to CR[crfD] */
ceriond953ebb2005-11-29 13:27:20 +00006929 putGST_field( PPC_GST_CR,
6930 getGST_field( PPC_GST_XER, 7 ),
cerionedf7fc52005-11-18 20:57:41 +00006931 crfD );
sewardj55ccc3e2005-09-09 19:45:02 +00006932
6933 // Clear XER[0-3]
cerionedf7fc52005-11-18 20:57:41 +00006934 putXER_SO( mkU8(0) );
6935 putXER_OV( mkU8(0) );
6936 putXER_CA( mkU8(0) );
cerioncb14e732005-09-09 16:38:19 +00006937 break;
sewardj55ccc3e2005-09-09 19:45:02 +00006938 }
cerionb85e8bb2005-02-16 08:54:33 +00006939
sewardj72aefb22006-03-01 18:58:39 +00006940 case 0x013:
6941 // b11to20==0: mfcr (Move from Cond Register, PPC32 p467)
6942 // b20==1 & b11==0: mfocrf (Move from One CR Field)
6943 // However it seems that the 'mfcr' behaviour is an acceptable
6944 // implementation of mfocr (from the 2.02 arch spec)
6945 if (b11to20 == 0) {
6946 DIP("mfcr r%u\n", rD_addr);
sewardje9d8a262009-07-01 08:06:34 +00006947 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
6948 /* Signed */False) );
sewardj72aefb22006-03-01 18:58:39 +00006949 break;
cerionb85e8bb2005-02-16 08:54:33 +00006950 }
sewardj72aefb22006-03-01 18:58:39 +00006951 if (b20 == 1 && b11 == 0) {
6952 DIP("mfocrf r%u,%u\n", rD_addr, CRM);
sewardje9d8a262009-07-01 08:06:34 +00006953 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_CR ),
6954 /* Signed */False) );
sewardj72aefb22006-03-01 18:58:39 +00006955 break;
6956 }
6957 /* not decodable */
6958 return False;
carll0c74bb52013-08-12 18:01:40 +00006959
cerionb85e8bb2005-02-16 08:54:33 +00006960 /* XFX-Form */
cerione9d361a2005-03-04 17:35:29 +00006961 case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
cerionb85e8bb2005-02-16 08:54:33 +00006962
cerion76de5cf2005-11-18 18:25:12 +00006963 switch (SPR) { // Choose a register...
ceriond953ebb2005-11-29 13:27:20 +00006964 case 0x1:
6965 DIP("mfxer r%u\n", rD_addr);
sewardje9d8a262009-07-01 08:06:34 +00006966 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_XER ),
6967 /* Signed */False) );
ceriond953ebb2005-11-29 13:27:20 +00006968 break;
6969 case 0x8:
6970 DIP("mflr r%u\n", rD_addr);
6971 putIReg( rD_addr, getGST( PPC_GST_LR ) );
6972 break;
6973 case 0x9:
6974 DIP("mfctr r%u\n", rD_addr);
6975 putIReg( rD_addr, getGST( PPC_GST_CTR ) );
6976 break;
carll8943d022013-10-02 16:25:57 +00006977 case 0x80: // 128
6978 DIP("mfspr r%u (TFHAR)\n", rD_addr);
6979 putIReg( rD_addr, getGST( PPC_GST_TFHAR) );
6980 break;
6981 case 0x81: // 129
6982 DIP("mfspr r%u (TFIAR)\n", rD_addr);
6983 putIReg( rD_addr, getGST( PPC_GST_TFIAR) );
6984 break;
6985 case 0x82: // 130
6986 DIP("mfspr r%u (TEXASR)\n", rD_addr);
6987 putIReg( rD_addr, getGST( PPC_GST_TEXASR) );
6988 break;
ceriond953ebb2005-11-29 13:27:20 +00006989 case 0x100:
6990 DIP("mfvrsave r%u\n", rD_addr);
sewardje9d8a262009-07-01 08:06:34 +00006991 putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_VRSAVE ),
6992 /* Signed */False) );
ceriond953ebb2005-11-29 13:27:20 +00006993 break;
sewardjaca070a2006-10-17 00:28:22 +00006994
6995 case 0x103:
6996 DIP("mfspr r%u, SPRG3(readonly)\n", rD_addr);
6997 putIReg( rD_addr, getGST( PPC_GST_SPRG3_RO ) );
6998 break;
6999
sewardjabb321c2006-12-27 18:39:46 +00007000 /* Even a lowly PPC7400 can run the associated helper, so no
7001 obvious need for feature testing at this point. */
7002 case 268 /* 0x10C */:
7003 case 269 /* 0x10D */: {
7004 UInt arg = SPR==268 ? 0 : 1;
7005 IRTemp val = newTemp(Ity_I32);
7006 IRExpr** args = mkIRExprVec_1( mkU32(arg) );
7007 IRDirty* d = unsafeIRDirty_1_N(
7008 val,
7009 0/*regparms*/,
7010 "ppc32g_dirtyhelper_MFSPR_268_269",
7011 fnptr_to_fnentry
7012 (vbi, &ppc32g_dirtyhelper_MFSPR_268_269),
7013 args
7014 );
7015 /* execute the dirty call, dumping the result in val. */
7016 stmt( IRStmt_Dirty(d) );
sewardj37b2ee82009-08-02 14:35:45 +00007017 putIReg( rD_addr,
7018 mkWidenFrom32(ty, mkexpr(val), False/*unsigned*/) );
7019 DIP("mfspr r%u,%u", rD_addr, (UInt)SPR);
7020 break;
7021 }
7022
7023 /* Again, runs natively on PPC7400 (7447, really). Not
7024 bothering with a feature test. */
7025 case 287: /* 0x11F */ {
7026 IRTemp val = newTemp(Ity_I32);
7027 IRExpr** args = mkIRExprVec_0();
7028 IRDirty* d = unsafeIRDirty_1_N(
7029 val,
7030 0/*regparms*/,
7031 "ppc32g_dirtyhelper_MFSPR_287",
7032 fnptr_to_fnentry
7033 (vbi, &ppc32g_dirtyhelper_MFSPR_287),
7034 args
7035 );
7036 /* execute the dirty call, dumping the result in val. */
7037 stmt( IRStmt_Dirty(d) );
7038 putIReg( rD_addr,
7039 mkWidenFrom32(ty, mkexpr(val), False/*unsigned*/) );
sewardjabb321c2006-12-27 18:39:46 +00007040 DIP("mfspr r%u,%u", rD_addr, (UInt)SPR);
7041 break;
7042 }
7043
ceriond953ebb2005-11-29 13:27:20 +00007044 default:
cerion5b2325f2005-12-23 00:55:09 +00007045 vex_printf("dis_proc_ctl(ppc)(mfspr,SPR)(0x%x)\n", SPR);
ceriond953ebb2005-11-29 13:27:20 +00007046 return False;
cerionb85e8bb2005-02-16 08:54:33 +00007047 }
7048 break;
7049
sewardj73a91972005-09-06 10:25:46 +00007050 case 0x173: { // mftb (Move from Time Base, PPC32 p475)
7051 IRTemp val = newTemp(Ity_I64);
7052 IRExpr** args = mkIRExprVec_0();
cerion4c4f5ef2006-01-02 14:41:50 +00007053 IRDirty* d = unsafeIRDirty_1_N(
7054 val,
7055 0/*regparms*/,
7056 "ppcg_dirtyhelper_MFTB",
sewardjdd40fdf2006-12-24 02:20:24 +00007057 fnptr_to_fnentry(vbi, &ppcg_dirtyhelper_MFTB),
cerion4c4f5ef2006-01-02 14:41:50 +00007058 args );
sewardj73a91972005-09-06 10:25:46 +00007059 /* execute the dirty call, dumping the result in val. */
7060 stmt( IRStmt_Dirty(d) );
7061
7062 switch (TBR) {
ceriond953ebb2005-11-29 13:27:20 +00007063 case 269:
ceriond953ebb2005-11-29 13:27:20 +00007064 DIP("mftbu r%u", rD_addr);
cerion2831b002005-11-30 19:55:22 +00007065 putIReg( rD_addr,
sewardje9d8a262009-07-01 08:06:34 +00007066 mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(val)),
7067 /* Signed */False) );
ceriond953ebb2005-11-29 13:27:20 +00007068 break;
7069 case 268:
ceriond953ebb2005-11-29 13:27:20 +00007070 DIP("mftb r%u", rD_addr);
cerion2831b002005-11-30 19:55:22 +00007071 putIReg( rD_addr, (mode64) ? mkexpr(val) :
7072 unop(Iop_64to32, mkexpr(val)) );
ceriond953ebb2005-11-29 13:27:20 +00007073 break;
7074 default:
7075 return False; /* illegal instruction */
sewardj73a91972005-09-06 10:25:46 +00007076 }
7077 break;
7078 }
7079
sewardj72aefb22006-03-01 18:58:39 +00007080 case 0x090: {
7081 // b20==0: mtcrf (Move to Cond Register Fields, PPC32 p477)
7082 // b20==1: mtocrf (Move to One Cond Reg Field)
cerionedf7fc52005-11-18 20:57:41 +00007083 Int cr;
7084 UChar shft;
sewardj72aefb22006-03-01 18:58:39 +00007085 if (b11 != 0)
cerionb85e8bb2005-02-16 08:54:33 +00007086 return False;
sewardj72aefb22006-03-01 18:58:39 +00007087 if (b20 == 1) {
7088 /* ppc64 v2.02 spec says mtocrf gives undefined outcome if >
7089 1 field is written. It seems more robust to decline to
7090 decode the insn if so. */
7091 switch (CRM) {
7092 case 0x01: case 0x02: case 0x04: case 0x08:
7093 case 0x10: case 0x20: case 0x40: case 0x80:
7094 break;
7095 default:
7096 return False;
7097 }
cerionb85e8bb2005-02-16 08:54:33 +00007098 }
sewardj72aefb22006-03-01 18:58:39 +00007099 DIP("%s 0x%x,r%u\n", b20==1 ? "mtocrf" : "mtcrf",
7100 CRM, rS_addr);
cerionedf7fc52005-11-18 20:57:41 +00007101 /* Write to each field specified by CRM */
7102 for (cr = 0; cr < 8; cr++) {
7103 if ((CRM & (1 << (7-cr))) == 0)
7104 continue;
7105 shft = 4*(7-cr);
ceriond953ebb2005-11-29 13:27:20 +00007106 putGST_field( PPC_GST_CR,
cerion2831b002005-11-30 19:55:22 +00007107 binop(Iop_Shr32,
sewardje9d8a262009-07-01 08:06:34 +00007108 mkNarrowTo32(ty, mkexpr(rS)),
cerion2831b002005-11-30 19:55:22 +00007109 mkU8(shft)), cr );
cerionedf7fc52005-11-18 20:57:41 +00007110 }
cerionb85e8bb2005-02-16 08:54:33 +00007111 break;
cerionedf7fc52005-11-18 20:57:41 +00007112 }
cerione9d361a2005-03-04 17:35:29 +00007113
7114 case 0x1D3: // mtspr (Move to Special-Purpose Register, PPC32 p483)
cerionb85e8bb2005-02-16 08:54:33 +00007115
cerion76de5cf2005-11-18 18:25:12 +00007116 switch (SPR) { // Choose a register...
ceriond953ebb2005-11-29 13:27:20 +00007117 case 0x1:
7118 DIP("mtxer r%u\n", rS_addr);
sewardje9d8a262009-07-01 08:06:34 +00007119 putGST( PPC_GST_XER, mkNarrowTo32(ty, mkexpr(rS)) );
ceriond953ebb2005-11-29 13:27:20 +00007120 break;
7121 case 0x8:
7122 DIP("mtlr r%u\n", rS_addr);
7123 putGST( PPC_GST_LR, mkexpr(rS) );
7124 break;
7125 case 0x9:
7126 DIP("mtctr r%u\n", rS_addr);
7127 putGST( PPC_GST_CTR, mkexpr(rS) );
7128 break;
7129 case 0x100:
7130 DIP("mtvrsave r%u\n", rS_addr);
sewardje9d8a262009-07-01 08:06:34 +00007131 putGST( PPC_GST_VRSAVE, mkNarrowTo32(ty, mkexpr(rS)) );
ceriond953ebb2005-11-29 13:27:20 +00007132 break;
carll8943d022013-10-02 16:25:57 +00007133 case 0x80: // 128
7134 DIP("mtspr r%u (TFHAR)\n", rS_addr);
7135 putGST( PPC_GST_TFHAR, mkexpr(rS) );
7136 break;
7137 case 0x81: // 129
7138 DIP("mtspr r%u (TFIAR)\n", rS_addr);
7139 putGST( PPC_GST_TFIAR, mkexpr(rS) );
7140 break;
7141 case 0x82: // 130
7142 DIP("mtspr r%u (TEXASR)\n", rS_addr);
7143 putGST( PPC_GST_TEXASR, mkexpr(rS) );
7144 break;
ceriond953ebb2005-11-29 13:27:20 +00007145 default:
cerion5b2325f2005-12-23 00:55:09 +00007146 vex_printf("dis_proc_ctl(ppc)(mtspr,SPR)(%u)\n", SPR);
ceriond953ebb2005-11-29 13:27:20 +00007147 return False;
cerionb85e8bb2005-02-16 08:54:33 +00007148 }
7149 break;
carll0c74bb52013-08-12 18:01:40 +00007150
7151 case 0x33: // mfvsrd
7152 {
7153 UChar XS = ifieldRegXS( theInstr );
7154 UChar rA_addr = ifieldRegA(theInstr);
7155 IRExpr * high64;
7156 IRTemp vS = newTemp( Ity_V128 );
7157 DIP("mfvsrd r%u,vsr%d\n", rA_addr, (UInt)XS);
7158
7159 /* XS = SX || S
7160 * For SX=0, mfvsrd is treated as a Floating-Point
7161 * instruction in terms of resource availability.
7162 * For SX=1, mfvsrd is treated as a Vector instruction in
7163 * terms of resource availability.
carll78850ae2013-09-10 18:46:40 +00007164 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
carll0c74bb52013-08-12 18:01:40 +00007165 */
7166 assign( vS, getVSReg( XS ) );
7167 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
7168 putIReg( rA_addr, (mode64) ? high64 :
7169 unop( Iop_64to32, high64 ) );
7170 break;
7171 }
7172
carll78850ae2013-09-10 18:46:40 +00007173 case 0x73: // mfvsrwz
7174 {
7175 UChar XS = ifieldRegXS( theInstr );
7176 UChar rA_addr = ifieldRegA(theInstr);
7177 IRExpr * high64;
7178 IRTemp vS = newTemp( Ity_V128 );
7179 DIP("mfvsrwz r%u,vsr%d\n", rA_addr, (UInt)XS);
7180 /* XS = SX || S
7181 * For SX=0, mfvsrwz is treated as a Floating-Point
7182 * instruction in terms of resource availability.
7183 * For SX=1, mfvsrwz is treated as a Vector instruction in
7184 * terms of resource availability.
7185 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
7186 */
7187
7188 assign( vS, getVSReg( XS ) );
7189 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
7190 /* move value to the destination setting the upper 32-bits to zero */
7191 putIReg( rA_addr, (mode64) ?
7192 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) :
7193 unop( Iop_64to32,
7194 binop( Iop_And64, high64, mkU64( 0xFFFFFFFF ) ) ) );
7195 break;
7196 }
7197
carll0c74bb52013-08-12 18:01:40 +00007198 case 0xB3: // mtvsrd
7199 {
7200 UChar XT = ifieldRegXT( theInstr );
7201 UChar rA_addr = ifieldRegA(theInstr);
7202 IRTemp rA = newTemp(ty);
7203 DIP("mtvsrd vsr%d,r%u\n", (UInt)XT, rA_addr);
7204 /* XS = SX || S
7205 * For SX=0, mfvsrd is treated as a Floating-Point
7206 * instruction in terms of resource availability.
7207 * For SX=1, mfvsrd is treated as a Vector instruction in
7208 * terms of resource availability.
carll78850ae2013-09-10 18:46:40 +00007209 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
carll0c74bb52013-08-12 18:01:40 +00007210 */
7211 assign( rA, getIReg(rA_addr) );
7212
7213 if (mode64)
7214 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( rA ), mkU64( 0 ) ) );
7215 else
7216 putVSReg( XT, binop( Iop_64HLtoV128,
7217 binop( Iop_32HLto64,
7218 mkU32( 0 ),
7219 mkexpr( rA ) ),
7220 mkU64( 0 ) ) );
7221 break;
7222 }
7223
7224 case 0xD3: // mtvsrwa
7225 {
7226 UChar XT = ifieldRegXT( theInstr );
7227 UChar rA_addr = ifieldRegA(theInstr);
7228 IRTemp rA = newTemp( Ity_I32 );
7229 DIP("mtvsrwa vsr%d,r%u\n", (UInt)XT, rA_addr);
7230 /* XS = SX || S
7231 * For SX=0, mtvsrwa is treated as a Floating-Point
7232 * instruction in terms of resource availability.
7233 * For SX=1, mtvsrwa is treated as a Vector instruction in
7234 * terms of resource availability.
carll78850ae2013-09-10 18:46:40 +00007235 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
carll0c74bb52013-08-12 18:01:40 +00007236 */
7237 if (mode64)
7238 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
7239 else
7240 assign( rA, getIReg(rA_addr) );
7241
7242 putVSReg( XT, binop( Iop_64HLtoV128,
7243 unop( Iop_32Sto64, mkexpr( rA ) ),
7244 mkU64( 0 ) ) );
7245 break;
7246 }
7247
carll78850ae2013-09-10 18:46:40 +00007248 case 0xF3: // mtvsrwz
7249 {
7250 UChar XT = ifieldRegXT( theInstr );
7251 UChar rA_addr = ifieldRegA(theInstr);
7252 IRTemp rA = newTemp( Ity_I32 );
7253 DIP("mtvsrwz vsr%d,r%u\n", rA_addr, (UInt)XT);
7254 /* XS = SX || S
7255 * For SX=0, mtvsrwz is treated as a Floating-Point
7256 * instruction in terms of resource availability.
7257 * For SX=1, mtvsrwz is treated as a Vector instruction in
7258 * terms of resource availability.
7259 * FIXME: NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
7260 */
7261 if (mode64)
7262 assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
7263 else
7264 assign( rA, getIReg(rA_addr) );
7265
7266 putVSReg( XT, binop( Iop_64HLtoV128,
7267 binop( Iop_32HLto64, mkU32( 0 ), mkexpr ( rA ) ),
7268 mkU64( 0 ) ) );
7269 break;
7270 }
7271
cerionb85e8bb2005-02-16 08:54:33 +00007272 default:
cerion5b2325f2005-12-23 00:55:09 +00007273 vex_printf("dis_proc_ctl(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00007274 return False;
7275 }
7276 return True;
cerion8c3adda2005-01-31 11:54:05 +00007277}
7278
7279
cerion3d870a32005-03-18 12:23:33 +00007280/*
7281 Cache Management Instructions
7282*/
sewardjd94b73a2005-06-30 12:08:48 +00007283static Bool dis_cache_manage ( UInt theInstr,
sewardj9e6491a2005-07-02 19:24:10 +00007284 DisResult* dres,
sewardjd94b73a2005-06-30 12:08:48 +00007285 VexArchInfo* guest_archinfo )
cerion8c3adda2005-01-31 11:54:05 +00007286{
cerionb85e8bb2005-02-16 08:54:33 +00007287 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00007288 UChar opc1 = ifieldOPC(theInstr);
7289 UChar b21to25 = ifieldRegDS(theInstr);
7290 UChar rA_addr = ifieldRegA(theInstr);
7291 UChar rB_addr = ifieldRegB(theInstr);
7292 UInt opc2 = ifieldOPClo10(theInstr);
7293 UChar b0 = ifieldBIT0(theInstr);
florian9138b172013-08-03 19:36:55 +00007294 UInt lineszB = guest_archinfo->ppc_icache_line_szB;
sewardje971c6a2010-09-03 15:49:57 +00007295 Bool is_dcbzl = False;
ceriond953ebb2005-11-29 13:27:20 +00007296
7297 IRType ty = mode64 ? Ity_I64 : Ity_I32;
cerion094d1392005-06-20 13:45:57 +00007298
carllb77db0e2013-09-05 19:47:40 +00007299 // Check for valid hint values for dcbt and dcbtst as currently described in
7300 // ISA 2.07. If valid, then we simply set b21to25 to zero since we have no
7301 // means of modeling the hint anyway.
7302 if (opc1 == 0x1F && ((opc2 == 0x116) || (opc2 == 0xF6))) {
carll9708b6a2013-09-06 16:49:42 +00007303 if (b21to25 == 0x10 || b21to25 < 0x10)
carllb77db0e2013-09-05 19:47:40 +00007304 b21to25 = 0;
sewardj6be67232006-01-24 19:00:05 +00007305 }
carll9708b6a2013-09-06 16:49:42 +00007306 if (opc1 == 0x1F && opc2 == 0x116 && b21to25 == 0x11)
carllb77db0e2013-09-05 19:47:40 +00007307 b21to25 = 0;
7308
sewardje971c6a2010-09-03 15:49:57 +00007309 if (opc1 == 0x1F && opc2 == 0x3F6) { // dcbz
7310 if (b21to25 == 1) {
7311 is_dcbzl = True;
7312 b21to25 = 0;
7313 if (!(guest_archinfo->ppc_dcbzl_szB)) {
7314 vex_printf("dis_cache_manage(ppc)(dcbzl not supported by host)\n");
7315 return False;
7316 }
7317 }
7318 }
sewardj6be67232006-01-24 19:00:05 +00007319
cerionb85e8bb2005-02-16 08:54:33 +00007320 if (opc1 != 0x1F || b21to25 != 0 || b0 != 0) {
sewardj6be67232006-01-24 19:00:05 +00007321 if (0) vex_printf("dis_cache_manage %d %d %d\n",
7322 (Int)opc1, (Int)b21to25, (Int)b0);
cerion5b2325f2005-12-23 00:55:09 +00007323 vex_printf("dis_cache_manage(ppc)(opc1|b21to25|b0)\n");
cerionb85e8bb2005-02-16 08:54:33 +00007324 return False;
7325 }
sewardjd94b73a2005-06-30 12:08:48 +00007326
7327 /* stay sane .. */
sewardj2691a612013-10-14 11:40:24 +00007328 vassert(lineszB == 16 || lineszB == 32 || lineszB == 64 || lineszB == 128);
cerionb85e8bb2005-02-16 08:54:33 +00007329
7330 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00007331//zz case 0x2F6: // dcba (Data Cache Block Allocate, PPC32 p380)
7332//zz vassert(0); /* AWAITING TEST CASE */
ceriond953ebb2005-11-29 13:27:20 +00007333//zz DIP("dcba r%u,r%u\n", rA_addr, rB_addr);
cerion5b2325f2005-12-23 00:55:09 +00007334//zz if (0) vex_printf("vex ppc->IR: kludged dcba\n");
sewardjb51f0f42005-07-18 11:38:02 +00007335//zz break;
sewardj20ef5472005-07-21 14:48:31 +00007336
7337 case 0x056: // dcbf (Data Cache Block Flush, PPC32 p382)
ceriond953ebb2005-11-29 13:27:20 +00007338 DIP("dcbf r%u,r%u\n", rA_addr, rB_addr);
sewardj20ef5472005-07-21 14:48:31 +00007339 /* nop as far as vex is concerned */
sewardj20ef5472005-07-21 14:48:31 +00007340 break;
cerionb85e8bb2005-02-16 08:54:33 +00007341
cerione9d361a2005-03-04 17:35:29 +00007342 case 0x036: // dcbst (Data Cache Block Store, PPC32 p384)
ceriond953ebb2005-11-29 13:27:20 +00007343 DIP("dcbst r%u,r%u\n", rA_addr, rB_addr);
sewardjb51f0f42005-07-18 11:38:02 +00007344 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00007345 break;
cerion8c3adda2005-01-31 11:54:05 +00007346
cerione9d361a2005-03-04 17:35:29 +00007347 case 0x116: // dcbt (Data Cache Block Touch, PPC32 p385)
ceriond953ebb2005-11-29 13:27:20 +00007348 DIP("dcbt r%u,r%u\n", rA_addr, rB_addr);
sewardjb51f0f42005-07-18 11:38:02 +00007349 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00007350 break;
7351
cerione9d361a2005-03-04 17:35:29 +00007352 case 0x0F6: // dcbtst (Data Cache Block Touch for Store, PPC32 p386)
ceriond953ebb2005-11-29 13:27:20 +00007353 DIP("dcbtst r%u,r%u\n", rA_addr, rB_addr);
sewardjb51f0f42005-07-18 11:38:02 +00007354 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00007355 break;
7356
cerion094d1392005-06-20 13:45:57 +00007357 case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
sewardje971c6a2010-09-03 15:49:57 +00007358 // dcbzl (Data Cache Block Clear to Zero Long, bug#135264)
sewardjd94b73a2005-06-30 12:08:48 +00007359 /* Clear all bytes in cache block at (rA|0) + rB. */
cerion2831b002005-11-30 19:55:22 +00007360 IRTemp EA = newTemp(ty);
7361 IRTemp addr = newTemp(ty);
cerion094d1392005-06-20 13:45:57 +00007362 IRExpr* irx_addr;
cerion094d1392005-06-20 13:45:57 +00007363 UInt i;
sewardje971c6a2010-09-03 15:49:57 +00007364 UInt clearszB;
7365 if (is_dcbzl) {
7366 clearszB = guest_archinfo->ppc_dcbzl_szB;
7367 DIP("dcbzl r%u,r%u\n", rA_addr, rB_addr);
7368 }
7369 else {
7370 clearszB = guest_archinfo->ppc_dcbz_szB;
7371 DIP("dcbz r%u,r%u\n", rA_addr, rB_addr);
7372 }
sewardjcb1f68e2005-12-30 03:39:14 +00007373
ceriond953ebb2005-11-29 13:27:20 +00007374 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
cerion094d1392005-06-20 13:45:57 +00007375
cerion2831b002005-11-30 19:55:22 +00007376 if (mode64) {
7377 /* Round EA down to the start of the containing block. */
7378 assign( addr, binop( Iop_And64,
7379 mkexpr(EA),
sewardje971c6a2010-09-03 15:49:57 +00007380 mkU64( ~((ULong)clearszB-1) )) );
cerion2831b002005-11-30 19:55:22 +00007381
sewardje971c6a2010-09-03 15:49:57 +00007382 for (i = 0; i < clearszB / 8; i++) {
cerion2831b002005-11-30 19:55:22 +00007383 irx_addr = binop( Iop_Add64, mkexpr(addr), mkU64(i*8) );
carll1f5fe1f2014-08-07 23:25:23 +00007384 store( irx_addr, mkU64(0) );
cerion2831b002005-11-30 19:55:22 +00007385 }
7386 } else {
7387 /* Round EA down to the start of the containing block. */
7388 assign( addr, binop( Iop_And32,
7389 mkexpr(EA),
sewardje971c6a2010-09-03 15:49:57 +00007390 mkU32( ~(clearszB-1) )) );
cerion2831b002005-11-30 19:55:22 +00007391
sewardje971c6a2010-09-03 15:49:57 +00007392 for (i = 0; i < clearszB / 4; i++) {
cerion2831b002005-11-30 19:55:22 +00007393 irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
carll1f5fe1f2014-08-07 23:25:23 +00007394 store( irx_addr, mkU32(0) );
cerion2831b002005-11-30 19:55:22 +00007395 }
cerion094d1392005-06-20 13:45:57 +00007396 }
cerionb85e8bb2005-02-16 08:54:33 +00007397 break;
cerion094d1392005-06-20 13:45:57 +00007398 }
cerion8c3adda2005-01-31 11:54:05 +00007399
sewardj7ce9d152005-03-15 16:54:13 +00007400 case 0x3D6: {
7401 // icbi (Instruction Cache Block Invalidate, PPC32 p431)
7402 /* Invalidate all translations containing code from the cache
sewardjd94b73a2005-06-30 12:08:48 +00007403 block at (rA|0) + rB. */
ceriond953ebb2005-11-29 13:27:20 +00007404 IRTemp EA = newTemp(ty);
7405 IRTemp addr = newTemp(ty);
7406 DIP("icbi r%u,r%u\n", rA_addr, rB_addr);
7407 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
sewardj7ce9d152005-03-15 16:54:13 +00007408
cerion2831b002005-11-30 19:55:22 +00007409 /* Round EA down to the start of the containing block. */
7410 assign( addr, binop( mkSzOp(ty, Iop_And8),
ceriond953ebb2005-11-29 13:27:20 +00007411 mkexpr(EA),
cerion2831b002005-11-30 19:55:22 +00007412 mkSzImm(ty, ~(((ULong)lineszB)-1) )) );
sewardj05f5e012014-05-04 10:52:11 +00007413 putGST( PPC_GST_CMSTART, mkexpr(addr) );
7414 putGST( PPC_GST_CMLEN, mkSzImm(ty, lineszB) );
sewardj7ce9d152005-03-15 16:54:13 +00007415
sewardja8078f62005-03-15 18:27:40 +00007416 /* be paranoid ... */
sewardjc4356f02007-11-09 21:15:04 +00007417 stmt( IRStmt_MBE(Imbe_Fence) );
sewardja8078f62005-03-15 18:27:40 +00007418
sewardj3dee8492012-04-20 00:13:28 +00007419 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()));
sewardj05f5e012014-05-04 10:52:11 +00007420 dres->jk_StopHere = Ijk_InvalICache;
sewardj3dee8492012-04-20 00:13:28 +00007421 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00007422 break;
sewardj7ce9d152005-03-15 16:54:13 +00007423 }
cerion8c3adda2005-01-31 11:54:05 +00007424
cerionb85e8bb2005-02-16 08:54:33 +00007425 default:
cerion5b2325f2005-12-23 00:55:09 +00007426 vex_printf("dis_cache_manage(ppc)(opc2)\n");
cerionb85e8bb2005-02-16 08:54:33 +00007427 return False;
7428 }
7429 return True;
cerion8c3adda2005-01-31 11:54:05 +00007430}
7431
7432
sewardje14bb9f2005-07-22 09:39:02 +00007433/*------------------------------------------------------------*/
7434/*--- Floating Point Helpers ---*/
7435/*------------------------------------------------------------*/
7436
sewardje14bb9f2005-07-22 09:39:02 +00007437/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
7438/* Produces a value in 0 .. 3, which is encoded as per the type
cerion5b2325f2005-12-23 00:55:09 +00007439 IRRoundingMode. PPCRoundingMode encoding is different to
sewardje14bb9f2005-07-22 09:39:02 +00007440 IRRoundingMode, so need to map it.
7441*/
sewardjb183b852006-02-03 16:08:03 +00007442static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode ( void )
sewardje14bb9f2005-07-22 09:39:02 +00007443{
7444/*
7445 rounding mode | PPC | IR
7446 ------------------------
7447 to nearest | 00 | 00
7448 to zero | 01 | 11
7449 to +infinity | 10 | 10
7450 to -infinity | 11 | 01
7451*/
7452 IRTemp rm_PPC32 = newTemp(Ity_I32);
ceriond953ebb2005-11-29 13:27:20 +00007453 assign( rm_PPC32, getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN ) );
sewardje14bb9f2005-07-22 09:39:02 +00007454
7455 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
sewardjb183b852006-02-03 16:08:03 +00007456 return binop( Iop_Xor32,
7457 mkexpr(rm_PPC32),
7458 binop( Iop_And32,
7459 binop(Iop_Shl32, mkexpr(rm_PPC32), mkU8(1)),
7460 mkU32(2) ));
sewardje14bb9f2005-07-22 09:39:02 +00007461}
cerion094d1392005-06-20 13:45:57 +00007462
sewardjc6bbd472012-04-02 10:20:48 +00007463/* The DFP IR rounding modes were chosen such that the existing PPC to IR
7464 * mapping would still work with the extended three bit DFP rounding
7465 * mode designator.
7466
7467 * rounding mode | PPC | IR
7468 * -----------------------------------------------
7469 * to nearest, ties to even | 000 | 000
7470 * to zero | 001 | 011
7471 * to +infinity | 010 | 010
7472 * to -infinity | 011 | 001
7473 * to nearest, ties away from 0 | 100 | 100
7474 * to nearest, ties toward 0 | 101 | 111
7475 * to away from 0 | 110 | 110
7476 * to prepare for shorter precision | 111 | 101
7477 */
7478static IRExpr* /* :: Ity_I32 */ get_IR_roundingmode_DFP( void )
7479{
7480 IRTemp rm_PPC32 = newTemp( Ity_I32 );
7481 assign( rm_PPC32, getGST_masked_upper( PPC_GST_FPSCR, MASK_FPSCR_DRN ) );
7482
7483 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
7484 return binop( Iop_Xor32,
7485 mkexpr( rm_PPC32 ),
7486 binop( Iop_And32,
7487 binop( Iop_Shl32, mkexpr( rm_PPC32 ), mkU8( 1 ) ),
7488 mkU32( 2 ) ) );
7489}
cerion094d1392005-06-20 13:45:57 +00007490
sewardj2bcdd652012-07-14 08:22:13 +00007491#define NANmaskSingle 0x7F800000
7492#define NANmaskDouble 0x7FF00000
7493
7494static IRExpr * Check_NaN( IRExpr * value, IRExpr * Hi32Mask )
7495{
7496 IRTemp exp_zero = newTemp(Ity_I8);
7497 IRTemp frac_mask = newTemp(Ity_I32);
7498 IRTemp frac_not_zero = newTemp(Ity_I8);
7499
7500 /* Check if the result is QNAN or SNAN and not +infinity or -infinity.
7501 * The input value is always 64-bits, for single precision values, the
7502 * lower 32 bits must be zero.
7503 *
7504 * Single Pricision
7505 * [62:54] exponent field is equal to 0xFF for NAN and Infinity.
7506 * [53:32] fraction field is zero for Infinity and non-zero for NAN
7507 * [31:0] unused for single precision representation
7508 *
7509 * Double Pricision
7510 * [62:51] exponent field is equal to 0xFF for NAN and Infinity.
7511 * [50:0] fraction field is zero for Infinity and non-zero for NAN
7512 *
7513 * Returned result is a U32 value of 0xFFFFFFFF for NaN and 0 otherwise.
7514 */
7515 assign( frac_mask, unop( Iop_Not32,
7516 binop( Iop_Or32,
7517 mkU32( 0x80000000ULL ), Hi32Mask) ) );
7518
7519 assign( exp_zero,
7520 unop( Iop_1Sto8,
7521 binop( Iop_CmpEQ32,
7522 binop( Iop_And32,
7523 unop( Iop_64HIto32,
7524 unop( Iop_ReinterpF64asI64,
7525 value ) ),
7526 Hi32Mask ),
7527 Hi32Mask ) ) );
7528 assign( frac_not_zero,
7529 binop( Iop_Or8,
7530 unop( Iop_1Sto8,
7531 binop( Iop_CmpNE32,
7532 binop( Iop_And32,
7533 unop( Iop_64HIto32,
7534 unop( Iop_ReinterpF64asI64,
7535 value ) ),
7536 mkexpr( frac_mask ) ),
7537 mkU32( 0x0 ) ) ),
7538 unop( Iop_1Sto8,
7539 binop( Iop_CmpNE32,
7540 binop( Iop_And32,
7541 unop( Iop_64to32,
7542 unop( Iop_ReinterpF64asI64,
7543 value ) ),
7544 mkU32( 0xFFFFFFFF ) ),
7545 mkU32( 0x0 ) ) ) ) );
7546 return unop( Iop_8Sto32,
7547 binop( Iop_And8,
7548 mkexpr( exp_zero ),
7549 mkexpr( frac_not_zero ) ) );
7550}
7551
7552static IRExpr * Complement_non_NaN( IRExpr * value, IRExpr * nan_mask )
7553{
7554 /* This function will only complement the 64-bit floating point value if it
7555 * is not Nan. NaN is not a signed value. Need to do computations using
7556 * 32-bit operands to ensure it will run in 32-bit mode.
7557 */
7558 return binop( Iop_32HLto64,
7559 binop( Iop_Or32,
7560 binop( Iop_And32,
7561 nan_mask,
7562 unop( Iop_64HIto32,
7563 unop( Iop_ReinterpF64asI64,
7564 value ) ) ),
7565 binop( Iop_And32,
7566 unop( Iop_Not32,
7567 nan_mask ),
7568 unop( Iop_64HIto32,
7569 unop( Iop_ReinterpF64asI64,
7570 unop( Iop_NegF64,
7571 value ) ) ) ) ),
7572 unop( Iop_64to32,
7573 unop( Iop_ReinterpF64asI64, value ) ) );
7574}
7575
cerion3d870a32005-03-18 12:23:33 +00007576/*------------------------------------------------------------*/
7577/*--- Floating Point Instruction Translation ---*/
7578/*------------------------------------------------------------*/
7579
7580/*
7581 Floating Point Load Instructions
7582*/
7583static Bool dis_fp_load ( UInt theInstr )
7584{
cerion76de5cf2005-11-18 18:25:12 +00007585 /* X-Form, D-Form */
7586 UChar opc1 = ifieldOPC(theInstr);
7587 UChar frD_addr = ifieldRegDS(theInstr);
7588 UChar rA_addr = ifieldRegA(theInstr);
7589 UChar rB_addr = ifieldRegB(theInstr);
7590 UInt opc2 = ifieldOPClo10(theInstr);
7591 UChar b0 = ifieldBIT0(theInstr);
cerion2831b002005-11-30 19:55:22 +00007592 UInt uimm16 = ifieldUIMM16(theInstr);
cerion094d1392005-06-20 13:45:57 +00007593
cerion2831b002005-11-30 19:55:22 +00007594 Int simm16 = extend_s_16to32(uimm16);
7595 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7596 IRTemp EA = newTemp(ty);
7597 IRTemp rA = newTemp(ty);
7598 IRTemp rB = newTemp(ty);
sewardj7e846302010-09-03 23:37:02 +00007599 IRTemp iHi = newTemp(Ity_I32);
7600 IRTemp iLo = newTemp(Ity_I32);
cerion094d1392005-06-20 13:45:57 +00007601
7602 assign( rA, getIReg(rA_addr) );
7603 assign( rB, getIReg(rB_addr) );
ceriond953ebb2005-11-29 13:27:20 +00007604
sewardjb183b852006-02-03 16:08:03 +00007605 /* These are completely straightforward from a rounding and status
7606 bits perspective: no rounding involved and no funny status or CR
7607 bits affected. */
cerion3d870a32005-03-18 12:23:33 +00007608
sewardjb183b852006-02-03 16:08:03 +00007609 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00007610 case 0x30: // lfs (Load Float Single, PPC32 p441)
ceriond953ebb2005-11-29 13:27:20 +00007611 DIP("lfs fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7612 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
cerion5b2325f2005-12-23 00:55:09 +00007613 putFReg( frD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00007614 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
sewardje14bb9f2005-07-22 09:39:02 +00007615 break;
7616
cerion5b2325f2005-12-23 00:55:09 +00007617 case 0x31: // lfsu (Load Float Single, Update, PPC32 p442)
sewardjb183b852006-02-03 16:08:03 +00007618 if (rA_addr == 0)
cerion729edb72005-12-02 16:03:46 +00007619 return False;
cerion729edb72005-12-02 16:03:46 +00007620 DIP("lfsu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7621 assign( EA, ea_rA_simm(rA_addr, simm16) );
cerion5b2325f2005-12-23 00:55:09 +00007622 putFReg( frD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00007623 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
cerion729edb72005-12-02 16:03:46 +00007624 putIReg( rA_addr, mkexpr(EA) );
7625 break;
cerion094d1392005-06-20 13:45:57 +00007626
7627 case 0x32: // lfd (Load Float Double, PPC32 p437)
ceriond953ebb2005-11-29 13:27:20 +00007628 DIP("lfd fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7629 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007630 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
cerion094d1392005-06-20 13:45:57 +00007631 break;
cerion3d870a32005-03-18 12:23:33 +00007632
cerion5b2325f2005-12-23 00:55:09 +00007633 case 0x33: // lfdu (Load Float Double, Update, PPC32 p438)
sewardjb183b852006-02-03 16:08:03 +00007634 if (rA_addr == 0)
sewardj0e2cc672005-07-29 21:58:51 +00007635 return False;
ceriond953ebb2005-11-29 13:27:20 +00007636 DIP("lfdu fr%u,%d(r%u)\n", frD_addr, simm16, rA_addr);
7637 assign( EA, ea_rA_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007638 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
sewardj0e2cc672005-07-29 21:58:51 +00007639 putIReg( rA_addr, mkexpr(EA) );
7640 break;
sewardje14bb9f2005-07-22 09:39:02 +00007641
7642 case 0x1F:
7643 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00007644 vex_printf("dis_fp_load(ppc)(instr,b0)\n");
sewardje14bb9f2005-07-22 09:39:02 +00007645 return False;
7646 }
7647
7648 switch(opc2) {
ceriond953ebb2005-11-29 13:27:20 +00007649 case 0x217: // lfsx (Load Float Single Indexed, PPC32 p444)
7650 DIP("lfsx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7651 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
7652 putFReg( frD_addr, unop( Iop_F32toF64,
carll1f5fe1f2014-08-07 23:25:23 +00007653 load(Ity_F32, mkexpr(EA))) );
ceriond953ebb2005-11-29 13:27:20 +00007654 break;
7655
cerion5b2325f2005-12-23 00:55:09 +00007656 case 0x237: // lfsux (Load Float Single, Update Indxd, PPC32 p443)
sewardjb183b852006-02-03 16:08:03 +00007657 if (rA_addr == 0)
sewardje14bb9f2005-07-22 09:39:02 +00007658 return False;
ceriond953ebb2005-11-29 13:27:20 +00007659 DIP("lfsux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7660 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
cerion5b2325f2005-12-23 00:55:09 +00007661 putFReg( frD_addr,
carll1f5fe1f2014-08-07 23:25:23 +00007662 unop(Iop_F32toF64, load(Ity_F32, mkexpr(EA))) );
ceriond953ebb2005-11-29 13:27:20 +00007663 putIReg( rA_addr, mkexpr(EA) );
7664 break;
7665
7666 case 0x257: // lfdx (Load Float Double Indexed, PPC32 p440)
7667 DIP("lfdx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7668 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007669 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
ceriond953ebb2005-11-29 13:27:20 +00007670 break;
7671
cerion5b2325f2005-12-23 00:55:09 +00007672 case 0x277: // lfdux (Load Float Double, Update Indxd, PPC32 p439)
sewardjb183b852006-02-03 16:08:03 +00007673 if (rA_addr == 0)
ceriond953ebb2005-11-29 13:27:20 +00007674 return False;
ceriond953ebb2005-11-29 13:27:20 +00007675 DIP("lfdux fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7676 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007677 putFReg( frD_addr, load(Ity_F64, mkexpr(EA)) );
ceriond953ebb2005-11-29 13:27:20 +00007678 putIReg( rA_addr, mkexpr(EA) );
7679 break;
7680
sewardj7e846302010-09-03 23:37:02 +00007681 case 0x357: // lfiwax (Load Float As Integer, Indxd, ISA 2.05 p120)
7682 DIP("lfiwax fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7683 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
carll1f5fe1f2014-08-07 23:25:23 +00007684 assign( iLo, load(Ity_I32, mkexpr(EA)) );
sewardj7e846302010-09-03 23:37:02 +00007685 assign( iHi, binop(Iop_Sub32,
7686 mkU32(0),
7687 binop(Iop_Shr32, mkexpr(iLo), mkU8(31))) );
7688 putFReg( frD_addr, unop(Iop_ReinterpI64asF64,
7689 binop(Iop_32HLto64, mkexpr(iHi), mkexpr(iLo))) );
7690 break;
7691
sewardj66d5ef22011-04-15 11:55:00 +00007692 case 0x377: // lfiwzx (Load floating-point as integer word, zero indexed
7693 {
7694 IRTemp dw = newTemp( Ity_I64 );
7695 DIP("lfiwzx fr%u,r%u,r%u\n", frD_addr, rA_addr, rB_addr);
7696 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
carll1f5fe1f2014-08-07 23:25:23 +00007697 assign( iLo, load(Ity_I32, mkexpr(EA)) );
sewardj66d5ef22011-04-15 11:55:00 +00007698 assign( dw, binop( Iop_32HLto64, mkU32( 0 ), mkexpr( iLo ) ) );
7699 putFReg( frD_addr, unop( Iop_ReinterpI64asF64, mkexpr( dw ) ) );
7700 break;
7701 }
7702
ceriond953ebb2005-11-29 13:27:20 +00007703 default:
cerion5b2325f2005-12-23 00:55:09 +00007704 vex_printf("dis_fp_load(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00007705 return False;
sewardje14bb9f2005-07-22 09:39:02 +00007706 }
7707 break;
cerion3d870a32005-03-18 12:23:33 +00007708
7709 default:
cerion5b2325f2005-12-23 00:55:09 +00007710 vex_printf("dis_fp_load(ppc)(opc1)\n");
cerion3d870a32005-03-18 12:23:33 +00007711 return False;
7712 }
7713 return True;
7714}
7715
7716
7717
7718/*
7719 Floating Point Store Instructions
7720*/
7721static Bool dis_fp_store ( UInt theInstr )
7722{
cerion76de5cf2005-11-18 18:25:12 +00007723 /* X-Form, D-Form */
7724 UChar opc1 = ifieldOPC(theInstr);
7725 UChar frS_addr = ifieldRegDS(theInstr);
7726 UChar rA_addr = ifieldRegA(theInstr);
7727 UChar rB_addr = ifieldRegB(theInstr);
7728 UInt opc2 = ifieldOPClo10(theInstr);
7729 UChar b0 = ifieldBIT0(theInstr);
ceriond953ebb2005-11-29 13:27:20 +00007730 Int uimm16 = ifieldUIMM16(theInstr);
cerion094d1392005-06-20 13:45:57 +00007731
cerion2831b002005-11-30 19:55:22 +00007732 Int simm16 = extend_s_16to32(uimm16);
7733 IRTemp frS = newTemp(Ity_F64);
7734 IRType ty = mode64 ? Ity_I64 : Ity_I32;
7735 IRTemp EA = newTemp(ty);
7736 IRTemp rA = newTemp(ty);
7737 IRTemp rB = newTemp(ty);
cerion094d1392005-06-20 13:45:57 +00007738
7739 assign( frS, getFReg(frS_addr) );
cerionedf7fc52005-11-18 20:57:41 +00007740 assign( rA, getIReg(rA_addr) );
7741 assign( rB, getIReg(rB_addr) );
cerion3d870a32005-03-18 12:23:33 +00007742
sewardjb183b852006-02-03 16:08:03 +00007743 /* These are straightforward from a status bits perspective: no
7744 funny status or CR bits affected. For single precision stores,
7745 the values are truncated and denormalised (not rounded) to turn
7746 them into single precision values. */
7747
7748 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00007749
7750 case 0x34: // stfs (Store Float Single, PPC32 p518)
ceriond953ebb2005-11-29 13:27:20 +00007751 DIP("stfs fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7752 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
sewardjb183b852006-02-03 16:08:03 +00007753 /* Use Iop_TruncF64asF32 to truncate and possible denormalise
7754 the value to be stored in the correct way, without any
7755 rounding. */
carll1f5fe1f2014-08-07 23:25:23 +00007756 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
sewardje14bb9f2005-07-22 09:39:02 +00007757 break;
7758
cerion5b2325f2005-12-23 00:55:09 +00007759 case 0x35: // stfsu (Store Float Single, Update, PPC32 p519)
sewardjb183b852006-02-03 16:08:03 +00007760 if (rA_addr == 0)
cerion729edb72005-12-02 16:03:46 +00007761 return False;
cerion729edb72005-12-02 16:03:46 +00007762 DIP("stfsu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7763 assign( EA, ea_rA_simm(rA_addr, simm16) );
sewardjb183b852006-02-03 16:08:03 +00007764 /* See comment for stfs */
carll1f5fe1f2014-08-07 23:25:23 +00007765 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
cerion729edb72005-12-02 16:03:46 +00007766 putIReg( rA_addr, mkexpr(EA) );
7767 break;
cerion3d870a32005-03-18 12:23:33 +00007768
cerion094d1392005-06-20 13:45:57 +00007769 case 0x36: // stfd (Store Float Double, PPC32 p513)
ceriond953ebb2005-11-29 13:27:20 +00007770 DIP("stfd fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7771 assign( EA, ea_rAor0_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007772 store( mkexpr(EA), mkexpr(frS) );
cerion094d1392005-06-20 13:45:57 +00007773 break;
cerion3d870a32005-03-18 12:23:33 +00007774
cerion5b2325f2005-12-23 00:55:09 +00007775 case 0x37: // stfdu (Store Float Double, Update, PPC32 p514)
sewardjb183b852006-02-03 16:08:03 +00007776 if (rA_addr == 0)
sewardje14bb9f2005-07-22 09:39:02 +00007777 return False;
ceriond953ebb2005-11-29 13:27:20 +00007778 DIP("stfdu fr%u,%d(r%u)\n", frS_addr, simm16, rA_addr);
7779 assign( EA, ea_rA_simm(rA_addr, simm16) );
carll1f5fe1f2014-08-07 23:25:23 +00007780 store( mkexpr(EA), mkexpr(frS) );
sewardje14bb9f2005-07-22 09:39:02 +00007781 putIReg( rA_addr, mkexpr(EA) );
7782 break;
7783
7784 case 0x1F:
7785 if (b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00007786 vex_printf("dis_fp_store(ppc)(instr,b0)\n");
sewardje14bb9f2005-07-22 09:39:02 +00007787 return False;
7788 }
sewardje14bb9f2005-07-22 09:39:02 +00007789 switch(opc2) {
ceriond953ebb2005-11-29 13:27:20 +00007790 case 0x297: // stfsx (Store Float Single Indexed, PPC32 p521)
7791 DIP("stfsx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7792 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
sewardjb183b852006-02-03 16:08:03 +00007793 /* See note for stfs */
carll1f5fe1f2014-08-07 23:25:23 +00007794 store( mkexpr(EA),
7795 unop(Iop_TruncF64asF32, mkexpr(frS)) );
ceriond953ebb2005-11-29 13:27:20 +00007796 break;
7797
cerion5b2325f2005-12-23 00:55:09 +00007798 case 0x2B7: // stfsux (Store Float Sgl, Update Indxd, PPC32 p520)
sewardjb183b852006-02-03 16:08:03 +00007799 if (rA_addr == 0)
cerion729edb72005-12-02 16:03:46 +00007800 return False;
cerion729edb72005-12-02 16:03:46 +00007801 DIP("stfsux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7802 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
sewardjb183b852006-02-03 16:08:03 +00007803 /* See note for stfs */
carll1f5fe1f2014-08-07 23:25:23 +00007804 store( mkexpr(EA), unop(Iop_TruncF64asF32, mkexpr(frS)) );
cerion729edb72005-12-02 16:03:46 +00007805 putIReg( rA_addr, mkexpr(EA) );
7806 break;
sewardje14bb9f2005-07-22 09:39:02 +00007807
ceriond953ebb2005-11-29 13:27:20 +00007808 case 0x2D7: // stfdx (Store Float Double Indexed, PPC32 p516)
7809 DIP("stfdx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7810 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007811 store( mkexpr(EA), mkexpr(frS) );
ceriond953ebb2005-11-29 13:27:20 +00007812 break;
sewardje14bb9f2005-07-22 09:39:02 +00007813
cerion5b2325f2005-12-23 00:55:09 +00007814 case 0x2F7: // stfdux (Store Float Dbl, Update Indxd, PPC32 p515)
sewardjb183b852006-02-03 16:08:03 +00007815 if (rA_addr == 0)
ceriond953ebb2005-11-29 13:27:20 +00007816 return False;
ceriond953ebb2005-11-29 13:27:20 +00007817 DIP("stfdux fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7818 assign( EA, ea_rA_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007819 store( mkexpr(EA), mkexpr(frS) );
ceriond953ebb2005-11-29 13:27:20 +00007820 putIReg( rA_addr, mkexpr(EA) );
7821 break;
sewardj5f63c0c2005-09-09 10:36:55 +00007822
sewardj09e88d12006-01-27 16:05:49 +00007823 case 0x3D7: // stfiwx (Store Float as Int, Indexed, PPC32 p517)
sewardj5117ce12006-01-27 21:20:15 +00007824 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardj09e88d12006-01-27 16:05:49 +00007825 DIP("stfiwx fr%u,r%u,r%u\n", frS_addr, rA_addr, rB_addr);
7826 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
carll1f5fe1f2014-08-07 23:25:23 +00007827 store( mkexpr(EA),
7828 unop(Iop_64to32, unop(Iop_ReinterpF64asI64, mkexpr(frS))) );
sewardj09e88d12006-01-27 16:05:49 +00007829 break;
sewardje14bb9f2005-07-22 09:39:02 +00007830
ceriond953ebb2005-11-29 13:27:20 +00007831 default:
cerion5b2325f2005-12-23 00:55:09 +00007832 vex_printf("dis_fp_store(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00007833 return False;
sewardje14bb9f2005-07-22 09:39:02 +00007834 }
7835 break;
cerion3d870a32005-03-18 12:23:33 +00007836
7837 default:
cerion5b2325f2005-12-23 00:55:09 +00007838 vex_printf("dis_fp_store(ppc)(opc1)\n");
cerion3d870a32005-03-18 12:23:33 +00007839 return False;
7840 }
7841 return True;
7842}
7843
7844
7845
7846/*
7847 Floating Point Arith Instructions
7848*/
7849static Bool dis_fp_arith ( UInt theInstr )
7850{
7851 /* A-Form */
cerion76de5cf2005-11-18 18:25:12 +00007852 UChar opc1 = ifieldOPC(theInstr);
7853 UChar frD_addr = ifieldRegDS(theInstr);
7854 UChar frA_addr = ifieldRegA(theInstr);
7855 UChar frB_addr = ifieldRegB(theInstr);
7856 UChar frC_addr = ifieldRegC(theInstr);
7857 UChar opc2 = ifieldOPClo5(theInstr);
7858 UChar flag_rC = ifieldBIT0(theInstr);
cerion094d1392005-06-20 13:45:57 +00007859
sewardjb183b852006-02-03 16:08:03 +00007860 IRTemp frD = newTemp(Ity_F64);
7861 IRTemp frA = newTemp(Ity_F64);
7862 IRTemp frB = newTemp(Ity_F64);
7863 IRTemp frC = newTemp(Ity_F64);
7864 IRExpr* rm = get_IR_roundingmode();
7865
7866 /* By default, we will examine the results of the operation and set
7867 fpscr[FPRF] accordingly. */
7868 Bool set_FPRF = True;
7869
7870 /* By default, if flag_RC is set, we will clear cr1 after the
7871 operation. In reality we should set cr1 to indicate the
7872 exception status of the operation, but since we're not
7873 simulating exceptions, the exception status will appear to be
7874 zero. Hence cr1 should be cleared if this is a . form insn. */
7875 Bool clear_CR1 = True;
cerion094d1392005-06-20 13:45:57 +00007876
7877 assign( frA, getFReg(frA_addr));
7878 assign( frB, getFReg(frB_addr));
7879 assign( frC, getFReg(frC_addr));
cerion3d870a32005-03-18 12:23:33 +00007880
7881 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00007882 case 0x3B:
7883 switch (opc2) {
7884 case 0x12: // fdivs (Floating Divide Single, PPC32 p407)
sewardjb183b852006-02-03 16:08:03 +00007885 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007886 return False;
cerion5b2325f2005-12-23 00:55:09 +00007887 DIP("fdivs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007888 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007889 assign( frD, triop( Iop_DivF64r32,
7890 rm, mkexpr(frA), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00007891 break;
7892
7893 case 0x14: // fsubs (Floating Subtract Single, PPC32 p430)
sewardjb183b852006-02-03 16:08:03 +00007894 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007895 return False;
cerion5b2325f2005-12-23 00:55:09 +00007896 DIP("fsubs%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007897 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007898 assign( frD, triop( Iop_SubF64r32,
7899 rm, mkexpr(frA), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00007900 break;
7901
7902 case 0x15: // fadds (Floating Add Single, PPC32 p401)
sewardjb183b852006-02-03 16:08:03 +00007903 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007904 return False;
cerion5b2325f2005-12-23 00:55:09 +00007905 DIP("fadds%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007906 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007907 assign( frD, triop( Iop_AddF64r32,
7908 rm, mkexpr(frA), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00007909 break;
7910
sewardj870c84b2006-01-24 03:33:43 +00007911 case 0x16: // fsqrts (Floating SqRt (Single-Precision), PPC32 p428)
sewardj5117ce12006-01-27 21:20:15 +00007912 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
sewardjb183b852006-02-03 16:08:03 +00007913 if (frA_addr != 0 || frC_addr != 0)
sewardj870c84b2006-01-24 03:33:43 +00007914 return False;
sewardj870c84b2006-01-24 03:33:43 +00007915 DIP("fsqrts%s fr%u,fr%u\n", flag_rC ? ".":"",
7916 frD_addr, frB_addr);
sewardj79fd33f2006-01-29 17:07:57 +00007917 // however illogically, on ppc970 this insn behaves identically
sewardjb183b852006-02-03 16:08:03 +00007918 // to fsqrt (double-precision). So use SqrtF64, not SqrtF64r32.
7919 assign( frD, binop( Iop_SqrtF64, rm, mkexpr(frB) ));
sewardj870c84b2006-01-24 03:33:43 +00007920 break;
sewardje14bb9f2005-07-22 09:39:02 +00007921
sewardjbaf971a2006-01-27 15:09:35 +00007922 case 0x18: // fres (Floating Reciprocal Estimate Single, PPC32 p421)
sewardj5117ce12006-01-27 21:20:15 +00007923 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardjb183b852006-02-03 16:08:03 +00007924 if (frA_addr != 0 || frC_addr != 0)
sewardjbaf971a2006-01-27 15:09:35 +00007925 return False;
sewardjbaf971a2006-01-27 15:09:35 +00007926 DIP("fres%s fr%u,fr%u\n", flag_rC ? ".":"",
7927 frD_addr, frB_addr);
sewardj157b19b2006-01-31 16:32:25 +00007928 { IRExpr* ieee_one
7929 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
sewardjb183b852006-02-03 16:08:03 +00007930 assign( frD, triop( Iop_DivF64r32,
7931 rm,
7932 ieee_one, mkexpr(frB) ));
sewardj157b19b2006-01-31 16:32:25 +00007933 }
sewardjbaf971a2006-01-27 15:09:35 +00007934 break;
sewardje14bb9f2005-07-22 09:39:02 +00007935
7936 case 0x19: // fmuls (Floating Multiply Single, PPC32 p414)
sewardjb183b852006-02-03 16:08:03 +00007937 if (frB_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007938 return False;
cerion5b2325f2005-12-23 00:55:09 +00007939 DIP("fmuls%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007940 frD_addr, frA_addr, frC_addr);
sewardjb183b852006-02-03 16:08:03 +00007941 assign( frD, triop( Iop_MulF64r32,
7942 rm, mkexpr(frA), mkexpr(frC) ));
sewardje14bb9f2005-07-22 09:39:02 +00007943 break;
7944
sewardj79fd33f2006-01-29 17:07:57 +00007945 case 0x1A: // frsqrtes (Floating Recip SqRt Est Single)
7946 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
7947 // Undocumented instruction?
sewardjb183b852006-02-03 16:08:03 +00007948 if (frA_addr != 0 || frC_addr != 0)
sewardj79fd33f2006-01-29 17:07:57 +00007949 return False;
sewardj79fd33f2006-01-29 17:07:57 +00007950 DIP("frsqrtes%s fr%u,fr%u\n", flag_rC ? ".":"",
7951 frD_addr, frB_addr);
sewardj1ddee212014-08-24 14:00:19 +00007952 assign( frD, unop(Iop_RSqrtEst5GoodF64, mkexpr(frB)) );
sewardj79fd33f2006-01-29 17:07:57 +00007953 break;
7954
sewardje14bb9f2005-07-22 09:39:02 +00007955 default:
cerion5b2325f2005-12-23 00:55:09 +00007956 vex_printf("dis_fp_arith(ppc)(3B: opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00007957 return False;
7958 }
7959 break;
cerion094d1392005-06-20 13:45:57 +00007960
cerion3d870a32005-03-18 12:23:33 +00007961 case 0x3F:
7962 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00007963 case 0x12: // fdiv (Floating Div (Double-Precision), PPC32 p406)
sewardjb183b852006-02-03 16:08:03 +00007964 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007965 return False;
cerion5b2325f2005-12-23 00:55:09 +00007966 DIP("fdiv%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007967 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007968 assign( frD, triop(Iop_DivF64, rm, mkexpr(frA), mkexpr(frB)) );
sewardje14bb9f2005-07-22 09:39:02 +00007969 break;
7970
cerion5b2325f2005-12-23 00:55:09 +00007971 case 0x14: // fsub (Floating Sub (Double-Precision), PPC32 p429)
sewardjb183b852006-02-03 16:08:03 +00007972 if (frC_addr != 0)
sewardje14bb9f2005-07-22 09:39:02 +00007973 return False;
cerion5b2325f2005-12-23 00:55:09 +00007974 DIP("fsub%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00007975 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007976 assign( frD, triop(Iop_SubF64, rm, mkexpr(frA), mkexpr(frB)) );
sewardje14bb9f2005-07-22 09:39:02 +00007977 break;
cerion3d870a32005-03-18 12:23:33 +00007978
7979 case 0x15: // fadd (Floating Add (Double-Precision), PPC32 p400)
sewardjb183b852006-02-03 16:08:03 +00007980 if (frC_addr != 0)
cerion3d870a32005-03-18 12:23:33 +00007981 return False;
cerion5b2325f2005-12-23 00:55:09 +00007982 DIP("fadd%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
cerion3d870a32005-03-18 12:23:33 +00007983 frD_addr, frA_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007984 assign( frD, triop(Iop_AddF64, rm, mkexpr(frA), mkexpr(frB)) );
cerion094d1392005-06-20 13:45:57 +00007985 break;
cerion3d870a32005-03-18 12:23:33 +00007986
cerion876ef412005-12-14 22:00:53 +00007987 case 0x16: // fsqrt (Floating SqRt (Double-Precision), PPC32 p427)
sewardj5117ce12006-01-27 21:20:15 +00007988 // NOTE: POWERPC OPTIONAL, "General-Purpose Group" (PPC32_FX)
sewardjb183b852006-02-03 16:08:03 +00007989 if (frA_addr != 0 || frC_addr != 0)
cerion876ef412005-12-14 22:00:53 +00007990 return False;
cerion5b2325f2005-12-23 00:55:09 +00007991 DIP("fsqrt%s fr%u,fr%u\n", flag_rC ? ".":"",
cerion876ef412005-12-14 22:00:53 +00007992 frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00007993 assign( frD, binop(Iop_SqrtF64, rm, mkexpr(frB)) );
cerion876ef412005-12-14 22:00:53 +00007994 break;
sewardje14bb9f2005-07-22 09:39:02 +00007995
7996 case 0x17: { // fsel (Floating Select, PPC32 p426)
sewardj5117ce12006-01-27 21:20:15 +00007997 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardje14bb9f2005-07-22 09:39:02 +00007998 IRTemp cc = newTemp(Ity_I32);
7999 IRTemp cc_b0 = newTemp(Ity_I32);
8000
cerion5b2325f2005-12-23 00:55:09 +00008001 DIP("fsel%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008002 frD_addr, frA_addr, frC_addr, frB_addr);
8003
8004 // cc: UN == 0x41, LT == 0x01, GT == 0x00, EQ == 0x40
8005 // => GT|EQ == (cc & 0x1 == 0)
cerion5b2325f2005-12-23 00:55:09 +00008006 assign( cc, binop(Iop_CmpF64, mkexpr(frA),
8007 IRExpr_Const(IRConst_F64(0))) );
sewardje14bb9f2005-07-22 09:39:02 +00008008 assign( cc_b0, binop(Iop_And32, mkexpr(cc), mkU32(1)) );
8009
8010 // frD = (frA >= 0.0) ? frC : frB
8011 // = (cc_b0 == 0) ? frC : frB
8012 assign( frD,
florian99dd03e2013-01-29 03:56:06 +00008013 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00008014 binop(Iop_CmpEQ32, mkexpr(cc_b0), mkU32(0)),
florian99dd03e2013-01-29 03:56:06 +00008015 mkexpr(frC),
8016 mkexpr(frB) ));
sewardjb183b852006-02-03 16:08:03 +00008017
8018 /* One of the rare ones which don't mess with FPRF */
8019 set_FPRF = False;
sewardje14bb9f2005-07-22 09:39:02 +00008020 break;
8021 }
8022
sewardj79fd33f2006-01-29 17:07:57 +00008023 case 0x18: // fre (Floating Reciprocal Estimate)
8024 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
8025 // Note: unclear whether this insn really exists or not
8026 // ppc970 doesn't have it, but POWER5 does
sewardjb183b852006-02-03 16:08:03 +00008027 if (frA_addr != 0 || frC_addr != 0)
sewardj79fd33f2006-01-29 17:07:57 +00008028 return False;
sewardj79fd33f2006-01-29 17:07:57 +00008029 DIP("fre%s fr%u,fr%u\n", flag_rC ? ".":"",
8030 frD_addr, frB_addr);
sewardj157b19b2006-01-31 16:32:25 +00008031 { IRExpr* ieee_one
8032 = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
sewardjb183b852006-02-03 16:08:03 +00008033 assign( frD, triop( Iop_DivF64,
sewardj56de4212006-02-06 22:19:17 +00008034 rm,
sewardjb183b852006-02-03 16:08:03 +00008035 ieee_one, mkexpr(frB) ));
sewardj157b19b2006-01-31 16:32:25 +00008036 }
sewardj79fd33f2006-01-29 17:07:57 +00008037 break;
8038
cerion5b2325f2005-12-23 00:55:09 +00008039 case 0x19: // fmul (Floating Mult (Double Precision), PPC32 p413)
sewardjb183b852006-02-03 16:08:03 +00008040 if (frB_addr != 0)
cerion5b2325f2005-12-23 00:55:09 +00008041 vex_printf("dis_fp_arith(ppc)(instr,fmul)\n");
cerion5b2325f2005-12-23 00:55:09 +00008042 DIP("fmul%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008043 frD_addr, frA_addr, frC_addr);
sewardjb183b852006-02-03 16:08:03 +00008044 assign( frD, triop(Iop_MulF64, rm, mkexpr(frA), mkexpr(frC)) );
sewardje14bb9f2005-07-22 09:39:02 +00008045 break;
8046
sewardjbaf971a2006-01-27 15:09:35 +00008047 case 0x1A: // frsqrte (Floating Recip SqRt Est., PPC32 p424)
sewardj5117ce12006-01-27 21:20:15 +00008048 // NOTE: POWERPC OPTIONAL, "Graphics Group" (PPC32_GX)
sewardjb183b852006-02-03 16:08:03 +00008049 if (frA_addr != 0 || frC_addr != 0)
sewardjbaf971a2006-01-27 15:09:35 +00008050 return False;
sewardjbaf971a2006-01-27 15:09:35 +00008051 DIP("frsqrte%s fr%u,fr%u\n", flag_rC ? ".":"",
8052 frD_addr, frB_addr);
sewardj1ddee212014-08-24 14:00:19 +00008053 assign( frD, unop(Iop_RSqrtEst5GoodF64, mkexpr(frB)) );
sewardjbaf971a2006-01-27 15:09:35 +00008054 break;
cerion3d870a32005-03-18 12:23:33 +00008055
8056 default:
cerion5b2325f2005-12-23 00:55:09 +00008057 vex_printf("dis_fp_arith(ppc)(3F: opc2)\n");
cerion3d870a32005-03-18 12:23:33 +00008058 return False;
8059 }
cerion094d1392005-06-20 13:45:57 +00008060 break;
8061
cerion3d870a32005-03-18 12:23:33 +00008062 default:
cerion5b2325f2005-12-23 00:55:09 +00008063 vex_printf("dis_fp_arith(ppc)(opc1)\n");
cerion3d870a32005-03-18 12:23:33 +00008064 return False;
8065 }
cerion094d1392005-06-20 13:45:57 +00008066
8067 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00008068
8069 if (set_FPRF) {
8070 // XXX XXX XXX FIXME
8071 // set FPRF from frD
8072 }
8073
8074 if (flag_rC && clear_CR1) {
8075 putCR321( 1, mkU8(0) );
8076 putCR0( 1, mkU8(0) );
8077 }
8078
cerion3d870a32005-03-18 12:23:33 +00008079 return True;
8080}
8081
8082
8083
sewardje14bb9f2005-07-22 09:39:02 +00008084/*
8085 Floating Point Mult-Add Instructions
8086*/
8087static Bool dis_fp_multadd ( UInt theInstr )
8088{
8089 /* A-Form */
cerion76de5cf2005-11-18 18:25:12 +00008090 UChar opc1 = ifieldOPC(theInstr);
8091 UChar frD_addr = ifieldRegDS(theInstr);
8092 UChar frA_addr = ifieldRegA(theInstr);
8093 UChar frB_addr = ifieldRegB(theInstr);
8094 UChar frC_addr = ifieldRegC(theInstr);
8095 UChar opc2 = ifieldOPClo5(theInstr);
8096 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00008097
sewardjb183b852006-02-03 16:08:03 +00008098 IRTemp frD = newTemp(Ity_F64);
8099 IRTemp frA = newTemp(Ity_F64);
8100 IRTemp frB = newTemp(Ity_F64);
8101 IRTemp frC = newTemp(Ity_F64);
8102 IRTemp rmt = newTemp(Ity_I32);
sewardj2bcdd652012-07-14 08:22:13 +00008103 IRTemp tmp = newTemp(Ity_F64);
8104 IRTemp sign_tmp = newTemp(Ity_I64);
8105 IRTemp nan_mask = newTemp(Ity_I32);
sewardjb183b852006-02-03 16:08:03 +00008106 IRExpr* rm;
8107
8108 /* By default, we will examine the results of the operation and set
8109 fpscr[FPRF] accordingly. */
8110 Bool set_FPRF = True;
8111
8112 /* By default, if flag_RC is set, we will clear cr1 after the
8113 operation. In reality we should set cr1 to indicate the
8114 exception status of the operation, but since we're not
8115 simulating exceptions, the exception status will appear to be
8116 zero. Hence cr1 should be cleared if this is a . form insn. */
8117 Bool clear_CR1 = True;
8118
8119 /* Bind the rounding mode expression to a temp; there's no
8120 point in creating gratuitous CSEs, as we know we'll need
8121 to use it twice. */
8122 assign( rmt, get_IR_roundingmode() );
8123 rm = mkexpr(rmt);
sewardje14bb9f2005-07-22 09:39:02 +00008124
8125 assign( frA, getFReg(frA_addr));
8126 assign( frB, getFReg(frB_addr));
8127 assign( frC, getFReg(frC_addr));
8128
sewardjb183b852006-02-03 16:08:03 +00008129 /* The rounding in this is all a bit dodgy. The idea is to only do
8130 one rounding. That clearly isn't achieveable without dedicated
8131 four-input IR primops, although in the single precision case we
8132 can sort-of simulate it by doing the inner multiply in double
8133 precision.
8134
8135 In the negated cases, the negation happens after rounding. */
8136
sewardje14bb9f2005-07-22 09:39:02 +00008137 switch (opc1) {
8138 case 0x3B:
8139 switch (opc2) {
8140 case 0x1C: // fmsubs (Floating Mult-Subtr Single, PPC32 p412)
cerion5b2325f2005-12-23 00:55:09 +00008141 DIP("fmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008142 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008143 assign( frD, qop( Iop_MSubF64r32, rm,
8144 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardjb183b852006-02-03 16:08:03 +00008145 break;
sewardje14bb9f2005-07-22 09:39:02 +00008146
8147 case 0x1D: // fmadds (Floating Mult-Add Single, PPC32 p409)
cerion5b2325f2005-12-23 00:55:09 +00008148 DIP("fmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008149 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008150 assign( frD, qop( Iop_MAddF64r32, rm,
8151 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00008152 break;
8153
8154 case 0x1E: // fnmsubs (Float Neg Mult-Subtr Single, PPC32 p420)
sewardje14bb9f2005-07-22 09:39:02 +00008155 case 0x1F: // fnmadds (Floating Negative Multiply-Add Single, PPC32 p418)
sewardj2bcdd652012-07-14 08:22:13 +00008156
8157 if (opc2 == 0x1E) {
8158 DIP("fnmsubs%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8159 frD_addr, frA_addr, frC_addr, frB_addr);
8160 assign( tmp, qop( Iop_MSubF64r32, rm,
8161 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
8162 } else {
8163 DIP("fnmadds%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8164 frD_addr, frA_addr, frC_addr, frB_addr);
8165 assign( tmp, qop( Iop_MAddF64r32, rm,
8166 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
8167 }
8168
8169 assign( nan_mask, Check_NaN( mkexpr( tmp ),
8170 mkU32( NANmaskSingle ) ) );
8171 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
8172 mkexpr( nan_mask ) ) );
8173 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
sewardje14bb9f2005-07-22 09:39:02 +00008174 break;
8175
8176 default:
cerion5b2325f2005-12-23 00:55:09 +00008177 vex_printf("dis_fp_multadd(ppc)(3B: opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008178 return False;
8179 }
8180 break;
8181
8182 case 0x3F:
8183 switch (opc2) {
cerion5b2325f2005-12-23 00:55:09 +00008184 case 0x1C: // fmsub (Float Mult-Sub (Dbl Precision), PPC32 p411)
8185 DIP("fmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008186 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008187 assign( frD, qop( Iop_MSubF64, rm,
8188 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00008189 break;
8190
cerion5b2325f2005-12-23 00:55:09 +00008191 case 0x1D: // fmadd (Float Mult-Add (Dbl Precision), PPC32 p408)
8192 DIP("fmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
sewardje14bb9f2005-07-22 09:39:02 +00008193 frD_addr, frA_addr, frC_addr, frB_addr);
sewardj40c80262006-02-08 19:30:46 +00008194 assign( frD, qop( Iop_MAddF64, rm,
8195 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
sewardje14bb9f2005-07-22 09:39:02 +00008196 break;
8197
cerion5b2325f2005-12-23 00:55:09 +00008198 case 0x1E: // fnmsub (Float Neg Mult-Subtr (Dbl Precision), PPC32 p419)
cerion5b2325f2005-12-23 00:55:09 +00008199 case 0x1F: // fnmadd (Float Neg Mult-Add (Dbl Precision), PPC32 p417)
sewardj2bcdd652012-07-14 08:22:13 +00008200
8201 if (opc2 == 0x1E) {
8202 DIP("fnmsub%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8203 frD_addr, frA_addr, frC_addr, frB_addr);
8204 assign( tmp, qop( Iop_MSubF64, rm,
8205 mkexpr(frA), mkexpr(frC), mkexpr(frB) ) );
8206 } else {
8207 DIP("fnmadd%s fr%u,fr%u,fr%u,fr%u\n", flag_rC ? ".":"",
8208 frD_addr, frA_addr, frC_addr, frB_addr);
8209 assign( tmp, qop( Iop_MAddF64, rm,
8210 mkexpr(frA), mkexpr(frC), mkexpr(frB) ));
8211 }
8212
8213 assign( nan_mask, Check_NaN( mkexpr( tmp ),
8214 mkU32( NANmaskDouble ) ) );
8215 assign( sign_tmp, Complement_non_NaN( mkexpr( tmp ),
8216 mkexpr( nan_mask ) ) );
8217 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr( sign_tmp ) ) );
sewardj0e2cc672005-07-29 21:58:51 +00008218 break;
sewardje14bb9f2005-07-22 09:39:02 +00008219
8220 default:
cerion5b2325f2005-12-23 00:55:09 +00008221 vex_printf("dis_fp_multadd(ppc)(3F: opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008222 return False;
8223 }
8224 break;
8225
8226 default:
cerion5b2325f2005-12-23 00:55:09 +00008227 vex_printf("dis_fp_multadd(ppc)(opc1)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008228 return False;
8229 }
8230
8231 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00008232
8233 if (set_FPRF) {
8234 // XXX XXX XXX FIXME
8235 // set FPRF from frD
8236 }
8237
8238 if (flag_rC && clear_CR1) {
8239 putCR321( 1, mkU8(0) );
8240 putCR0( 1, mkU8(0) );
8241 }
8242
sewardje14bb9f2005-07-22 09:39:02 +00008243 return True;
8244}
8245
sewardj66d5ef22011-04-15 11:55:00 +00008246/*
8247 * fe_flag is set to 1 if any of the following conditions occurs:
sewardje71e56a2011-09-05 12:11:06 +00008248 * - The floating-point operand in register FRB is a Zero, a
8249 * NaN, an Infinity, or a negative value.
8250 * - e_b is less than or equal to: -970 for double precision; -103 for single precision
8251 * Otherwise fe_flag is set to 0.
8252 *
8253 * fg_flag is set to 1 if either of the following conditions occurs.
8254 * - The floating-point operand in register FRB is a Zero, an
8255 * Infinity, or a denormalized value.
8256 * Otherwise fg_flag is set to 0.
8257 *
8258 */
8259static void do_fp_tsqrt(IRTemp frB_Int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
8260{
8261 // The following temps are for holding intermediate results
8262 IRTemp e_b = newTemp(Ity_I32);
8263 IRExpr * fe_flag, * fg_flag;
8264 IRTemp frB_exp_shR = newTemp(Ity_I32);
8265 UInt bias = sp? 127 : 1023;
8266 IRExpr * frbNaN, * frbDenorm, * frBNeg;
8267 IRExpr * eb_LTE;
8268 IRTemp frbZero_tmp = newTemp(Ity_I1);
8269 IRTemp frbInf_tmp = newTemp(Ity_I1);
8270 *fe_flag_tmp = newTemp(Ity_I32);
8271 *fg_flag_tmp = newTemp(Ity_I32);
8272 assign( frB_exp_shR, fp_exp_part( frB_Int, sp ) );
8273 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
8274
8275 ////////////////// fe_flag tests BEGIN //////////////////////
8276 /* We first do all tests that may result in setting fe_flag to '1'.
8277 * (NOTE: These tests are similar to those used for ftdiv. See do_fp_tdiv()
8278 * for details.)
8279 */
8280 frbNaN = sp ? is_NaN_32(frB_Int) : is_NaN(frB_Int);
8281 assign( frbInf_tmp, is_Inf(frB_Int, sp) );
8282 assign( frbZero_tmp, is_Zero(frB_Int, sp ) );
8283 {
8284 // Test_value = -970 for double precision
8285 UInt test_value = sp ? 0xffffff99 : 0xfffffc36;
8286 eb_LTE = binop( Iop_CmpLE32S, mkexpr( e_b ), mkU32( test_value ) );
8287 }
8288 frBNeg = binop( Iop_CmpEQ32,
8289 binop( Iop_Shr32,
8290 sp ? mkexpr( frB_Int ) : unop( Iop_64HIto32, mkexpr( frB_Int ) ),
8291 mkU8( 31 ) ),
8292 mkU32( 1 ) );
8293 ////////////////// fe_flag tests END //////////////////////
8294
8295 ////////////////// fg_flag tests BEGIN //////////////////////
8296 /*
8297 * The following tests were already performed above in the fe_flag
8298 * tests. So these conditions will result in both fe_ and fg_ flags
8299 * being set.
8300 * - Test if FRB is Zero
8301 * - Test if FRB is an Infinity
8302 */
8303
8304 /*
8305 * Test if FRB holds a denormalized value. A denormalized value is one where
8306 * the exp is 0 and the fraction is non-zero.
8307 */
8308 if (sp) {
8309 IRTemp frac_part = newTemp(Ity_I32);
8310 assign( frac_part, binop( Iop_And32, mkexpr(frB_Int), mkU32(0x007fffff)) );
8311 frbDenorm
8312 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
8313 binop( Iop_CmpNE32, mkexpr( frac_part ), mkU32( 0 ) ) );
8314 } else {
8315 IRExpr * hi32, * low32, * fraction_is_nonzero;
8316 IRTemp frac_part = newTemp(Ity_I64);
8317
8318 assign( frac_part, FP_FRAC_PART(frB_Int) );
8319 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
8320 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
8321 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
8322 mkU32( 0 ) );
8323 frbDenorm
8324 = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ), mkU32( 0 ) ),
8325 fraction_is_nonzero );
8326 }
8327 ////////////////// fg_flag tests END //////////////////////
8328
8329 /////////////////////////
8330 fe_flag = mkOR1( mkexpr( frbZero_tmp ),
8331 mkOR1( frbNaN,
8332 mkOR1( mkexpr( frbInf_tmp ),
8333 mkOR1( frBNeg, eb_LTE ) ) ) );
8334
8335 fe_flag = unop(Iop_1Uto32, fe_flag);
8336
8337 fg_flag = mkOR1( mkexpr( frbZero_tmp ),
8338 mkOR1( mkexpr( frbInf_tmp ), frbDenorm ) );
8339 fg_flag = unop(Iop_1Uto32, fg_flag);
8340 assign (*fg_flag_tmp, fg_flag);
8341 assign (*fe_flag_tmp, fe_flag);
8342}
8343/*
8344 * fe_flag is set to 1 if any of the following conditions occurs:
sewardj66d5ef22011-04-15 11:55:00 +00008345 * - The double-precision floating-point operand in register FRA is a NaN or an
8346 * Infinity.
8347 * - The double-precision floating-point operand in register FRB is a Zero, a
8348 * NaN, or an Infinity.
8349 * - e_b is less than or equal to -1022.
8350 * - e_b is greater than or equal to 1021.
8351 * - The double-precision floating-point operand in register FRA is not a zero
8352 * and the difference, e_a - e_b, is greater than or equal to 1023.
8353 * - The double-precision floating-point operand in register FRA is not a zero
8354 * and the difference, e_a - e_b, is less than or equal to -1021.
8355 * - The double-precision floating-point operand in register FRA is not a zero
8356 * and e_a is less than or equal to -970
8357 * Otherwise fe_flag is set to 0.
8358 *
8359 * fg_flag is set to 1 if either of the following conditions occurs.
8360 * - The double-precision floating-point operand in register FRA is an Infinity.
8361 * - The double-precision floating-point operand in register FRB is a Zero, an
8362 * Infinity, or a denormalized value.
8363 * Otherwise fg_flag is set to 0.
8364 *
8365 */
sewardje71e56a2011-09-05 12:11:06 +00008366static void _do_fp_tdiv(IRTemp frA_int, IRTemp frB_int, Bool sp, IRTemp * fe_flag_tmp, IRTemp * fg_flag_tmp)
sewardj66d5ef22011-04-15 11:55:00 +00008367{
sewardj66d5ef22011-04-15 11:55:00 +00008368 // The following temps are for holding intermediate results
sewardj66d5ef22011-04-15 11:55:00 +00008369 IRTemp e_a = newTemp(Ity_I32);
8370 IRTemp e_b = newTemp(Ity_I32);
8371 IRTemp frA_exp_shR = newTemp(Ity_I32);
8372 IRTemp frB_exp_shR = newTemp(Ity_I32);
8373
sewardje71e56a2011-09-05 12:11:06 +00008374 UInt bias = sp? 127 : 1023;
8375 *fe_flag_tmp = newTemp(Ity_I32);
8376 *fg_flag_tmp = newTemp(Ity_I32);
sewardj66d5ef22011-04-15 11:55:00 +00008377
8378 /* The following variables hold boolean results from tests
8379 * that are OR'ed together for setting the fe_ and fg_ flags.
8380 * For some cases, the booleans are used more than once, so
8381 * I make those IRTemp's instead of IRExpr's.
8382 */
8383 IRExpr * fraNaN, * frbNaN, * frbDenorm;
8384 IRExpr * eb_LTE, * eb_GTE, * ea_eb_GTE, * ea_eb_LTE, * ea_LTE;
8385 IRTemp fraInf_tmp = newTemp(Ity_I1);
8386 IRTemp frbZero_tmp = newTemp(Ity_I1);
8387 IRTemp frbInf_tmp = newTemp(Ity_I1);
8388 IRTemp fraNotZero_tmp = newTemp(Ity_I1);
8389
8390/* The following are the flags that are set by OR'ing the results of
sewardj4aa412a2011-07-24 14:13:21 +00008391 * all the tests done for tdiv. These flags are the input to the specified CR.
sewardj66d5ef22011-04-15 11:55:00 +00008392 */
sewardje71e56a2011-09-05 12:11:06 +00008393 IRExpr * fe_flag, * fg_flag;
sewardj66d5ef22011-04-15 11:55:00 +00008394
sewardj66d5ef22011-04-15 11:55:00 +00008395 // Create temps that will be used throughout the following tests.
sewardje71e56a2011-09-05 12:11:06 +00008396 assign( frA_exp_shR, fp_exp_part( frA_int, sp ) );
8397 assign( frB_exp_shR, fp_exp_part( frB_int, sp ) );
sewardj66d5ef22011-04-15 11:55:00 +00008398 /* Let e_[a|b] be the unbiased exponent: i.e. exp - 1023. */
8399 assign(e_a, binop( Iop_Sub32, mkexpr(frA_exp_shR), mkU32( bias ) ));
8400 assign(e_b, binop( Iop_Sub32, mkexpr(frB_exp_shR), mkU32( bias ) ));
8401
8402
8403 ////////////////// fe_flag tests BEGIN //////////////////////
8404 /* We first do all tests that may result in setting fe_flag to '1'. */
8405
8406 /*
8407 * Test if the double-precision floating-point operand in register FRA is
8408 * a NaN:
sewardj66d5ef22011-04-15 11:55:00 +00008409 */
sewardje71e56a2011-09-05 12:11:06 +00008410 fraNaN = sp ? is_NaN_32(frA_int) : is_NaN(frA_int);
sewardj66d5ef22011-04-15 11:55:00 +00008411 /*
8412 * Test if the double-precision floating-point operand in register FRA is
8413 * an Infinity.
sewardj66d5ef22011-04-15 11:55:00 +00008414 */
sewardje71e56a2011-09-05 12:11:06 +00008415 assign(fraInf_tmp, is_Inf(frA_int, sp));
sewardj66d5ef22011-04-15 11:55:00 +00008416
8417 /*
8418 * Test if the double-precision floating-point operand in register FRB is
8419 * a NaN:
sewardj66d5ef22011-04-15 11:55:00 +00008420 */
sewardje71e56a2011-09-05 12:11:06 +00008421 frbNaN = sp ? is_NaN_32(frB_int) : is_NaN(frB_int);
sewardj66d5ef22011-04-15 11:55:00 +00008422 /*
8423 * Test if the double-precision floating-point operand in register FRB is
8424 * an Infinity.
sewardj66d5ef22011-04-15 11:55:00 +00008425 */
sewardje71e56a2011-09-05 12:11:06 +00008426 assign( frbInf_tmp, is_Inf(frB_int, sp) );
sewardj66d5ef22011-04-15 11:55:00 +00008427 /*
8428 * Test if the double-precision floating-point operand in register FRB is
8429 * a Zero.
sewardj66d5ef22011-04-15 11:55:00 +00008430 */
sewardje71e56a2011-09-05 12:11:06 +00008431 assign( frbZero_tmp, is_Zero(frB_int, sp) );
sewardj66d5ef22011-04-15 11:55:00 +00008432
8433 /*
sewardje71e56a2011-09-05 12:11:06 +00008434 * Test if e_b <= -1022 for double precision;
8435 * or e_b <= -126 for single precision
sewardj66d5ef22011-04-15 11:55:00 +00008436 */
8437 {
sewardje71e56a2011-09-05 12:11:06 +00008438 UInt test_value = sp ? 0xffffff82 : 0xfffffc02;
sewardj66d5ef22011-04-15 11:55:00 +00008439 eb_LTE = binop(Iop_CmpLE32S, mkexpr(e_b), mkU32(test_value));
8440 }
8441
8442 /*
sewardje71e56a2011-09-05 12:11:06 +00008443 * Test if e_b >= 1021 (i.e., 1021 < e_b) for double precision;
8444 * or e_b >= -125 (125 < e_b) for single precision
sewardj66d5ef22011-04-15 11:55:00 +00008445 */
8446 {
sewardje71e56a2011-09-05 12:11:06 +00008447 Int test_value = sp ? 125 : 1021;
sewardj66d5ef22011-04-15 11:55:00 +00008448 eb_GTE = binop(Iop_CmpLT32S, mkU32(test_value), mkexpr(e_b));
8449 }
8450
8451 /*
sewardje71e56a2011-09-05 12:11:06 +00008452 * Test if FRA != Zero and (e_a - e_b) >= bias
sewardj66d5ef22011-04-15 11:55:00 +00008453 */
sewardje71e56a2011-09-05 12:11:06 +00008454 assign( fraNotZero_tmp, unop( Iop_Not1, is_Zero( frA_int, sp ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00008455 ea_eb_GTE = mkAND1( mkexpr( fraNotZero_tmp ),
8456 binop( Iop_CmpLT32S, mkU32( bias ),
8457 binop( Iop_Sub32, mkexpr( e_a ),
8458 mkexpr( e_b ) ) ) );
8459
8460 /*
sewardje71e56a2011-09-05 12:11:06 +00008461 * Test if FRA != Zero and (e_a - e_b) <= [-1021 (double precision) or -125 (single precision)]
sewardj66d5ef22011-04-15 11:55:00 +00008462 */
8463 {
sewardje71e56a2011-09-05 12:11:06 +00008464 UInt test_value = sp ? 0xffffff83 : 0xfffffc03;
sewardj66d5ef22011-04-15 11:55:00 +00008465
8466 ea_eb_LTE = mkAND1( mkexpr( fraNotZero_tmp ),
8467 binop( Iop_CmpLE32S,
8468 binop( Iop_Sub32,
8469 mkexpr( e_a ),
8470 mkexpr( e_b ) ),
8471 mkU32( test_value ) ) );
8472 }
8473
8474 /*
sewardje71e56a2011-09-05 12:11:06 +00008475 * Test if FRA != Zero and e_a <= [-970 (double precision) or -103 (single precision)]
sewardj66d5ef22011-04-15 11:55:00 +00008476 */
8477 {
8478 UInt test_value = 0xfffffc36; //Int test_value = -970;
8479
8480 ea_LTE = mkAND1( mkexpr( fraNotZero_tmp ), binop( Iop_CmpLE32S,
8481 mkexpr( e_a ),
8482 mkU32( test_value ) ) );
8483 }
8484 ////////////////// fe_flag tests END //////////////////////
8485
8486 ////////////////// fg_flag tests BEGIN //////////////////////
8487 /*
8488 * The following tests were already performed above in the fe_flag
8489 * tests. So these conditions will result in both fe_ and fg_ flags
8490 * being set.
8491 * - Test if FRA is an Infinity
8492 * - Test if FRB ix Zero
8493 * - Test if FRB is an Infinity
8494 */
8495
8496 /*
8497 * Test if FRB holds a denormalized value. A denormalized value is one where
8498 * the exp is 0 and the fraction is non-zero.
8499 */
8500 {
sewardje71e56a2011-09-05 12:11:06 +00008501 IRExpr * fraction_is_nonzero;
sewardj66d5ef22011-04-15 11:55:00 +00008502
sewardje71e56a2011-09-05 12:11:06 +00008503 if (sp) {
8504 fraction_is_nonzero = binop( Iop_CmpNE32, FP_FRAC_PART32(frB_int),
8505 mkU32( 0 ) );
8506 } else {
8507 IRExpr * hi32, * low32;
8508 IRTemp frac_part = newTemp(Ity_I64);
8509 assign( frac_part, FP_FRAC_PART(frB_int) );
8510
8511 hi32 = unop( Iop_64HIto32, mkexpr( frac_part ) );
8512 low32 = unop( Iop_64to32, mkexpr( frac_part ) );
8513 fraction_is_nonzero = binop( Iop_CmpNE32, binop( Iop_Or32, low32, hi32 ),
8514 mkU32( 0 ) );
8515 }
sewardj66d5ef22011-04-15 11:55:00 +00008516 frbDenorm = mkAND1( binop( Iop_CmpEQ32, mkexpr( frB_exp_shR ),
sewardje71e56a2011-09-05 12:11:06 +00008517 mkU32( 0x0 ) ), fraction_is_nonzero );
sewardj66d5ef22011-04-15 11:55:00 +00008518
8519 }
8520 ////////////////// fg_flag tests END //////////////////////
8521
sewardj66d5ef22011-04-15 11:55:00 +00008522 fe_flag
8523 = mkOR1(
8524 fraNaN,
8525 mkOR1(
8526 mkexpr( fraInf_tmp ),
8527 mkOR1(
8528 mkexpr( frbZero_tmp ),
8529 mkOR1(
8530 frbNaN,
8531 mkOR1(
8532 mkexpr( frbInf_tmp ),
8533 mkOR1( eb_LTE,
8534 mkOR1( eb_GTE,
8535 mkOR1( ea_eb_GTE,
8536 mkOR1( ea_eb_LTE,
8537 ea_LTE ) ) ) ) ) ) ) ) );
8538
8539 fe_flag = unop(Iop_1Uto32, fe_flag);
8540
8541 fg_flag = mkOR1( mkexpr( fraInf_tmp ), mkOR1( mkexpr( frbZero_tmp ),
8542 mkOR1( mkexpr( frbInf_tmp ),
8543 frbDenorm ) ) );
8544 fg_flag = unop(Iop_1Uto32, fg_flag);
sewardje71e56a2011-09-05 12:11:06 +00008545 assign(*fe_flag_tmp, fe_flag);
8546 assign(*fg_flag_tmp, fg_flag);
8547}
sewardj66d5ef22011-04-15 11:55:00 +00008548
sewardje71e56a2011-09-05 12:11:06 +00008549/* See description for _do_fp_tdiv() above. */
8550static IRExpr * do_fp_tdiv(IRTemp frA_int, IRTemp frB_int)
8551{
8552 IRTemp fe_flag, fg_flag;
8553 /////////////////////////
8554 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
8555 * where fl_flag == 1 on ppc64.
8556 */
8557 IRExpr * fl_flag = unop(Iop_Not32, mkU32(0xFFFFFE));
8558 fe_flag = fg_flag = IRTemp_INVALID;
8559 _do_fp_tdiv(frA_int, frB_int, False/*not single precision*/, &fe_flag, &fg_flag);
sewardj4aa412a2011-07-24 14:13:21 +00008560 return binop( Iop_Or32,
8561 binop( Iop_Or32,
8562 binop( Iop_Shl32, fl_flag, mkU8( 3 ) ),
sewardje71e56a2011-09-05 12:11:06 +00008563 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
8564 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) );
sewardj4aa412a2011-07-24 14:13:21 +00008565}
8566
sewardje71e56a2011-09-05 12:11:06 +00008567static Bool dis_fp_tests ( UInt theInstr )
sewardj4aa412a2011-07-24 14:13:21 +00008568{
8569 UChar opc1 = ifieldOPC(theInstr);
8570 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
sewardj4aa412a2011-07-24 14:13:21 +00008571 UChar frB_addr = ifieldRegB(theInstr);
8572 UChar b0 = ifieldBIT0(theInstr);
sewardje71e56a2011-09-05 12:11:06 +00008573 UInt opc2 = ifieldOPClo10(theInstr);
sewardj4aa412a2011-07-24 14:13:21 +00008574 IRTemp frB_I64 = newTemp(Ity_I64);
8575
sewardje71e56a2011-09-05 12:11:06 +00008576 if (opc1 != 0x3F || b0 != 0 ){
8577 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
sewardj4aa412a2011-07-24 14:13:21 +00008578 return False;
8579 }
sewardj4aa412a2011-07-24 14:13:21 +00008580 assign( frB_I64, unop( Iop_ReinterpF64asI64, getFReg( frB_addr ) ) );
8581
sewardje71e56a2011-09-05 12:11:06 +00008582 switch (opc2) {
8583 case 0x080: // ftdiv
8584 {
8585 UChar frA_addr = ifieldRegA(theInstr);
8586 IRTemp frA_I64 = newTemp(Ity_I64);
8587 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
8588 if (b21to22 != 0 ) {
8589 vex_printf("dis_fp_tests(ppc)(ftdiv)\n");
8590 return False;
8591 }
sewardj66d5ef22011-04-15 11:55:00 +00008592
sewardje71e56a2011-09-05 12:11:06 +00008593 assign( frA_I64, unop( Iop_ReinterpF64asI64, getFReg( frA_addr ) ) );
8594 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
8595
8596 DIP("ftdiv crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
8597 break;
8598 }
8599 case 0x0A0: // ftsqrt
8600 {
8601 IRTemp flags = newTemp(Ity_I32);
8602 IRTemp fe_flag, fg_flag;
8603 fe_flag = fg_flag = IRTemp_INVALID;
8604 UChar b18to22 = toUChar( IFIELD( theInstr, 18, 5 ) );
8605 if ( b18to22 != 0) {
8606 vex_printf("dis_fp_tests(ppc)(ftsqrt)\n");
8607 return False;
8608 }
8609 DIP("ftsqrt crf%d,fr%u\n", crfD, frB_addr);
8610 do_fp_tsqrt(frB_I64, False /* not single precision*/, &fe_flag, &fg_flag);
8611 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
8612 * where fl_flag == 1 on ppc64.
8613 */
8614 assign( flags,
8615 binop( Iop_Or32,
8616 binop( Iop_Or32, mkU32( 8 ), // fl_flag
8617 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
8618 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
8619 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
8620 break;
8621 }
8622
8623 default:
8624 vex_printf("dis_fp_tests(ppc)(opc2)\n");
8625 return False;
8626
8627 }
sewardj66d5ef22011-04-15 11:55:00 +00008628 return True;
8629}
sewardje14bb9f2005-07-22 09:39:02 +00008630
8631/*
8632 Floating Point Compare Instructions
8633*/
8634static Bool dis_fp_cmp ( UInt theInstr )
8635{
8636 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00008637 UChar opc1 = ifieldOPC(theInstr);
8638 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
8639 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
8640 UChar frA_addr = ifieldRegA(theInstr);
8641 UChar frB_addr = ifieldRegB(theInstr);
8642 UInt opc2 = ifieldOPClo10(theInstr);
8643 UChar b0 = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00008644
8645 IRTemp ccIR = newTemp(Ity_I32);
8646 IRTemp ccPPC32 = newTemp(Ity_I32);
8647
sewardje14bb9f2005-07-22 09:39:02 +00008648 IRTemp frA = newTemp(Ity_F64);
8649 IRTemp frB = newTemp(Ity_F64);
sewardje14bb9f2005-07-22 09:39:02 +00008650
8651 if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00008652 vex_printf("dis_fp_cmp(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008653 return False;
8654 }
8655
8656 assign( frA, getFReg(frA_addr));
8657 assign( frB, getFReg(frB_addr));
8658
8659 assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
8660
8661 /* Map compare result from IR to PPC32 */
8662 /*
8663 FP cmp result | PPC | IR
8664 --------------------------
8665 UN | 0x1 | 0x45
8666 EQ | 0x2 | 0x40
8667 GT | 0x4 | 0x00
8668 LT | 0x8 | 0x01
8669 */
8670
sewardjb183b852006-02-03 16:08:03 +00008671 // ccPPC32 = Shl(1, (~(ccIR>>5) & 2)
8672 // | ((ccIR ^ (ccIR>>6)) & 1)
sewardje14bb9f2005-07-22 09:39:02 +00008673 assign(
8674 ccPPC32,
sewardjb183b852006-02-03 16:08:03 +00008675 binop(
8676 Iop_Shl32,
8677 mkU32(1),
8678 unop(
8679 Iop_32to8,
8680 binop(
8681 Iop_Or32,
8682 binop(
8683 Iop_And32,
8684 unop(
8685 Iop_Not32,
8686 binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))
8687 ),
8688 mkU32(2)
8689 ),
8690 binop(
8691 Iop_And32,
8692 binop(
8693 Iop_Xor32,
8694 mkexpr(ccIR),
8695 binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))
8696 ),
8697 mkU32(1)
8698 )
8699 )
8700 )
8701 )
sewardje14bb9f2005-07-22 09:39:02 +00008702 );
8703
ceriond953ebb2005-11-29 13:27:20 +00008704 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
sewardje14bb9f2005-07-22 09:39:02 +00008705
cerionedf7fc52005-11-18 20:57:41 +00008706 /* CAB: TODO?: Support writing cc to FPSCR->FPCC ?
ceriond953ebb2005-11-29 13:27:20 +00008707 putGST_field( PPC_GST_FPSCR, mkexpr(ccPPC32), 4 );
cerionedf7fc52005-11-18 20:57:41 +00008708 */
sewardjb183b852006-02-03 16:08:03 +00008709 // XXX XXX XXX FIXME
8710 // Also write the result into FPRF (it's not entirely clear how)
sewardje14bb9f2005-07-22 09:39:02 +00008711
cerionedf7fc52005-11-18 20:57:41 +00008712 /* Note: Differences between fcmpu and fcmpo are only in exception
8713 flag settings, which aren't supported anyway. */
sewardje14bb9f2005-07-22 09:39:02 +00008714 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +00008715 case 0x000: // fcmpu (Floating Compare Unordered, PPC32 p403)
8716 DIP("fcmpu crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
8717 break;
8718 case 0x020: // fcmpo (Floating Compare Ordered, PPC32 p402)
8719 DIP("fcmpo crf%d,fr%u,fr%u\n", crfD, frA_addr, frB_addr);
8720 break;
8721 default:
cerion5b2325f2005-12-23 00:55:09 +00008722 vex_printf("dis_fp_cmp(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00008723 return False;
sewardje14bb9f2005-07-22 09:39:02 +00008724 }
8725 return True;
8726}
8727
8728
8729
8730/*
8731 Floating Point Rounding/Conversion Instructions
8732*/
8733static Bool dis_fp_round ( UInt theInstr )
8734{
8735 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00008736 UChar opc1 = ifieldOPC(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00008737 UChar b16to20 = ifieldRegA(theInstr);
sewardj7e846302010-09-03 23:37:02 +00008738 UChar frD_addr = ifieldRegDS(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00008739 UChar frB_addr = ifieldRegB(theInstr);
8740 UInt opc2 = ifieldOPClo10(theInstr);
8741 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00008742
sewardjb183b852006-02-03 16:08:03 +00008743 IRTemp frD = newTemp(Ity_F64);
8744 IRTemp frB = newTemp(Ity_F64);
8745 IRTemp r_tmp32 = newTemp(Ity_I32);
8746 IRTemp r_tmp64 = newTemp(Ity_I64);
8747 IRExpr* rm = get_IR_roundingmode();
sewardje14bb9f2005-07-22 09:39:02 +00008748
sewardjb183b852006-02-03 16:08:03 +00008749 /* By default, we will examine the results of the operation and set
8750 fpscr[FPRF] accordingly. */
8751 Bool set_FPRF = True;
8752
8753 /* By default, if flag_RC is set, we will clear cr1 after the
8754 operation. In reality we should set cr1 to indicate the
8755 exception status of the operation, but since we're not
8756 simulating exceptions, the exception status will appear to be
8757 zero. Hence cr1 should be cleared if this is a . form insn. */
8758 Bool clear_CR1 = True;
sewardj66d5ef22011-04-15 11:55:00 +00008759 if ((!(opc1 == 0x3F || opc1 == 0x3B)) || b16to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00008760 vex_printf("dis_fp_round(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00008761 return False;
8762 }
8763
8764 assign( frB, getFReg(frB_addr));
sewardj66d5ef22011-04-15 11:55:00 +00008765 if (opc1 == 0x3B) {
8766 /* The fcfid[u]s instructions (from ISA 2.06) are a bit odd because
8767 * they're very similar to the other instructions handled here, but have
8768 * a different primary opcode.
8769 */
8770 switch (opc2) {
8771 case 0x34E: // fcfids (Float convert from signed DWord to single precision)
8772 DIP("fcfids%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8773 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
8774 assign( frD, binop( Iop_RoundF64toF32, rm, binop( Iop_I64StoF64, rm,
8775 mkexpr( r_tmp64 ) ) ) );
8776 goto putFR;
8777
8778 case 0x3Ce: // fcfidus (Float convert from unsigned DWord to single precision)
8779 DIP("fcfidus%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8780 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
sewardj95d6f3a2011-04-27 10:07:42 +00008781 assign( frD, unop( Iop_F32toF64, binop( Iop_I64UtoF32, rm, mkexpr( r_tmp64 ) ) ) );
sewardj66d5ef22011-04-15 11:55:00 +00008782 goto putFR;
8783 }
8784 }
8785
sewardje14bb9f2005-07-22 09:39:02 +00008786
sewardje14bb9f2005-07-22 09:39:02 +00008787 switch (opc2) {
cerionf0de28c2005-12-13 20:21:11 +00008788 case 0x00C: // frsp (Float Round to Single, PPC32 p423)
cerion5b2325f2005-12-23 00:55:09 +00008789 DIP("frsp%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00008790 assign( frD, binop( Iop_RoundF64toF32, rm, mkexpr(frB) ));
ceriond953ebb2005-11-29 13:27:20 +00008791 break;
8792
cerionf0de28c2005-12-13 20:21:11 +00008793 case 0x00E: // fctiw (Float Conv to Int, PPC32 p404)
cerion5b2325f2005-12-23 00:55:09 +00008794 DIP("fctiw%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8795 assign( r_tmp32,
sewardj6c299f32009-12-31 18:00:12 +00008796 binop(Iop_F64toI32S, rm, mkexpr(frB)) );
ceriond953ebb2005-11-29 13:27:20 +00008797 assign( frD, unop( Iop_ReinterpI64asF64,
cerion07b07a92005-12-22 14:32:35 +00008798 unop( Iop_32Uto64, mkexpr(r_tmp32))));
sewardjb183b852006-02-03 16:08:03 +00008799 /* FPRF is undefined after fctiw. Leave unchanged. */
8800 set_FPRF = False;
ceriond953ebb2005-11-29 13:27:20 +00008801 break;
8802
cerionf0de28c2005-12-13 20:21:11 +00008803 case 0x00F: // fctiwz (Float Conv to Int, Round to Zero, PPC32 p405)
cerion5b2325f2005-12-23 00:55:09 +00008804 DIP("fctiwz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00008805 assign( r_tmp32,
sewardj6c299f32009-12-31 18:00:12 +00008806 binop(Iop_F64toI32S, mkU32(Irrm_ZERO), mkexpr(frB) ));
ceriond953ebb2005-11-29 13:27:20 +00008807 assign( frD, unop( Iop_ReinterpI64asF64,
cerion07b07a92005-12-22 14:32:35 +00008808 unop( Iop_32Uto64, mkexpr(r_tmp32))));
sewardjb183b852006-02-03 16:08:03 +00008809 /* FPRF is undefined after fctiwz. Leave unchanged. */
8810 set_FPRF = False;
ceriond953ebb2005-11-29 13:27:20 +00008811 break;
cerionf0de28c2005-12-13 20:21:11 +00008812
sewardj4aa412a2011-07-24 14:13:21 +00008813 case 0x08F: case 0x08E: // fctiwu[z]
8814 DIP("fctiwu%s%s fr%u,fr%u\n", opc2 == 0x08F ? "z" : "",
8815 flag_rC ? ".":"", frD_addr, frB_addr);
8816 assign( r_tmp32,
8817 binop( Iop_F64toI32U,
8818 opc2 == 0x08F ? mkU32( Irrm_ZERO ) : rm,
8819 mkexpr( frB ) ) );
8820 assign( frD, unop( Iop_ReinterpI64asF64,
8821 unop( Iop_32Uto64, mkexpr(r_tmp32))));
8822 /* FPRF is undefined after fctiwz. Leave unchanged. */
8823 set_FPRF = False;
8824 break;
8825
8826
cerion5b2325f2005-12-23 00:55:09 +00008827 case 0x32E: // fctid (Float Conv to Int DWord, PPC64 p437)
8828 DIP("fctid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8829 assign( r_tmp64,
sewardj6c299f32009-12-31 18:00:12 +00008830 binop(Iop_F64toI64S, rm, mkexpr(frB)) );
cerion07b07a92005-12-22 14:32:35 +00008831 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
sewardjb183b852006-02-03 16:08:03 +00008832 /* FPRF is undefined after fctid. Leave unchanged. */
8833 set_FPRF = False;
cerion07b07a92005-12-22 14:32:35 +00008834 break;
cerionf0de28c2005-12-13 20:21:11 +00008835
cerion5b2325f2005-12-23 00:55:09 +00008836 case 0x32F: // fctidz (Float Conv to Int DWord, Round to Zero, PPC64 p437)
8837 DIP("fctidz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
sewardjb183b852006-02-03 16:08:03 +00008838 assign( r_tmp64,
sewardj6c299f32009-12-31 18:00:12 +00008839 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
cerion07b07a92005-12-22 14:32:35 +00008840 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
sewardjb183b852006-02-03 16:08:03 +00008841 /* FPRF is undefined after fctidz. Leave unchanged. */
8842 set_FPRF = False;
cerion07b07a92005-12-22 14:32:35 +00008843 break;
cerionf0de28c2005-12-13 20:21:11 +00008844
sewardj4aa412a2011-07-24 14:13:21 +00008845 case 0x3AE: case 0x3AF: // fctidu[z] (Float Conv to Int DWord Unsigned [Round to Zero])
8846 {
8847 DIP("fctidu%s%s fr%u,fr%u\n", opc2 == 0x3AE ? "" : "z",
8848 flag_rC ? ".":"", frD_addr, frB_addr);
8849 assign( r_tmp64,
8850 binop(Iop_F64toI64U, opc2 == 0x3AE ? rm : mkU32(Irrm_ZERO), mkexpr(frB)) );
8851 assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
8852 /* FPRF is undefined after fctidz. Leave unchanged. */
8853 set_FPRF = False;
8854 break;
8855 }
cerion5b2325f2005-12-23 00:55:09 +00008856 case 0x34E: // fcfid (Float Conv from Int DWord, PPC64 p434)
8857 DIP("fcfid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
cerion07b07a92005-12-22 14:32:35 +00008858 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
sewardjb183b852006-02-03 16:08:03 +00008859 assign( frD,
sewardj6c299f32009-12-31 18:00:12 +00008860 binop(Iop_I64StoF64, rm, mkexpr(r_tmp64)) );
cerion07b07a92005-12-22 14:32:35 +00008861 break;
cerionf0de28c2005-12-13 20:21:11 +00008862
sewardj66d5ef22011-04-15 11:55:00 +00008863 case 0x3CE: // fcfidu (Float convert from unsigned DWord)
8864 DIP("fcfidu%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8865 assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
8866 assign( frD, binop( Iop_I64UtoF64, rm, mkexpr( r_tmp64 ) ) );
8867 break;
8868
sewardj7e846302010-09-03 23:37:02 +00008869 case 0x188: case 0x1A8: case 0x1C8: case 0x1E8: // frin, friz, frip, frim
8870 switch(opc2) {
8871 case 0x188: // frin (Floating Round to Integer Nearest)
8872 DIP("frin%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8873 assign( r_tmp64,
8874 binop(Iop_F64toI64S, mkU32(Irrm_NEAREST), mkexpr(frB)) );
8875 break;
8876 case 0x1A8: // friz (Floating Round to Integer Toward Zero)
8877 DIP("friz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8878 assign( r_tmp64,
8879 binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
8880 break;
8881 case 0x1C8: // frip (Floating Round to Integer Plus)
8882 DIP("frip%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8883 assign( r_tmp64,
8884 binop(Iop_F64toI64S, mkU32(Irrm_PosINF), mkexpr(frB)) );
8885 break;
8886 case 0x1E8: // frim (Floating Round to Integer Minus)
8887 DIP("frim%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
8888 assign( r_tmp64,
8889 binop(Iop_F64toI64S, mkU32(Irrm_NegINF), mkexpr(frB)) );
8890 break;
8891 }
8892
8893 /* don't use the rounded integer if frB is outside -9e18..9e18 */
8894 /* F64 has only log10(2**52) significant digits anyway */
8895 /* need to preserve sign of zero */
8896 /* frD = (fabs(frB) > 9e18) ? frB :
8897 (sign(frB)) ? -fabs((double)r_tmp64) : (double)r_tmp64 */
florian99dd03e2013-01-29 03:56:06 +00008898 assign(frD, IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00008899 binop(Iop_CmpNE8,
8900 unop(Iop_32to8,
8901 binop(Iop_CmpF64,
8902 IRExpr_Const(IRConst_F64(9e18)),
8903 unop(Iop_AbsF64, mkexpr(frB)))),
8904 mkU8(0)),
florian99dd03e2013-01-29 03:56:06 +00008905 mkexpr(frB),
8906 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +00008907 binop(Iop_CmpNE32,
8908 binop(Iop_Shr32,
8909 unop(Iop_64HIto32,
8910 unop(Iop_ReinterpF64asI64,
8911 mkexpr(frB))),
8912 mkU8(31)),
8913 mkU32(0)),
sewardj009230b2013-01-26 11:47:55 +00008914 unop(Iop_NegF64,
8915 unop( Iop_AbsF64,
8916 binop(Iop_I64StoF64, mkU32(0),
florian99dd03e2013-01-29 03:56:06 +00008917 mkexpr(r_tmp64)) )),
8918 binop(Iop_I64StoF64, mkU32(0), mkexpr(r_tmp64) )
8919 )
sewardj009230b2013-01-26 11:47:55 +00008920 ));
sewardj7e846302010-09-03 23:37:02 +00008921 break;
8922
ceriond953ebb2005-11-29 13:27:20 +00008923 default:
cerion5b2325f2005-12-23 00:55:09 +00008924 vex_printf("dis_fp_round(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00008925 return False;
sewardje14bb9f2005-07-22 09:39:02 +00008926 }
sewardj66d5ef22011-04-15 11:55:00 +00008927putFR:
sewardje14bb9f2005-07-22 09:39:02 +00008928 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00008929
8930 if (set_FPRF) {
8931 // XXX XXX XXX FIXME
8932 // set FPRF from frD
8933 }
8934
8935 if (flag_rC && clear_CR1) {
8936 putCR321( 1, mkU8(0) );
8937 putCR0( 1, mkU8(0) );
8938 }
8939
sewardje14bb9f2005-07-22 09:39:02 +00008940 return True;
8941}
8942
sewardj7e846302010-09-03 23:37:02 +00008943/*
8944 Floating Point Pair Instructions
8945*/
8946static Bool dis_fp_pair ( UInt theInstr )
8947{
8948 /* X-Form/DS-Form */
8949 UChar opc1 = ifieldOPC(theInstr);
8950 UChar frT_hi_addr = ifieldRegDS(theInstr);
8951 UChar frT_lo_addr = frT_hi_addr + 1;
8952 UChar rA_addr = ifieldRegA(theInstr);
8953 UChar rB_addr = ifieldRegB(theInstr);
8954 UInt uimm16 = ifieldUIMM16(theInstr);
8955 Int simm16 = extend_s_16to32(uimm16);
8956 UInt opc2 = ifieldOPClo10(theInstr);
8957 IRType ty = mode64 ? Ity_I64 : Ity_I32;
8958 IRTemp EA_hi = newTemp(ty);
8959 IRTemp EA_lo = newTemp(ty);
8960 IRTemp frT_hi = newTemp(Ity_F64);
8961 IRTemp frT_lo = newTemp(Ity_F64);
8962 UChar b0 = ifieldBIT0(theInstr);
8963 Bool is_load = 0;
8964
8965 if ((frT_hi_addr %2) != 0) {
8966 vex_printf("dis_fp_pair(ppc) : odd frT register\n");
8967 return False;
8968 }
8969
8970 switch (opc1) {
8971 case 0x1F: // register offset
8972 switch(opc2) {
8973 case 0x317: // lfdpx (FP Load Double Pair X-form, ISA 2.05 p125)
8974 DIP("ldpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
8975 is_load = 1;
8976 break;
8977 case 0x397: // stfdpx (FP STORE Double Pair X-form, ISA 2.05 p125)
8978 DIP("stdpx fr%u,r%u,r%u\n", frT_hi_addr, rA_addr, rB_addr);
8979 break;
8980 default:
8981 vex_printf("dis_fp_pair(ppc) : X-form wrong opc2\n");
8982 return False;
8983 }
8984
8985 if (b0 != 0) {
8986 vex_printf("dis_fp_pair(ppc)(0x1F,b0)\n");
8987 return False;
8988 }
8989 assign( EA_hi, ea_rAor0_idxd( rA_addr, rB_addr ) );
8990 break;
8991 case 0x39: // lfdp (FP Load Double Pair DS-form, ISA 2.05 p125)
8992 DIP("lfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
8993 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
8994 is_load = 1;
8995 break;
8996 case 0x3d: // stfdp (FP Store Double Pair DS-form, ISA 2.05 p125)
8997 DIP("stfdp fr%u,%d(r%u)\n", frT_hi_addr, simm16, rA_addr);
8998 assign( EA_hi, ea_rAor0_simm( rA_addr, simm16 ) );
8999 break;
9000 default: // immediate offset
9001 vex_printf("dis_fp_pair(ppc)(instr)\n");
9002 return False;
9003 }
9004
9005 if (mode64)
9006 assign( EA_lo, binop(Iop_Add64, mkexpr(EA_hi), mkU64(8)) );
9007 else
9008 assign( EA_lo, binop(Iop_Add32, mkexpr(EA_hi), mkU32(8)) );
9009
9010 assign( frT_hi, getFReg(frT_hi_addr) );
9011 assign( frT_lo, getFReg(frT_lo_addr) );
9012
9013 if (is_load) {
carll1f5fe1f2014-08-07 23:25:23 +00009014 putFReg( frT_hi_addr, load(Ity_F64, mkexpr(EA_hi)) );
9015 putFReg( frT_lo_addr, load(Ity_F64, mkexpr(EA_lo)) );
sewardj7e846302010-09-03 23:37:02 +00009016 } else {
carll1f5fe1f2014-08-07 23:25:23 +00009017 store( mkexpr(EA_hi), mkexpr(frT_hi) );
9018 store( mkexpr(EA_lo), mkexpr(frT_lo) );
sewardj7e846302010-09-03 23:37:02 +00009019 }
9020
9021 return True;
9022}
sewardje14bb9f2005-07-22 09:39:02 +00009023
9024
9025/*
carll78850ae2013-09-10 18:46:40 +00009026 Floating Point Merge Instructions
9027*/
9028static Bool dis_fp_merge ( UInt theInstr )
9029{
9030 /* X-Form */
9031 UInt opc2 = ifieldOPClo10(theInstr);
9032 UChar frD_addr = ifieldRegDS(theInstr);
9033 UChar frA_addr = ifieldRegA(theInstr);
9034 UChar frB_addr = ifieldRegB(theInstr);
9035
9036 IRTemp frD = newTemp(Ity_F64);
9037 IRTemp frA = newTemp(Ity_F64);
9038 IRTemp frB = newTemp(Ity_F64);
9039
9040 assign( frA, getFReg(frA_addr));
9041 assign( frB, getFReg(frB_addr));
9042
9043 switch (opc2) {
9044 case 0x3c6: // fmrgew floating merge even word
9045 DIP("fmrgew fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
9046
9047 assign( frD, unop( Iop_ReinterpI64asF64,
9048 binop( Iop_32HLto64,
9049 unop( Iop_64HIto32,
9050 unop( Iop_ReinterpF64asI64,
9051 mkexpr(frA) ) ),
9052 unop( Iop_64HIto32,
9053 unop( Iop_ReinterpF64asI64,
9054 mkexpr(frB) ) ) ) ) );
9055 break;
9056
9057 case 0x346: // fmrgow floating merge odd word
9058 DIP("fmrgow fr%u,fr%u,fr%u\n", frD_addr, frA_addr, frB_addr);
9059
9060 assign( frD, unop( Iop_ReinterpI64asF64,
9061 binop( Iop_32HLto64,
9062 unop( Iop_64to32,
9063 unop( Iop_ReinterpF64asI64,
9064 mkexpr(frA) ) ),
9065 unop( Iop_64to32,
9066 unop( Iop_ReinterpF64asI64,
9067 mkexpr(frB) ) ) ) ) );
9068 break;
9069
9070 default:
9071 vex_printf("dis_fp_merge(ppc)(opc2)\n");
9072 return False;
9073 }
9074
9075 putFReg( frD_addr, mkexpr(frD) );
9076 return True;
9077}
9078
9079/*
sewardje14bb9f2005-07-22 09:39:02 +00009080 Floating Point Move Instructions
9081*/
9082static Bool dis_fp_move ( UInt theInstr )
9083{
9084 /* X-Form */
cerion76de5cf2005-11-18 18:25:12 +00009085 UChar opc1 = ifieldOPC(theInstr);
9086 UChar frD_addr = ifieldRegDS(theInstr);
sewardj7e846302010-09-03 23:37:02 +00009087 UChar frA_addr = ifieldRegA(theInstr);
cerion76de5cf2005-11-18 18:25:12 +00009088 UChar frB_addr = ifieldRegB(theInstr);
9089 UInt opc2 = ifieldOPClo10(theInstr);
9090 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00009091
9092 IRTemp frD = newTemp(Ity_F64);
9093 IRTemp frB = newTemp(Ity_F64);
sewardj7e846302010-09-03 23:37:02 +00009094 IRTemp itmpB = newTemp(Ity_F64);
9095 IRTemp frA;
9096 IRTemp signA;
9097 IRTemp hiD;
sewardje14bb9f2005-07-22 09:39:02 +00009098
sewardj7e846302010-09-03 23:37:02 +00009099 if (opc1 != 0x3F || (frA_addr != 0 && opc2 != 0x008)) {
cerion5b2325f2005-12-23 00:55:09 +00009100 vex_printf("dis_fp_move(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009101 return False;
9102 }
9103
9104 assign( frB, getFReg(frB_addr));
9105
sewardje14bb9f2005-07-22 09:39:02 +00009106 switch (opc2) {
sewardj7e846302010-09-03 23:37:02 +00009107 case 0x008: // fcpsgn (Floating Copy Sign, ISA_V2.05 p126)
9108 DIP("fcpsgn%s fr%u,fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frA_addr,
9109 frB_addr);
9110 signA = newTemp(Ity_I32);
9111 hiD = newTemp(Ity_I32);
9112 itmpB = newTemp(Ity_I64);
9113 frA = newTemp(Ity_F64);
9114 assign( frA, getFReg(frA_addr) );
9115
9116 /* get A's sign bit */
9117 assign(signA, binop(Iop_And32,
9118 unop(Iop_64HIto32, unop(Iop_ReinterpF64asI64,
9119 mkexpr(frA))),
9120 mkU32(0x80000000)) );
9121
9122 assign( itmpB, unop(Iop_ReinterpF64asI64, mkexpr(frB)) );
9123
9124 /* mask off B's sign bit and or in A's sign bit */
9125 assign(hiD, binop(Iop_Or32,
9126 binop(Iop_And32,
9127 unop(Iop_64HIto32,
9128 mkexpr(itmpB)), /* frB's high 32 bits */
9129 mkU32(0x7fffffff)),
9130 mkexpr(signA)) );
9131
9132 /* combine hiD/loB into frD */
9133 assign( frD, unop(Iop_ReinterpI64asF64,
9134 binop(Iop_32HLto64,
9135 mkexpr(hiD),
9136 unop(Iop_64to32,
9137 mkexpr(itmpB)))) ); /* frB's low 32 bits */
9138 break;
9139
ceriond953ebb2005-11-29 13:27:20 +00009140 case 0x028: // fneg (Floating Negate, PPC32 p416)
cerion5b2325f2005-12-23 00:55:09 +00009141 DIP("fneg%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009142 assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
9143 break;
9144
9145 case 0x048: // fmr (Floating Move Register, PPC32 p410)
cerion5b2325f2005-12-23 00:55:09 +00009146 DIP("fmr%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009147 assign( frD, mkexpr(frB) );
9148 break;
9149
9150 case 0x088: // fnabs (Floating Negative Absolute Value, PPC32 p415)
cerion5b2325f2005-12-23 00:55:09 +00009151 DIP("fnabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009152 assign( frD, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr(frB) )));
9153 break;
9154
9155 case 0x108: // fabs (Floating Absolute Value, PPC32 p399)
cerion5b2325f2005-12-23 00:55:09 +00009156 DIP("fabs%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
ceriond953ebb2005-11-29 13:27:20 +00009157 assign( frD, unop( Iop_AbsF64, mkexpr(frB) ));
9158 break;
9159
9160 default:
cerion5b2325f2005-12-23 00:55:09 +00009161 vex_printf("dis_fp_move(ppc)(opc2)\n");
ceriond953ebb2005-11-29 13:27:20 +00009162 return False;
sewardje14bb9f2005-07-22 09:39:02 +00009163 }
9164
9165 putFReg( frD_addr, mkexpr(frD) );
sewardjb183b852006-02-03 16:08:03 +00009166
9167 /* None of these change FPRF. cr1 is set in the usual way though,
9168 if flag_rC is set. */
9169
9170 if (flag_rC) {
9171 putCR321( 1, mkU8(0) );
9172 putCR0( 1, mkU8(0) );
9173 }
9174
sewardje14bb9f2005-07-22 09:39:02 +00009175 return True;
9176}
9177
9178
9179
9180/*
9181 Floating Point Status/Control Register Instructions
9182*/
sewardjc6bbd472012-04-02 10:20:48 +00009183static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
sewardje14bb9f2005-07-22 09:39:02 +00009184{
cerion76de5cf2005-11-18 18:25:12 +00009185 /* Many forms - see each switch case */
9186 UChar opc1 = ifieldOPC(theInstr);
9187 UInt opc2 = ifieldOPClo10(theInstr);
9188 UChar flag_rC = ifieldBIT0(theInstr);
sewardje14bb9f2005-07-22 09:39:02 +00009189
9190 if (opc1 != 0x3F) {
cerion5b2325f2005-12-23 00:55:09 +00009191 vex_printf("dis_fp_scr(ppc)(instr)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009192 return False;
9193 }
9194
9195 switch (opc2) {
cerion3ea49ee2006-01-04 10:53:00 +00009196 case 0x026: { // mtfsb1 (Move to FPSCR Bit 1, PPC32 p479)
9197 // Bit crbD of the FPSCR is set.
9198 UChar crbD = ifieldRegDS(theInstr);
9199 UInt b11to20 = IFIELD(theInstr, 11, 10);
9200
9201 if (b11to20 != 0) {
9202 vex_printf("dis_fp_scr(ppc)(instr,mtfsb1)\n");
9203 return False;
9204 }
9205 DIP("mtfsb1%s crb%d \n", flag_rC ? ".":"", crbD);
sewardjc6bbd472012-04-02 10:20:48 +00009206 putGST_masked( PPC_GST_FPSCR, mkU64( 1 <<( 31 - crbD ) ),
9207 1ULL << ( 31 - crbD ) );
cerion3ea49ee2006-01-04 10:53:00 +00009208 break;
9209 }
9210
sewardj496b88f2006-10-04 17:46:11 +00009211 case 0x040: { // mcrfs (Move to Condition Register from FPSCR, PPC32 p465)
9212 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
9213 UChar b21to22 = toUChar( IFIELD( theInstr, 21, 2 ) );
9214 UChar crfS = toUChar( IFIELD( theInstr, 18, 3 ) );
9215 UChar b11to17 = toUChar( IFIELD( theInstr, 11, 7 ) );
9216 IRTemp tmp = newTemp(Ity_I32);
9217 IRExpr* fpscr_all;
9218 if (b21to22 != 0 || b11to17 != 0 || flag_rC != 0) {
9219 vex_printf("dis_fp_scr(ppc)(instr,mcrfs)\n");
9220 return False;
9221 }
9222 DIP("mcrfs crf%d,crf%d\n", crfD, crfS);
9223 vassert(crfD < 8);
9224 vassert(crfS < 8);
9225 fpscr_all = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
9226 assign( tmp, binop(Iop_And32,
9227 binop(Iop_Shr32,fpscr_all,mkU8(4 * (7-crfS))),
9228 mkU32(0xF)) );
9229 putGST_field( PPC_GST_CR, mkexpr(tmp), crfD );
9230 break;
9231 }
sewardj0e2cc672005-07-29 21:58:51 +00009232
9233 case 0x046: { // mtfsb0 (Move to FPSCR Bit 0, PPC32 p478)
9234 // Bit crbD of the FPSCR is cleared.
cerion76de5cf2005-11-18 18:25:12 +00009235 UChar crbD = ifieldRegDS(theInstr);
9236 UInt b11to20 = IFIELD(theInstr, 11, 10);
sewardj0e2cc672005-07-29 21:58:51 +00009237
9238 if (b11to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00009239 vex_printf("dis_fp_scr(ppc)(instr,mtfsb0)\n");
sewardj0e2cc672005-07-29 21:58:51 +00009240 return False;
9241 }
cerion5b2325f2005-12-23 00:55:09 +00009242 DIP("mtfsb0%s crb%d\n", flag_rC ? ".":"", crbD);
sewardjc6bbd472012-04-02 10:20:48 +00009243 putGST_masked( PPC_GST_FPSCR, mkU64( 0 ), 1ULL << ( 31 - crbD ) );
sewardj0e2cc672005-07-29 21:58:51 +00009244 break;
9245 }
9246
9247 case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
sewardjc6bbd472012-04-02 10:20:48 +00009248 UInt crfD = IFIELD( theInstr, 23, 3 );
cerion76de5cf2005-11-18 18:25:12 +00009249 UChar b16to22 = toUChar( IFIELD( theInstr, 16, 7 ) );
9250 UChar IMM = toUChar( IFIELD( theInstr, 12, 4 ) );
9251 UChar b11 = toUChar( IFIELD( theInstr, 11, 1 ) );
sewardjc6bbd472012-04-02 10:20:48 +00009252 UChar Wbit;
sewardj0e2cc672005-07-29 21:58:51 +00009253
9254 if (b16to22 != 0 || b11 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00009255 vex_printf("dis_fp_scr(ppc)(instr,mtfsfi)\n");
sewardj0e2cc672005-07-29 21:58:51 +00009256 return False;
9257 }
cerion5b2325f2005-12-23 00:55:09 +00009258 DIP("mtfsfi%s crf%d,%d\n", flag_rC ? ".":"", crfD, IMM);
sewardjc6bbd472012-04-02 10:20:48 +00009259 if (GX_level) {
9260 /* This implies that Decimal Floating Point is supported, and the
9261 * FPSCR must be managed as a 64-bit register.
9262 */
9263 Wbit = toUChar( IFIELD(theInstr, 16, 1) );
9264 } else {
9265 Wbit = 0;
9266 }
9267 crfD = crfD + (8 * (1 - Wbit) );
9268 putGST_field( PPC_GST_FPSCR, mkU32( IMM ), crfD );
sewardj0e2cc672005-07-29 21:58:51 +00009269 break;
9270 }
sewardje14bb9f2005-07-22 09:39:02 +00009271
9272 case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
sewardj496b88f2006-10-04 17:46:11 +00009273 UChar frD_addr = ifieldRegDS(theInstr);
9274 UInt b11to20 = IFIELD(theInstr, 11, 10);
sewardjc6bbd472012-04-02 10:20:48 +00009275 IRExpr* fpscr_lower = getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN );
9276 IRExpr* fpscr_upper = getGST_masked_upper( PPC_GST_FPSCR,
9277 MASK_FPSCR_DRN );
sewardje14bb9f2005-07-22 09:39:02 +00009278
9279 if (b11to20 != 0) {
cerion5b2325f2005-12-23 00:55:09 +00009280 vex_printf("dis_fp_scr(ppc)(instr,mffs)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009281 return False;
9282 }
cerion5b2325f2005-12-23 00:55:09 +00009283 DIP("mffs%s fr%u\n", flag_rC ? ".":"", frD_addr);
9284 putFReg( frD_addr,
9285 unop( Iop_ReinterpI64asF64,
sewardjc6bbd472012-04-02 10:20:48 +00009286 binop( Iop_32HLto64, fpscr_upper, fpscr_lower ) ) );
sewardje14bb9f2005-07-22 09:39:02 +00009287 break;
9288 }
9289
9290 case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
cerion76de5cf2005-11-18 18:25:12 +00009291 UChar b25 = toUChar( IFIELD(theInstr, 25, 1) );
9292 UChar FM = toUChar( IFIELD(theInstr, 17, 8) );
cerion76de5cf2005-11-18 18:25:12 +00009293 UChar frB_addr = ifieldRegB(theInstr);
9294 IRTemp frB = newTemp(Ity_F64);
sewardjc6bbd472012-04-02 10:20:48 +00009295 IRTemp rB_64 = newTemp( Ity_I64 );
9296 Int i;
9297 ULong mask;
9298 UChar Wbit;
9299#define BFP_MASK_SEED 0x3000000000000000ULL
9300#define DFP_MASK_SEED 0x7000000000000000ULL
9301
9302 if (GX_level) {
9303 /* This implies that Decimal Floating Point is supported, and the
9304 * FPSCR must be managed as a 64-bit register.
9305 */
9306 Wbit = toUChar( IFIELD(theInstr, 16, 1) );
9307 } else {
9308 Wbit = 0;
9309 }
sewardje14bb9f2005-07-22 09:39:02 +00009310
sewardj7e846302010-09-03 23:37:02 +00009311 if (b25 == 1) {
9312 /* new 64 bit move variant for power 6. If L field (bit 25) is
9313 * a one do a full 64 bit move. Note, the FPSCR is not really
9314 * properly modeled. This instruciton only changes the value of
9315 * the rounding mode. The HW exception bits do not get set in
9316 * the simulator. 1/12/09
9317 */
9318 DIP("mtfsf%s %d,fr%u (L=1)\n", flag_rC ? ".":"", FM, frB_addr);
9319 mask = 0xFF;
9320
9321 } else {
9322 DIP("mtfsf%s %d,fr%u\n", flag_rC ? ".":"", FM, frB_addr);
9323 // Build 32bit mask from FM:
9324 mask = 0;
9325 for (i=0; i<8; i++) {
9326 if ((FM & (1<<(7-i))) == 1) {
sewardjc6bbd472012-04-02 10:20:48 +00009327 /* FPSCR field k is set to the contents of the corresponding
9328 * field of register FRB, where k = i+8x(1-W). In the Power
9329 * ISA, register field numbering is from left to right, so field
9330 * 15 is the least significant field in a 64-bit register. To
9331 * generate the mask, we set all the appropriate rounding mode
9332 * bits in the highest order nibble (field 0) and shift right
9333 * 'k x nibble length'.
9334 */
9335 if (Wbit)
9336 mask |= DFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
9337 else
9338 mask |= BFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
sewardj7e846302010-09-03 23:37:02 +00009339 }
9340 }
9341 }
sewardje14bb9f2005-07-22 09:39:02 +00009342 assign( frB, getFReg(frB_addr));
sewardjc6bbd472012-04-02 10:20:48 +00009343 assign( rB_64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
9344 putGST_masked( PPC_GST_FPSCR, mkexpr( rB_64 ), mask );
sewardje14bb9f2005-07-22 09:39:02 +00009345 break;
9346 }
9347
9348 default:
cerion5b2325f2005-12-23 00:55:09 +00009349 vex_printf("dis_fp_scr(ppc)(opc2)\n");
sewardje14bb9f2005-07-22 09:39:02 +00009350 return False;
9351 }
9352 return True;
9353}
9354
sewardjc6bbd472012-04-02 10:20:48 +00009355/*------------------------------------------------------------*/
sewardj5eff1c52012-04-29 20:19:17 +00009356/*--- Decimal Floating Point (DFP) Helper functions ---*/
9357/*------------------------------------------------------------*/
9358#define DFP_LONG 1
9359#define DFP_EXTND 2
sewardj4c96e612012-06-02 23:47:02 +00009360#define DFP_LONG_BIAS 398
sewardj5eff1c52012-04-29 20:19:17 +00009361#define DFP_LONG_ENCODED_FIELD_MASK 0x1F00
sewardj4c96e612012-06-02 23:47:02 +00009362#define DFP_EXTND_BIAS 6176
sewardj5eff1c52012-04-29 20:19:17 +00009363#define DFP_EXTND_ENCODED_FIELD_MASK 0x1F000
9364#define DFP_LONG_EXP_MSK 0XFF
9365#define DFP_EXTND_EXP_MSK 0XFFF
9366
9367#define DFP_G_FIELD_LONG_MASK 0x7FFC0000 // upper 32-bits only
9368#define DFP_LONG_GFIELD_RT_SHIFT (63 - 13 - 32) // adj for upper 32-bits
9369#define DFP_G_FIELD_EXTND_MASK 0x7FFFC000 // upper 32-bits only
9370#define DFP_EXTND_GFIELD_RT_SHIFT (63 - 17 - 32) //adj for upper 32 bits
sewardj5eff1c52012-04-29 20:19:17 +00009371#define DFP_T_FIELD_LONG_MASK 0x3FFFF // mask for upper 32-bits
9372#define DFP_T_FIELD_EXTND_MASK 0x03FFFF // mask for upper 32-bits
sewardj5eff1c52012-04-29 20:19:17 +00009373#define DFP_LONG_EXP_MAX 369 // biased max
9374#define DFP_LONG_EXP_MIN 0 // biased min
9375#define DFP_EXTND_EXP_MAX 6111 // biased max
9376#define DFP_EXTND_EXP_MIN 0 // biased min
sewardj4c96e612012-06-02 23:47:02 +00009377#define DFP_LONG_MAX_SIG_DIGITS 16
9378#define DFP_EXTND_MAX_SIG_DIGITS 34
9379#define MAX_DIGITS_IN_STRING 8
9380
sewardj5eff1c52012-04-29 20:19:17 +00009381
9382#define AND(x, y) binop( Iop_And32, x, y )
sewardj5eff1c52012-04-29 20:19:17 +00009383#define AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
sewardj4c96e612012-06-02 23:47:02 +00009384#define OR(x, y) binop( Iop_Or32, x, y )
sewardj5eff1c52012-04-29 20:19:17 +00009385#define OR3(x, y, z) OR( x, OR( y, z ) )
9386#define OR4(w, x, y, z) OR( OR( w, x ), OR( y, z ) )
sewardj4c96e612012-06-02 23:47:02 +00009387#define NOT(x) unop( Iop_1Uto32, unop( Iop_Not1, unop( Iop_32to1, mkexpr( x ) ) ) )
9388
sewardj5eff1c52012-04-29 20:19:17 +00009389#define SHL(value, by) binop( Iop_Shl32, value, mkU8( by ) )
sewardj4c96e612012-06-02 23:47:02 +00009390#define SHR(value, by) binop( Iop_Shr32, value, mkU8( by ) )
9391
sewardjcb06d5e2012-04-30 08:10:11 +00009392#define BITS5(_b4,_b3,_b2,_b1,_b0) \
9393 (((_b4) << 4) | ((_b3) << 3) | ((_b2) << 2) | \
9394 ((_b1) << 1) | ((_b0) << 0))
sewardj5eff1c52012-04-29 20:19:17 +00009395
sewardj4c96e612012-06-02 23:47:02 +00009396static IRExpr * Gfield_encoding( IRExpr * lmexp, IRExpr * lmd32 )
sewardj5eff1c52012-04-29 20:19:17 +00009397{
sewardj4c96e612012-06-02 23:47:02 +00009398 IRTemp lmd_07_mask = newTemp( Ity_I32 );
9399 IRTemp lmd_8_mask = newTemp( Ity_I32 );
9400 IRTemp lmd_9_mask = newTemp( Ity_I32 );
9401 IRTemp lmexp_00_mask = newTemp( Ity_I32 );
9402 IRTemp lmexp_01_mask = newTemp( Ity_I32 );
9403 IRTemp lmexp_10_mask = newTemp( Ity_I32 );
9404 IRTemp lmd_07_val = newTemp( Ity_I32 );
9405 IRTemp lmd_8_val = newTemp( Ity_I32 );
9406 IRTemp lmd_9_val = newTemp( Ity_I32 );
sewardj5eff1c52012-04-29 20:19:17 +00009407
sewardj4c96e612012-06-02 23:47:02 +00009408 /* The encodig is as follows:
9409 * lmd - left most digit
9410 * lme - left most 2-bits of the exponent
9411 *
9412 * lmd
9413 * 0 - 7 (lmexp << 3) | lmd
9414 * 8 0b11000 (24 decimal) if lme=0b00;
9415 * 0b11010 (26 decimal) if lme=0b01;
9416 * 0b11100 (28 decimal) if lme=0b10;
9417 * 9 0b11001 (25 decimal) if lme=0b00;
9418 * 0b11011 (27 decimal) if lme=0b01;
9419 * 0b11101 (29 decimal) if lme=0b10;
9420 */
9421
9422 /* Generate the masks for each condition */
9423 assign( lmd_07_mask,
9424 unop( Iop_1Sto32, binop( Iop_CmpLE32U, lmd32, mkU32( 7 ) ) ) );
9425 assign( lmd_8_mask,
9426 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 8 ) ) ) );
9427 assign( lmd_9_mask,
9428 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 9 ) ) ) );
9429 assign( lmexp_00_mask,
9430 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 0 ) ) ) );
9431 assign( lmexp_01_mask,
9432 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 1 ) ) ) );
9433 assign( lmexp_10_mask,
9434 unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 2 ) ) ) );
9435
9436 /* Generate the values for each LMD condition, assuming the condition
9437 * is TRUE.
9438 */
9439 assign( lmd_07_val,
9440 binop( Iop_Or32, binop( Iop_Shl32, lmexp, mkU8( 3 ) ), lmd32 ) );
9441 assign( lmd_8_val,
9442 binop( Iop_Or32,
9443 binop( Iop_Or32,
9444 binop( Iop_And32,
9445 mkexpr( lmexp_00_mask ),
9446 mkU32( 24 ) ),
9447 binop( Iop_And32,
9448 mkexpr( lmexp_01_mask ),
9449 mkU32( 26 ) ) ),
9450 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 28 ) ) ) );
9451 assign( lmd_9_val,
9452 binop( Iop_Or32,
9453 binop( Iop_Or32,
9454 binop( Iop_And32,
9455 mkexpr( lmexp_00_mask ),
9456 mkU32( 25 ) ),
9457 binop( Iop_And32,
9458 mkexpr( lmexp_01_mask ),
9459 mkU32( 27 ) ) ),
9460 binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 29 ) ) ) );
9461
9462 /* generate the result from the possible LMD values */
9463 return binop( Iop_Or32,
9464 binop( Iop_Or32,
9465 binop( Iop_And32,
9466 mkexpr( lmd_07_mask ),
9467 mkexpr( lmd_07_val ) ),
9468 binop( Iop_And32,
9469 mkexpr( lmd_8_mask ),
9470 mkexpr( lmd_8_val ) ) ),
9471 binop( Iop_And32, mkexpr( lmd_9_mask ), mkexpr( lmd_9_val ) ) );
9472}
9473
9474static void Get_lmd( IRTemp * lmd, IRExpr * gfield_0_4 )
9475{
sewardj5eff1c52012-04-29 20:19:17 +00009476 /* Extract the exponent and the left most digit of the mantissa
9477 * from the G field bits [0:4].
9478 */
9479 IRTemp lmd_07_mask = newTemp( Ity_I32 );
9480 IRTemp lmd_8_00_mask = newTemp( Ity_I32 );
9481 IRTemp lmd_8_01_mask = newTemp( Ity_I32 );
9482 IRTemp lmd_8_10_mask = newTemp( Ity_I32 );
9483 IRTemp lmd_9_00_mask = newTemp( Ity_I32 );
9484 IRTemp lmd_9_01_mask = newTemp( Ity_I32 );
9485 IRTemp lmd_9_10_mask = newTemp( Ity_I32 );
9486
9487 IRTemp lmd_07_val = newTemp( Ity_I32 );
9488 IRTemp lmd_8_val = newTemp( Ity_I32 );
9489 IRTemp lmd_9_val = newTemp( Ity_I32 );
9490
9491 /* The left most digit (LMD) encoding is as follows:
9492 * lmd
9493 * 0 - 7 (lmexp << 3) | lmd
9494 * 8 0b11000 (24 decimal) if lme=0b00;
9495 * 0b11010 (26 decimal) if lme=0b01;
9496 * 0b11100 (28 decimal) if lme=0b10
9497 * 9 0b11001 (25 decimal) if lme=0b00;
9498 * 0b11011 (27 decimal) if lme=0b01;
9499 * 0b11101 (29 decimal) if lme=0b10;
9500 */
9501
9502 /* Generate the masks for each condition of LMD and exponent bits */
sewardjcb06d5e2012-04-30 08:10:11 +00009503 assign( lmd_07_mask,
9504 unop( Iop_1Sto32, binop( Iop_CmpLE32U,
9505 gfield_0_4,
9506 mkU32( BITS5(1,0,1,1,1) ) ) ) );
9507 assign( lmd_8_00_mask,
9508 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9509 gfield_0_4,
9510 mkU32( BITS5(1,1,0,0,0) ) ) ) );
9511 assign( lmd_8_01_mask,
9512 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9513 gfield_0_4,
9514 mkU32( BITS5(1,1,0,1,0) ) ) ) );
9515 assign( lmd_8_10_mask,
9516 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9517 gfield_0_4,
9518 mkU32( BITS5(1,1,1,0,0) ) ) ) );
9519 assign( lmd_9_00_mask,
9520 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9521 gfield_0_4,
9522 mkU32( BITS5(1,1,0,0,1) ) ) ) );
9523 assign( lmd_9_01_mask,
9524 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9525 gfield_0_4,
9526 mkU32( BITS5(1,1,0,1,1) ) ) ) );
9527 assign( lmd_9_10_mask,
9528 unop( Iop_1Sto32, binop( Iop_CmpEQ32,
9529 gfield_0_4,
9530 mkU32( BITS5(1,1,1,0,1) ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +00009531
9532 /* Generate the values for each LMD condition, assuming the condition
9533 * is TRUE.
9534 */
9535 assign( lmd_07_val, binop( Iop_And32, gfield_0_4, mkU32( 0x7 ) ) );
9536 assign( lmd_8_val, mkU32( 0x8 ) );
9537 assign( lmd_9_val, mkU32( 0x9 ) );
9538
9539 assign( *lmd,
9540 OR( OR3 ( AND( mkexpr( lmd_07_mask ), mkexpr( lmd_07_val ) ),
9541 AND( mkexpr( lmd_8_00_mask ), mkexpr( lmd_8_val ) ),
9542 AND( mkexpr( lmd_8_01_mask ), mkexpr( lmd_8_val ) )),
9543 OR4( AND( mkexpr( lmd_8_10_mask ), mkexpr( lmd_8_val ) ),
9544 AND( mkexpr( lmd_9_00_mask ), mkexpr( lmd_9_val ) ),
9545 AND( mkexpr( lmd_9_01_mask ), mkexpr( lmd_9_val ) ),
9546 AND( mkexpr( lmd_9_10_mask ), mkexpr( lmd_9_val ) )
9547 ) ) );
9548}
9549
sewardj4c96e612012-06-02 23:47:02 +00009550#define DIGIT1_SHR 4 // shift digit 1 to bottom 4 bits
9551#define DIGIT2_SHR 8 // shift digit 2 to bottom 4 bits
9552#define DIGIT3_SHR 12
9553#define DIGIT4_SHR 16
9554#define DIGIT5_SHR 20
9555#define DIGIT6_SHR 24
9556#define DIGIT7_SHR 28
9557
9558static IRExpr * bcd_digit_inval( IRExpr * bcd_u, IRExpr * bcd_l )
9559{
9560 /* 60-bit BCD string stored in two 32-bit values. Check that each,
9561 * digit is a valid BCD number, i.e. less then 9.
9562 */
9563 IRTemp valid = newTemp( Ity_I32 );
9564
9565 assign( valid,
9566 AND4( AND4 ( unop( Iop_1Sto32,
9567 binop( Iop_CmpLE32U,
9568 binop( Iop_And32,
9569 bcd_l,
9570 mkU32 ( 0xF ) ),
9571 mkU32( 0x9 ) ) ),
9572 unop( Iop_1Sto32,
9573 binop( Iop_CmpLE32U,
9574 binop( Iop_And32,
9575 binop( Iop_Shr32,
9576 bcd_l,
9577 mkU8 ( DIGIT1_SHR ) ),
9578 mkU32 ( 0xF ) ),
9579 mkU32( 0x9 ) ) ),
9580 unop( Iop_1Sto32,
9581 binop( Iop_CmpLE32U,
9582 binop( Iop_And32,
9583 binop( Iop_Shr32,
9584 bcd_l,
9585 mkU8 ( DIGIT2_SHR ) ),
9586 mkU32 ( 0xF ) ),
9587 mkU32( 0x9 ) ) ),
9588 unop( Iop_1Sto32,
9589 binop( Iop_CmpLE32U,
9590 binop( Iop_And32,
9591 binop( Iop_Shr32,
9592 bcd_l,
9593 mkU8 ( DIGIT3_SHR ) ),
9594 mkU32 ( 0xF ) ),
9595 mkU32( 0x9 ) ) ) ),
9596 AND4 ( unop( Iop_1Sto32,
9597 binop( Iop_CmpLE32U,
9598 binop( Iop_And32,
9599 binop( Iop_Shr32,
9600 bcd_l,
9601 mkU8 ( DIGIT4_SHR ) ),
9602 mkU32 ( 0xF ) ),
9603 mkU32( 0x9 ) ) ),
9604 unop( Iop_1Sto32,
9605 binop( Iop_CmpLE32U,
9606 binop( Iop_And32,
9607 binop( Iop_Shr32,
9608 bcd_l,
9609 mkU8 ( DIGIT5_SHR ) ),
9610 mkU32 ( 0xF ) ),
9611 mkU32( 0x9 ) ) ),
9612 unop( Iop_1Sto32,
9613 binop( Iop_CmpLE32U,
9614 binop( Iop_And32,
9615 binop( Iop_Shr32,
9616 bcd_l,
9617 mkU8 ( DIGIT6_SHR ) ),
9618 mkU32 ( 0xF ) ),
9619 mkU32( 0x9 ) ) ),
9620 unop( Iop_1Sto32,
9621 binop( Iop_CmpLE32U,
9622 binop( Iop_And32,
9623 binop( Iop_Shr32,
9624 bcd_l,
9625 mkU8 ( DIGIT7_SHR ) ),
9626 mkU32 ( 0xF ) ),
9627 mkU32( 0x9 ) ) ) ),
9628 AND4( unop( Iop_1Sto32,
9629 binop( Iop_CmpLE32U,
9630 binop( Iop_And32,
9631 bcd_u,
9632 mkU32 ( 0xF ) ),
9633 mkU32( 0x9 ) ) ),
9634 unop( Iop_1Sto32,
9635 binop( Iop_CmpLE32U,
9636 binop( Iop_And32,
9637 binop( Iop_Shr32,
9638 bcd_u,
9639 mkU8 ( DIGIT1_SHR ) ),
9640 mkU32 ( 0xF ) ),
9641 mkU32( 0x9 ) ) ),
9642 unop( Iop_1Sto32,
9643 binop( Iop_CmpLE32U,
9644 binop( Iop_And32,
9645 binop( Iop_Shr32,
9646 bcd_u,
9647 mkU8 ( DIGIT2_SHR ) ),
9648 mkU32 ( 0xF ) ),
9649 mkU32( 0x9 ) ) ),
9650 unop( Iop_1Sto32,
9651 binop( Iop_CmpLE32U,
9652 binop( Iop_And32,
9653 binop( Iop_Shr32,
9654 bcd_u,
9655 mkU8 ( DIGIT3_SHR ) ),
9656 mkU32 ( 0xF ) ),
9657 mkU32( 0x9 ) ) ) ),
9658 AND4( unop( Iop_1Sto32,
9659 binop( Iop_CmpLE32U,
9660 binop( Iop_And32,
9661 binop( Iop_Shr32,
9662 bcd_u,
9663 mkU8 ( DIGIT4_SHR ) ),
9664 mkU32 ( 0xF ) ),
9665 mkU32( 0x9 ) ) ),
9666 unop( Iop_1Sto32,
9667 binop( Iop_CmpLE32U,
9668 binop( Iop_And32,
9669 binop( Iop_Shr32,
9670 bcd_u,
9671 mkU8 ( DIGIT5_SHR ) ),
9672 mkU32 ( 0xF ) ),
9673 mkU32( 0x9 ) ) ),
9674 unop( Iop_1Sto32,
9675 binop( Iop_CmpLE32U,
9676 binop( Iop_And32,
9677 binop( Iop_Shr32,
9678 bcd_u,
9679 mkU8 ( DIGIT6_SHR ) ),
9680 mkU32 ( 0xF ) ),
9681 mkU32( 0x9 ) ) ),
9682 unop( Iop_1Sto32,
9683 binop( Iop_CmpLE32U,
9684 binop( Iop_And32,
9685 binop( Iop_Shr32,
9686 bcd_u,
9687 mkU8 ( DIGIT7_SHR ) ),
9688 mkU32 ( 0xF ) ),
9689 mkU32( 0x9 ) ) ) ) ) );
9690
9691 return unop( Iop_Not32, mkexpr( valid ) );
9692}
9693#undef DIGIT1_SHR
9694#undef DIGIT2_SHR
9695#undef DIGIT3_SHR
9696#undef DIGIT4_SHR
9697#undef DIGIT5_SHR
9698#undef DIGIT6_SHR
9699#undef DIGIT7_SHR
9700
9701static IRExpr * Generate_neg_sign_mask( IRExpr * sign )
9702{
9703 return binop( Iop_Or32,
9704 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xB ) ) ),
9705 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xD ) ) )
9706 );
9707}
9708
9709static IRExpr * Generate_pos_sign_mask( IRExpr * sign )
9710{
9711 return binop( Iop_Or32,
9712 binop( Iop_Or32,
9713 unop( Iop_1Sto32,
9714 binop( Iop_CmpEQ32, sign, mkU32( 0xA ) ) ),
9715 unop( Iop_1Sto32,
9716 binop( Iop_CmpEQ32, sign, mkU32( 0xC ) ) ) ),
9717 binop( Iop_Or32,
9718 unop( Iop_1Sto32,
9719 binop( Iop_CmpEQ32, sign, mkU32( 0xE ) ) ),
9720 unop( Iop_1Sto32,
9721 binop( Iop_CmpEQ32, sign, mkU32( 0xF ) ) ) ) );
9722}
9723
9724static IRExpr * Generate_sign_bit( IRExpr * pos_sign_mask,
9725 IRExpr * neg_sign_mask )
9726{
9727 return binop( Iop_Or32,
9728 binop( Iop_And32, neg_sign_mask, mkU32( 0x80000000 ) ),
9729 binop( Iop_And32, pos_sign_mask, mkU32( 0x00000000 ) ) );
9730}
9731
9732static IRExpr * Generate_inv_mask( IRExpr * invalid_bcd_mask,
9733 IRExpr * pos_sign_mask,
9734 IRExpr * neg_sign_mask )
9735/* first argument is all 1's if the BCD string had an invalid digit in it. */
9736{
9737 return binop( Iop_Or32,
9738 invalid_bcd_mask,
9739 unop( Iop_1Sto32,
9740 binop( Iop_CmpEQ32,
9741 binop( Iop_Or32, pos_sign_mask, neg_sign_mask ),
9742 mkU32( 0x0 ) ) ) );
9743}
9744
9745static void Generate_132_bit_bcd_string( IRExpr * frBI64_hi, IRExpr * frBI64_lo,
9746 IRTemp * top_12_l, IRTemp * mid_60_u,
9747 IRTemp * mid_60_l, IRTemp * low_60_u,
9748 IRTemp * low_60_l)
9749{
9750 IRTemp tmplow60 = newTemp( Ity_I64 );
9751 IRTemp tmpmid60 = newTemp( Ity_I64 );
9752 IRTemp tmptop12 = newTemp( Ity_I64 );
9753 IRTemp low_50 = newTemp( Ity_I64 );
9754 IRTemp mid_50 = newTemp( Ity_I64 );
9755 IRTemp top_10 = newTemp( Ity_I64 );
9756 IRTemp top_12_u = newTemp( Ity_I32 ); // only needed for a dummy arg
9757
9758 /* Convert the 110-bit densely packed BCD string to a 128-bit BCD string */
9759
9760 /* low_50[49:0] = ((frBI64_lo[49:32] << 14) | frBI64_lo[31:0]) */
9761 assign( low_50,
9762 binop( Iop_32HLto64,
9763 binop( Iop_And32,
9764 unop( Iop_64HIto32, frBI64_lo ),
9765 mkU32( 0x3FFFF ) ),
9766 unop( Iop_64to32, frBI64_lo ) ) );
9767
9768 /* Convert the 50 bit densely packed BCD string to a 60 bit
9769 * BCD string.
9770 */
9771 assign( tmplow60, unop( Iop_DPBtoBCD, mkexpr( low_50 ) ) );
9772 assign( *low_60_u, unop( Iop_64HIto32, mkexpr( tmplow60 ) ) );
9773 assign( *low_60_l, unop( Iop_64to32, mkexpr( tmplow60 ) ) );
9774
9775 /* mid_50[49:0] = ((frBI64_hi[35:32] << 14) | frBI64_hi[31:18]) |
9776 * ((frBI64_hi[17:0] << 14) | frBI64_lo[63:50])
9777 */
9778 assign( mid_50,
9779 binop( Iop_32HLto64,
9780 binop( Iop_Or32,
9781 binop( Iop_Shl32,
9782 binop( Iop_And32,
9783 unop( Iop_64HIto32, frBI64_hi ),
9784 mkU32( 0xF ) ),
9785 mkU8( 14 ) ),
9786 binop( Iop_Shr32,
9787 unop( Iop_64to32, frBI64_hi ),
9788 mkU8( 18 ) ) ),
9789 binop( Iop_Or32,
9790 binop( Iop_Shl32,
9791 unop( Iop_64to32, frBI64_hi ),
9792 mkU8( 14 ) ),
9793 binop( Iop_Shr32,
9794 unop( Iop_64HIto32, frBI64_lo ),
9795 mkU8( 18 ) ) ) ) );
9796
9797 /* Convert the 50 bit densely packed BCD string to a 60 bit
9798 * BCD string.
9799 */
9800 assign( tmpmid60, unop( Iop_DPBtoBCD, mkexpr( mid_50 ) ) );
9801 assign( *mid_60_u, unop( Iop_64HIto32, mkexpr( tmpmid60 ) ) );
9802 assign( *mid_60_l, unop( Iop_64to32, mkexpr( tmpmid60 ) ) );
9803
9804 /* top_10[49:0] = frBI64_hi[45:36]) | */
9805 assign( top_10,
9806 binop( Iop_32HLto64,
9807 mkU32( 0 ),
9808 binop( Iop_And32,
9809 binop( Iop_Shr32,
9810 unop( Iop_64HIto32, frBI64_hi ),
9811 mkU8( 4 ) ),
9812 mkU32( 0x3FF ) ) ) );
9813
9814 /* Convert the 10 bit densely packed BCD string to a 12 bit
9815 * BCD string.
9816 */
9817 assign( tmptop12, unop( Iop_DPBtoBCD, mkexpr( top_10 ) ) );
9818 assign( top_12_u, unop( Iop_64HIto32, mkexpr( tmptop12 ) ) );
9819 assign( *top_12_l, unop( Iop_64to32, mkexpr( tmptop12 ) ) );
9820}
9821
9822static void Count_zeros( int start, IRExpr * init_cnt, IRExpr * init_flag,
9823 IRTemp * final_cnt, IRTemp * final_flag,
9824 IRExpr * string )
9825{
9826 IRTemp cnt[MAX_DIGITS_IN_STRING + 1];IRTemp flag[MAX_DIGITS_IN_STRING+1];
9827 int digits = MAX_DIGITS_IN_STRING;
9828 int i;
9829
9830 cnt[start-1] = newTemp( Ity_I8 );
9831 flag[start-1] = newTemp( Ity_I8 );
9832 assign( cnt[start-1], init_cnt);
9833 assign( flag[start-1], init_flag);
9834
9835 for ( i = start; i <= digits; i++) {
9836 cnt[i] = newTemp( Ity_I8 );
9837 flag[i] = newTemp( Ity_I8 );
9838 assign( cnt[i],
9839 binop( Iop_Add8,
9840 mkexpr( cnt[i-1] ),
9841 binop(Iop_And8,
9842 unop( Iop_1Uto8,
9843 binop(Iop_CmpEQ32,
9844 binop(Iop_And32,
9845 string,
9846 mkU32( 0xF <<
9847 ( ( digits - i ) * 4) ) ),
9848 mkU32( 0 ) ) ),
9849 binop( Iop_Xor8, /* complement flag */
9850 mkexpr( flag[i - 1] ),
9851 mkU8( 0xFF ) ) ) ) );
9852
9853 /* set flag to 1 if digit was not a zero */
9854 assign( flag[i],
9855 binop(Iop_Or8,
9856 unop( Iop_1Sto8,
9857 binop(Iop_CmpNE32,
9858 binop(Iop_And32,
9859 string,
9860 mkU32( 0xF <<
9861 ( (digits - i) * 4) ) ),
9862 mkU32( 0 ) ) ),
9863 mkexpr( flag[i - 1] ) ) );
9864 }
9865
9866 *final_cnt = cnt[digits];
9867 *final_flag = flag[digits];
9868}
9869
9870static IRExpr * Count_leading_zeros_60( IRExpr * lmd, IRExpr * upper_28,
9871 IRExpr * low_32 )
9872{
9873 IRTemp num_lmd = newTemp( Ity_I8 );
9874 IRTemp num_upper = newTemp( Ity_I8 );
9875 IRTemp num_low = newTemp( Ity_I8 );
9876 IRTemp lmd_flag = newTemp( Ity_I8 );
9877 IRTemp upper_flag = newTemp( Ity_I8 );
9878 IRTemp low_flag = newTemp( Ity_I8 );
9879
9880 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
9881 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
9882
9883 Count_zeros( 2,
9884 mkexpr( num_lmd ),
9885 mkexpr( lmd_flag ),
9886 &num_upper,
9887 &upper_flag,
9888 upper_28 );
9889
9890 Count_zeros( 1,
9891 mkexpr( num_upper ),
9892 mkexpr( upper_flag ),
9893 &num_low,
9894 &low_flag,
9895 low_32 );
9896
9897 return mkexpr( num_low );
9898}
9899
9900static IRExpr * Count_leading_zeros_128( IRExpr * lmd, IRExpr * top_12_l,
9901 IRExpr * mid_60_u, IRExpr * mid_60_l,
9902 IRExpr * low_60_u, IRExpr * low_60_l)
9903{
9904 IRTemp num_lmd = newTemp( Ity_I8 );
9905 IRTemp num_top = newTemp( Ity_I8 );
9906 IRTemp num_mid_u = newTemp( Ity_I8 );
9907 IRTemp num_mid_l = newTemp( Ity_I8 );
9908 IRTemp num_low_u = newTemp( Ity_I8 );
9909 IRTemp num_low_l = newTemp( Ity_I8 );
9910
9911 IRTemp lmd_flag = newTemp( Ity_I8 );
9912 IRTemp top_flag = newTemp( Ity_I8 );
9913 IRTemp mid_u_flag = newTemp( Ity_I8 );
9914 IRTemp mid_l_flag = newTemp( Ity_I8 );
9915 IRTemp low_u_flag = newTemp( Ity_I8 );
9916 IRTemp low_l_flag = newTemp( Ity_I8 );
9917
9918 /* Check the LMD, digit 16, to see if it is zero. */
9919 assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
9920
9921 assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
9922
9923 Count_zeros( 6,
9924 mkexpr( num_lmd ),
9925 mkexpr( lmd_flag ),
9926 &num_top,
9927 &top_flag,
9928 top_12_l );
9929
9930 Count_zeros( 1,
9931 mkexpr( num_top ),
9932 mkexpr( top_flag ),
9933 &num_mid_u,
9934 &mid_u_flag,
9935 binop( Iop_Or32,
9936 binop( Iop_Shl32, mid_60_u, mkU8( 2 ) ),
9937 binop( Iop_Shr32, mid_60_l, mkU8( 30 ) ) ) );
9938
9939 Count_zeros( 2,
9940 mkexpr( num_mid_u ),
9941 mkexpr( mid_u_flag ),
9942 &num_mid_l,
9943 &mid_l_flag,
9944 mid_60_l );
9945
9946 Count_zeros( 1,
9947 mkexpr( num_mid_l ),
9948 mkexpr( mid_l_flag ),
9949 &num_low_u,
9950 &low_u_flag,
9951 binop( Iop_Or32,
9952 binop( Iop_Shl32, low_60_u, mkU8( 2 ) ),
9953 binop( Iop_Shr32, low_60_l, mkU8( 30 ) ) ) );
9954
9955 Count_zeros( 2,
9956 mkexpr( num_low_u ),
9957 mkexpr( low_u_flag ),
9958 &num_low_l,
9959 &low_l_flag,
9960 low_60_l );
9961
9962 return mkexpr( num_low_l );
9963}
9964
9965static IRExpr * Check_unordered(IRExpr * val)
9966{
9967 IRTemp gfield0to5 = newTemp( Ity_I32 );
9968
9969 /* Extract G[0:4] */
9970 assign( gfield0to5,
9971 binop( Iop_And32,
9972 binop( Iop_Shr32, unop( Iop_64HIto32, val ), mkU8( 26 ) ),
9973 mkU32( 0x1F ) ) );
9974
9975 /* Check for unordered, return all 1'x if true */
9976 return binop( Iop_Or32, /* QNaN check */
9977 unop( Iop_1Sto32,
9978 binop( Iop_CmpEQ32,
9979 mkexpr( gfield0to5 ),
9980 mkU32( 0x1E ) ) ),
9981 unop( Iop_1Sto32, /* SNaN check */
9982 binop( Iop_CmpEQ32,
9983 mkexpr( gfield0to5 ),
9984 mkU32( 0x1F ) ) ) );
9985}
9986
sewardj5eff1c52012-04-29 20:19:17 +00009987#undef AND
sewardj5eff1c52012-04-29 20:19:17 +00009988#undef AND4
sewardj4c96e612012-06-02 23:47:02 +00009989#undef OR
sewardj5eff1c52012-04-29 20:19:17 +00009990#undef OR3
9991#undef OR4
sewardj4c96e612012-06-02 23:47:02 +00009992#undef NOT
9993#undef SHR
sewardj5eff1c52012-04-29 20:19:17 +00009994#undef SHL
sewardjcb06d5e2012-04-30 08:10:11 +00009995#undef BITS5
sewardj5eff1c52012-04-29 20:19:17 +00009996
9997/*------------------------------------------------------------*/
sewardjc6bbd472012-04-02 10:20:48 +00009998/*--- Decimal Floating Point (DFP) instruction translation ---*/
9999/*------------------------------------------------------------*/
sewardj5eff1c52012-04-29 20:19:17 +000010000
sewardjc6bbd472012-04-02 10:20:48 +000010001/* DFP Arithmetic instructions */
10002static Bool dis_dfp_arith(UInt theInstr)
10003{
10004 UInt opc2 = ifieldOPClo10( theInstr );
10005 UChar frS_addr = ifieldRegDS( theInstr );
10006 UChar frA_addr = ifieldRegA( theInstr );
10007 UChar frB_addr = ifieldRegB( theInstr );
10008 UChar flag_rC = ifieldBIT0( theInstr );
sewardje14bb9f2005-07-22 09:39:02 +000010009
sewardjc6bbd472012-04-02 10:20:48 +000010010 IRTemp frA = newTemp( Ity_D64 );
10011 IRTemp frB = newTemp( Ity_D64 );
10012 IRTemp frS = newTemp( Ity_D64 );
10013 IRExpr* round = get_IR_roundingmode_DFP();
10014
10015 /* By default, if flag_RC is set, we will clear cr1 after the
10016 * operation. In reality we should set cr1 to indicate the
10017 * exception status of the operation, but since we're not
10018 * simulating exceptions, the exception status will appear to be
10019 * zero. Hence cr1 should be cleared if this is a . form insn.
10020 */
10021 Bool clear_CR1 = True;
10022
10023 assign( frA, getDReg( frA_addr ) );
10024 assign( frB, getDReg( frB_addr ) );
10025
10026 switch (opc2) {
10027 case 0x2: // dadd
10028 DIP( "dadd%s fr%u,fr%u,fr%u\n",
10029 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10030 assign( frS, triop( Iop_AddD64, round, mkexpr( frA ), mkexpr( frB ) ) );
10031 break;
10032 case 0x202: // dsub
10033 DIP( "dsub%s fr%u,fr%u,fr%u\n",
10034 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10035 assign( frS, triop( Iop_SubD64, round, mkexpr( frA ), mkexpr( frB ) ) );
10036 break;
10037 case 0x22: // dmul
10038 DIP( "dmul%s fr%u,fr%u,fr%u\n",
10039 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10040 assign( frS, triop( Iop_MulD64, round, mkexpr( frA ), mkexpr( frB ) ) );
10041 break;
10042 case 0x222: // ddiv
10043 DIP( "ddiv%s fr%u,fr%u,fr%u\n",
10044 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10045 assign( frS, triop( Iop_DivD64, round, mkexpr( frA ), mkexpr( frB ) ) );
10046 break;
10047 }
10048
10049 putDReg( frS_addr, mkexpr( frS ) );
10050
10051 if (flag_rC && clear_CR1) {
10052 putCR321( 1, mkU8( 0 ) );
10053 putCR0( 1, mkU8( 0 ) );
10054 }
10055
10056 return True;
10057}
10058
10059/* Quad DFP Arithmetic instructions */
10060static Bool dis_dfp_arithq(UInt theInstr)
10061{
10062 UInt opc2 = ifieldOPClo10( theInstr );
10063 UChar frS_addr = ifieldRegDS( theInstr );
10064 UChar frA_addr = ifieldRegA( theInstr );
10065 UChar frB_addr = ifieldRegB( theInstr );
10066 UChar flag_rC = ifieldBIT0( theInstr );
10067
10068 IRTemp frA = newTemp( Ity_D128 );
10069 IRTemp frB = newTemp( Ity_D128 );
10070 IRTemp frS = newTemp( Ity_D128 );
10071 IRExpr* round = get_IR_roundingmode_DFP();
10072
10073 /* By default, if flag_RC is set, we will clear cr1 after the
10074 * operation. In reality we should set cr1 to indicate the
10075 * exception status of the operation, but since we're not
10076 * simulating exceptions, the exception status will appear to be
10077 * zero. Hence cr1 should be cleared if this is a . form insn.
10078 */
10079 Bool clear_CR1 = True;
10080
10081 assign( frA, getDReg_pair( frA_addr ) );
10082 assign( frB, getDReg_pair( frB_addr ) );
10083
10084 switch (opc2) {
10085 case 0x2: // daddq
10086 DIP( "daddq%s fr%u,fr%u,fr%u\n",
10087 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10088 assign( frS, triop( Iop_AddD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10089 break;
10090 case 0x202: // dsubq
10091 DIP( "dsubq%s fr%u,fr%u,fr%u\n",
10092 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10093 assign( frS, triop( Iop_SubD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10094 break;
10095 case 0x22: // dmulq
10096 DIP( "dmulq%s fr%u,fr%u,fr%u\n",
10097 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10098 assign( frS, triop( Iop_MulD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10099 break;
10100 case 0x222: // ddivq
10101 DIP( "ddivq%s fr%u,fr%u,fr%u\n",
10102 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10103 assign( frS, triop( Iop_DivD128, round, mkexpr( frA ), mkexpr( frB ) ) );
10104 break;
10105 }
10106
10107 putDReg_pair( frS_addr, mkexpr( frS ) );
10108
10109 if (flag_rC && clear_CR1) {
10110 putCR321( 1, mkU8( 0 ) );
10111 putCR0( 1, mkU8( 0 ) );
10112 }
10113
10114 return True;
10115}
sewardje14bb9f2005-07-22 09:39:02 +000010116
sewardj26217b02012-04-12 17:19:48 +000010117/* DFP 64-bit logical shift instructions */
10118static Bool dis_dfp_shift(UInt theInstr) {
10119 UInt opc2 = ifieldOPClo9( theInstr );
10120 UChar frS_addr = ifieldRegDS( theInstr );
10121 UChar frA_addr = ifieldRegA( theInstr );
10122 UChar shift_val = IFIELD(theInstr, 10, 6);
10123 UChar flag_rC = ifieldBIT0( theInstr );
10124
10125 IRTemp frA = newTemp( Ity_D64 );
10126 IRTemp frS = newTemp( Ity_D64 );
10127 Bool clear_CR1 = True;
10128
10129 assign( frA, getDReg( frA_addr ) );
10130
10131 switch (opc2) {
10132 case 0x42: // dscli
10133 DIP( "dscli%s fr%u,fr%u,%u\n",
10134 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10135 assign( frS, binop( Iop_ShlD64, mkexpr( frA ), mkU8( shift_val ) ) );
10136 break;
10137 case 0x62: // dscri
10138 DIP( "dscri%s fr%u,fr%u,%u\n",
10139 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10140 assign( frS, binop( Iop_ShrD64, mkexpr( frA ), mkU8( shift_val ) ) );
10141 break;
10142 }
10143
10144 putDReg( frS_addr, mkexpr( frS ) );
10145
10146 if (flag_rC && clear_CR1) {
10147 putCR321( 1, mkU8( 0 ) );
10148 putCR0( 1, mkU8( 0 ) );
10149 }
10150
10151 return True;
10152}
10153
10154/* Quad DFP logical shift instructions */
10155static Bool dis_dfp_shiftq(UInt theInstr) {
10156 UInt opc2 = ifieldOPClo9( theInstr );
10157 UChar frS_addr = ifieldRegDS( theInstr );
10158 UChar frA_addr = ifieldRegA( theInstr );
10159 UChar shift_val = IFIELD(theInstr, 10, 6);
10160 UChar flag_rC = ifieldBIT0( theInstr );
10161
10162 IRTemp frA = newTemp( Ity_D128 );
10163 IRTemp frS = newTemp( Ity_D128 );
10164 Bool clear_CR1 = True;
10165
10166 assign( frA, getDReg_pair( frA_addr ) );
10167
10168 switch (opc2) {
10169 case 0x42: // dscliq
10170 DIP( "dscliq%s fr%u,fr%u,%u\n",
10171 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10172 assign( frS, binop( Iop_ShlD128, mkexpr( frA ), mkU8( shift_val ) ) );
10173 break;
10174 case 0x62: // dscriq
10175 DIP( "dscriq%s fr%u,fr%u,%u\n",
10176 flag_rC ? ".":"", frS_addr, frA_addr, shift_val );
10177 assign( frS, binop( Iop_ShrD128, mkexpr( frA ), mkU8( shift_val ) ) );
10178 break;
10179 }
10180
10181 putDReg_pair( frS_addr, mkexpr( frS ) );
10182
10183 if (flag_rC && clear_CR1) {
10184 putCR321( 1, mkU8( 0 ) );
10185 putCR0( 1, mkU8( 0 ) );
10186 }
10187
10188 return True;
10189}
10190
10191/* DFP 64-bit format conversion instructions */
10192static Bool dis_dfp_fmt_conv(UInt theInstr) {
10193 UInt opc2 = ifieldOPClo10( theInstr );
10194 UChar frS_addr = ifieldRegDS( theInstr );
10195 UChar frB_addr = ifieldRegB( theInstr );
10196 IRExpr* round = get_IR_roundingmode_DFP();
10197 UChar flag_rC = ifieldBIT0( theInstr );
10198 IRTemp frB;
10199 IRTemp frS;
10200 Bool clear_CR1 = True;
10201
10202 switch (opc2) {
10203 case 0x102: //dctdp
10204 DIP( "dctdp%s fr%u,fr%u\n",
10205 flag_rC ? ".":"", frS_addr, frB_addr );
10206
carllf704eb22013-01-21 18:12:31 +000010207 frB = newTemp( Ity_D32 );
sewardj26217b02012-04-12 17:19:48 +000010208 frS = newTemp( Ity_D64 );
carllf704eb22013-01-21 18:12:31 +000010209 assign( frB, getDReg32( frB_addr ) );
sewardj26217b02012-04-12 17:19:48 +000010210 assign( frS, unop( Iop_D32toD64, mkexpr( frB ) ) );
10211 putDReg( frS_addr, mkexpr( frS ) );
10212 break;
10213 case 0x302: // drsp
10214 DIP( "drsp%s fr%u,fr%u\n",
10215 flag_rC ? ".":"", frS_addr, frB_addr );
10216 frB = newTemp( Ity_D64 );
carllf704eb22013-01-21 18:12:31 +000010217 frS = newTemp( Ity_D32 );
sewardj26217b02012-04-12 17:19:48 +000010218 assign( frB, getDReg( frB_addr ) );
10219 assign( frS, binop( Iop_D64toD32, round, mkexpr( frB ) ) );
carllf704eb22013-01-21 18:12:31 +000010220 putDReg32( frS_addr, mkexpr( frS ) );
sewardj26217b02012-04-12 17:19:48 +000010221 break;
10222 case 0x122: // dctfix
carllcea07cc2013-01-22 20:25:31 +000010223 {
10224 IRTemp tmp = newTemp( Ity_I64 );
10225
10226 DIP( "dctfix%s fr%u,fr%u\n",
10227 flag_rC ? ".":"", frS_addr, frB_addr );
10228 frB = newTemp( Ity_D64 );
10229 frS = newTemp( Ity_D64 );
10230 assign( frB, getDReg( frB_addr ) );
10231 assign( tmp, binop( Iop_D64toI64S, round, mkexpr( frB ) ) );
10232 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
10233 putDReg( frS_addr, mkexpr( frS ) );
10234 }
sewardj26217b02012-04-12 17:19:48 +000010235 break;
10236 case 0x322: // dcffix
10237 DIP( "dcffix%s fr%u,fr%u\n",
10238 flag_rC ? ".":"", frS_addr, frB_addr );
10239 frB = newTemp( Ity_D64 );
10240 frS = newTemp( Ity_D64 );
10241 assign( frB, getDReg( frB_addr ) );
carllcea07cc2013-01-22 20:25:31 +000010242 assign( frS, binop( Iop_I64StoD64,
10243 round,
10244 unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) ) );
sewardj26217b02012-04-12 17:19:48 +000010245 putDReg( frS_addr, mkexpr( frS ) );
10246 break;
10247 }
10248
10249 if (flag_rC && clear_CR1) {
10250 putCR321( 1, mkU8( 0 ) );
10251 putCR0( 1, mkU8( 0 ) );
10252 }
10253
10254 return True;
10255}
10256
10257/* Quad DFP format conversion instructions */
10258static Bool dis_dfp_fmt_convq(UInt theInstr) {
10259 UInt opc2 = ifieldOPClo10( theInstr );
10260 UChar frS_addr = ifieldRegDS( theInstr );
10261 UChar frB_addr = ifieldRegB( theInstr );
10262 IRExpr* round = get_IR_roundingmode_DFP();
10263 IRTemp frB64 = newTemp( Ity_D64 );
10264 IRTemp frB128 = newTemp( Ity_D128 );
10265 IRTemp frS64 = newTemp( Ity_D64 );
10266 IRTemp frS128 = newTemp( Ity_D128 );
10267 UChar flag_rC = ifieldBIT0( theInstr );
10268 Bool clear_CR1 = True;
10269
10270 switch (opc2) {
10271 case 0x102: // dctqpq
10272 DIP( "dctqpq%s fr%u,fr%u\n",
10273 flag_rC ? ".":"", frS_addr, frB_addr );
10274 assign( frB64, getDReg( frB_addr ) );
10275 assign( frS128, unop( Iop_D64toD128, mkexpr( frB64 ) ) );
10276 putDReg_pair( frS_addr, mkexpr( frS128 ) );
10277 break;
10278 case 0x122: // dctfixq
carllcea07cc2013-01-22 20:25:31 +000010279 {
10280 IRTemp tmp = newTemp( Ity_I64 );
10281
10282 DIP( "dctfixq%s fr%u,fr%u\n",
10283 flag_rC ? ".":"", frS_addr, frB_addr );
10284 assign( frB128, getDReg_pair( frB_addr ) );
10285 assign( tmp, binop( Iop_D128toI64S, round, mkexpr( frB128 ) ) );
10286 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
10287 putDReg( frS_addr, mkexpr( frS64 ) );
10288 }
sewardj26217b02012-04-12 17:19:48 +000010289 break;
10290 case 0x302: //drdpq
10291 DIP( "drdpq%s fr%u,fr%u\n",
10292 flag_rC ? ".":"", frS_addr, frB_addr );
10293 assign( frB128, getDReg_pair( frB_addr ) );
10294 assign( frS64, binop( Iop_D128toD64, round, mkexpr( frB128 ) ) );
10295 putDReg( frS_addr, mkexpr( frS64 ) );
10296 break;
10297 case 0x322: // dcffixq
carllcea07cc2013-01-22 20:25:31 +000010298 {
sewardj26217b02012-04-12 17:19:48 +000010299 /* Have to introduce an IOP for this instruction so it will work
10300 * on POWER 6 because emulating the instruction requires a POWER 7
10301 * DFP instruction in the emulation code.
10302 */
10303 DIP( "dcffixq%s fr%u,fr%u\n",
10304 flag_rC ? ".":"", frS_addr, frB_addr );
10305 assign( frB64, getDReg( frB_addr ) );
carllcea07cc2013-01-22 20:25:31 +000010306 assign( frS128, unop( Iop_I64StoD128,
10307 unop( Iop_ReinterpD64asI64,
10308 mkexpr( frB64 ) ) ) );
sewardj26217b02012-04-12 17:19:48 +000010309 putDReg_pair( frS_addr, mkexpr( frS128 ) );
10310 break;
carllcea07cc2013-01-22 20:25:31 +000010311 }
sewardj26217b02012-04-12 17:19:48 +000010312 }
10313
10314 if (flag_rC && clear_CR1) {
10315 putCR321( 1, mkU8( 0 ) );
10316 putCR0( 1, mkU8( 0 ) );
10317 }
10318
10319 return True;
10320}
10321
sewardjcdc376d2012-04-23 11:21:12 +000010322static Bool dis_dfp_round( UInt theInstr ) {
10323 UChar frS_addr = ifieldRegDS(theInstr);
10324 UChar R = IFIELD(theInstr, 16, 1);
10325 UChar RMC = IFIELD(theInstr, 9, 2);
10326 UChar frB_addr = ifieldRegB( theInstr );
10327 UChar flag_rC = ifieldBIT0( theInstr );
10328 IRTemp frB = newTemp( Ity_D64 );
10329 IRTemp frS = newTemp( Ity_D64 );
10330 UInt opc2 = ifieldOPClo8( theInstr );
10331 Bool clear_CR1 = True;
10332
10333 switch (opc2) {
10334 /* drintn, is the same as drintx. The only difference is this
10335 * instruction does not generate an exception for an inexact operation.
10336 * Currently not supporting inexact exceptions.
10337 */
10338 case 0x63: // drintx
10339 case 0xE3: // drintn
10340 DIP( "drintx/drintn%s fr%u,fr%u\n",
10341 flag_rC ? ".":"", frS_addr, frB_addr );
10342
carllcea07cc2013-01-22 20:25:31 +000010343 /* NOTE, this instruction takes a DFP value and rounds to the
10344 * neares floating point integer value, i.e. fractional part
10345 * is zero. The result is a floating point number.
10346 */
sewardjcdc376d2012-04-23 11:21:12 +000010347 /* pass the value of R and RMC in the same field */
10348 assign( frB, getDReg( frB_addr ) );
10349 assign( frS, binop( Iop_RoundD64toInt,
10350 mkU32( ( R << 3 ) | RMC ),
10351 mkexpr( frB ) ) );
10352 putDReg( frS_addr, mkexpr( frS ) );
10353 break;
10354 default:
10355 vex_printf("dis_dfp_round(ppc)(opc2)\n");
10356 return False;
10357 }
10358
10359 if (flag_rC && clear_CR1) {
10360 putCR321( 1, mkU8( 0 ) );
10361 putCR0( 1, mkU8( 0 ) );
10362 }
10363
10364 return True;
10365}
10366
10367static Bool dis_dfp_roundq(UInt theInstr) {
10368 UChar frS_addr = ifieldRegDS( theInstr );
10369 UChar frB_addr = ifieldRegB( theInstr );
10370 UChar R = IFIELD(theInstr, 16, 1);
10371 UChar RMC = IFIELD(theInstr, 9, 2);
10372 UChar flag_rC = ifieldBIT0( theInstr );
10373 IRTemp frB = newTemp( Ity_D128 );
10374 IRTemp frS = newTemp( Ity_D128 );
10375 Bool clear_CR1 = True;
10376 UInt opc2 = ifieldOPClo8( theInstr );
10377
10378 switch (opc2) {
10379 /* drintnq, is the same as drintxq. The only difference is this
10380 * instruction does not generate an exception for an inexact operation.
10381 * Currently not supporting inexact exceptions.
10382 */
10383 case 0x63: // drintxq
10384 case 0xE3: // drintnq
10385 DIP( "drintxq/drintnq%s fr%u,fr%u\n",
10386 flag_rC ? ".":"", frS_addr, frB_addr );
10387
10388 /* pass the value of R and RMC in the same field */
10389 assign( frB, getDReg_pair( frB_addr ) );
10390 assign( frS, binop( Iop_RoundD128toInt,
10391 mkU32( ( R << 3 ) | RMC ),
10392 mkexpr( frB ) ) );
10393 putDReg_pair( frS_addr, mkexpr( frS ) );
10394 break;
10395 default:
10396 vex_printf("dis_dfp_roundq(ppc)(opc2)\n");
10397 return False;
10398 }
10399
10400 if (flag_rC && clear_CR1) {
10401 putCR321( 1, mkU8( 0 ) );
10402 putCR0( 1, mkU8( 0 ) );
10403 }
10404
10405 return True;
10406}
10407
10408static Bool dis_dfp_quantize_sig_rrnd(UInt theInstr) {
10409 UInt opc2 = ifieldOPClo8( theInstr );
10410 UChar frS_addr = ifieldRegDS( theInstr );
10411 UChar frA_addr = ifieldRegA( theInstr );
10412 UChar frB_addr = ifieldRegB( theInstr );
10413 UChar flag_rC = ifieldBIT0( theInstr );
10414 UInt TE_value = IFIELD(theInstr, 16, 4);
10415 UInt TE_sign = IFIELD(theInstr, 20, 1);
10416 UInt RMC = IFIELD(theInstr, 9, 2);
10417 IRTemp frA = newTemp( Ity_D64 );
10418 IRTemp frB = newTemp( Ity_D64 );
10419 IRTemp frS = newTemp( Ity_D64 );
10420 Bool clear_CR1 = True;
10421
10422 assign( frB, getDReg( frB_addr ) );
10423
10424 switch (opc2) {
10425 case 0x43: // dquai
10426 DIP( "dquai%s fr%u,fr%u,fr%u\n",
10427 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010428 IRTemp TE_I64 = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010429
10430 /* Generate a reference DFP value frA with the desired exponent
10431 * given by TE using significand from frB. Need to add the bias
10432 * 398 to TE. TE is stored as a 2's complement number.
10433 */
10434 if (TE_sign == 1) {
10435 /* Take 2's complement of the 5-bit value and subtract from bias.
10436 * Bias is adjusted for the +1 required when taking 2's complement.
10437 */
carllcea07cc2013-01-22 20:25:31 +000010438 assign( TE_I64,
10439 unop( Iop_32Uto64,
10440 binop( Iop_Sub32, mkU32( 397 ),
10441 binop( Iop_And32, mkU32( 0xF ),
10442 unop( Iop_Not32, mkU32( TE_value ) )
10443 ) ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010444
10445 } else {
carllcea07cc2013-01-22 20:25:31 +000010446 assign( TE_I64,
10447 unop( Iop_32Uto64,
10448 binop( Iop_Add32, mkU32( 398 ), mkU32( TE_value ) )
10449 ) );
sewardjcdc376d2012-04-23 11:21:12 +000010450 }
10451
carllcea07cc2013-01-22 20:25:31 +000010452 assign( frA, binop( Iop_InsertExpD64, mkexpr( TE_I64 ),
sewardjcdc376d2012-04-23 11:21:12 +000010453 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) );
10454
10455 assign( frS, triop( Iop_QuantizeD64,
10456 mkU32( RMC ),
10457 mkexpr( frA ),
10458 mkexpr( frB ) ) );
10459 break;
10460
10461 case 0x3: // dqua
10462 DIP( "dqua%s fr%u,fr%u,fr%u\n",
10463 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10464 assign( frA, getDReg( frA_addr ) );
10465 assign( frS, triop( Iop_QuantizeD64,
10466 mkU32( RMC ),
10467 mkexpr( frA ),
10468 mkexpr( frB ) ) );
10469 break;
10470 case 0x23: // drrnd
carllcea07cc2013-01-22 20:25:31 +000010471 {
10472 IRTemp tmp = newTemp( Ity_I8 );
10473
10474 DIP( "drrnd%s fr%u,fr%u,fr%u\n",
10475 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10476 assign( frA, getDReg( frA_addr ) );
10477 /* Iop_64to8 not supported in 32 bit mode, do it in two steps. */
10478 assign( tmp, unop( Iop_32to8,
10479 unop( Iop_64to32,
10480 unop( Iop_ReinterpD64asI64,
10481 mkexpr( frA ) ) ) ) );
10482 assign( frS, triop( Iop_SignificanceRoundD64,
10483 mkU32( RMC ),
10484 mkexpr( tmp ),
10485 mkexpr( frB ) ) );
10486 }
sewardjcdc376d2012-04-23 11:21:12 +000010487 break;
10488 default:
10489 vex_printf("dis_dfp_quantize_sig_rrnd(ppc)(opc2)\n");
10490 return False;
10491 }
10492 putDReg( frS_addr, mkexpr( frS ) );
10493
10494 if (flag_rC && clear_CR1) {
10495 putCR321( 1, mkU8( 0 ) );
10496 putCR0( 1, mkU8( 0 ) );
10497 }
10498
10499 return True;
10500}
10501
10502static Bool dis_dfp_quantize_sig_rrndq(UInt theInstr) {
10503 UInt opc2 = ifieldOPClo8( theInstr );
10504 UChar frS_addr = ifieldRegDS( theInstr );
10505 UChar frA_addr = ifieldRegA( theInstr );
10506 UChar frB_addr = ifieldRegB( theInstr );
10507 UChar flag_rC = ifieldBIT0( theInstr );
10508 UInt TE_value = IFIELD(theInstr, 16, 4);
10509 UInt TE_sign = IFIELD(theInstr, 20, 1);
10510 UInt RMC = IFIELD(theInstr, 9, 2);
10511 IRTemp frA = newTemp( Ity_D128 );
10512 IRTemp frB = newTemp( Ity_D128 );
10513 IRTemp frS = newTemp( Ity_D128 );
10514 Bool clear_CR1 = True;
10515
10516 assign( frB, getDReg_pair( frB_addr ) );
10517
10518 switch (opc2) {
10519 case 0x43: // dquaiq
10520 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
10521 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010522 IRTemp TE_I64 = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010523
10524 /* Generate a reference DFP value frA with the desired exponent
10525 * given by TE using significand of 1. Need to add the bias
10526 * 6176 to TE.
10527 */
10528 if (TE_sign == 1) {
10529 /* Take 2's complement of the 5-bit value and subtract from bias.
10530 * Bias adjusted for the +1 required when taking 2's complement.
10531 */
carllcea07cc2013-01-22 20:25:31 +000010532 assign( TE_I64,
10533 unop( Iop_32Uto64,
10534 binop( Iop_Sub32, mkU32( 6175 ),
10535 binop( Iop_And32, mkU32( 0xF ),
10536 unop( Iop_Not32, mkU32( TE_value ) )
10537 ) ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010538
10539 } else {
carllcea07cc2013-01-22 20:25:31 +000010540 assign( TE_I64,
10541 unop( Iop_32Uto64,
10542 binop( Iop_Add32,
10543 mkU32( 6176 ),
10544 mkU32( TE_value ) ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010545 }
10546
10547 assign( frA,
carllcea07cc2013-01-22 20:25:31 +000010548 binop( Iop_InsertExpD128, mkexpr( TE_I64 ),
10549 unop( Iop_D64toD128,
sewardjcdc376d2012-04-23 11:21:12 +000010550 unop( Iop_ReinterpI64asD64, mkU64( 1 ) ) ) ) );
10551 assign( frS, triop( Iop_QuantizeD128,
10552 mkU32( RMC ),
10553 mkexpr( frA ),
10554 mkexpr( frB ) ) );
10555 break;
10556 case 0x3: // dquaq
10557 DIP( "dquaiq%s fr%u,fr%u,fr%u\n",
10558 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10559 assign( frA, getDReg_pair( frA_addr ) );
10560 assign( frS, triop( Iop_QuantizeD128,
10561 mkU32( RMC ),
10562 mkexpr( frA ),
10563 mkexpr( frB ) ) );
10564 break;
10565 case 0x23: // drrndq
carllcea07cc2013-01-22 20:25:31 +000010566 {
10567 IRTemp tmp = newTemp( Ity_I8 );
10568
10569 DIP( "drrndq%s fr%u,fr%u,fr%u\n",
10570 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10571 assign( frA, getDReg_pair( frA_addr ) );
10572 assign( tmp, unop( Iop_32to8,
10573 unop( Iop_64to32,
10574 unop( Iop_ReinterpD64asI64,
10575 unop( Iop_D128HItoD64,
10576 mkexpr( frA ) ) ) ) ) );
10577 assign( frS, triop( Iop_SignificanceRoundD128,
10578 mkU32( RMC ),
10579 mkexpr( tmp ),
10580 mkexpr( frB ) ) );
10581 }
sewardjcdc376d2012-04-23 11:21:12 +000010582 break;
10583 default:
10584 vex_printf("dis_dfp_quantize_sig_rrndq(ppc)(opc2)\n");
10585 return False;
10586 }
10587 putDReg_pair( frS_addr, mkexpr( frS ) );
10588
10589 if (flag_rC && clear_CR1) {
10590 putCR321( 1, mkU8( 0 ) );
10591 putCR0( 1, mkU8( 0 ) );
10592 }
10593
10594 return True;
10595}
10596
10597static Bool dis_dfp_extract_insert(UInt theInstr) {
10598 UInt opc2 = ifieldOPClo10( theInstr );
10599 UChar frS_addr = ifieldRegDS( theInstr );
10600 UChar frA_addr = ifieldRegA( theInstr );
10601 UChar frB_addr = ifieldRegB( theInstr );
10602 UChar flag_rC = ifieldBIT0( theInstr );
10603 Bool clear_CR1 = True;
10604
10605 IRTemp frA = newTemp( Ity_D64 );
10606 IRTemp frB = newTemp( Ity_D64 );
10607 IRTemp frS = newTemp( Ity_D64 );
carllcea07cc2013-01-22 20:25:31 +000010608 IRTemp tmp = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010609
10610 assign( frA, getDReg( frA_addr ) );
10611 assign( frB, getDReg( frB_addr ) );
10612
10613 switch (opc2) {
10614 case 0x162: // dxex
10615 DIP( "dxex%s fr%u,fr%u,fr%u\n",
10616 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010617 assign( tmp, unop( Iop_ExtractExpD64, mkexpr( frB ) ) );
10618 assign( frS, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010619 break;
10620 case 0x362: // diex
10621 DIP( "diex%s fr%u,fr%u,fr%u\n",
10622 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
carllcea07cc2013-01-22 20:25:31 +000010623 assign( frS, binop( Iop_InsertExpD64,
10624 unop( Iop_ReinterpD64asI64,
10625 mkexpr( frA ) ),
10626 mkexpr( frB ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010627 break;
10628 default:
10629 vex_printf("dis_dfp_extract_insert(ppc)(opc2)\n");
10630 return False;
10631 }
10632
10633 putDReg( frS_addr, mkexpr( frS ) );
10634
10635 if (flag_rC && clear_CR1) {
10636 putCR321( 1, mkU8( 0 ) );
10637 putCR0( 1, mkU8( 0 ) );
10638 }
10639
10640 return True;
10641}
10642
10643static Bool dis_dfp_extract_insertq(UInt theInstr) {
10644 UInt opc2 = ifieldOPClo10( theInstr );
10645 UChar frS_addr = ifieldRegDS( theInstr );
10646 UChar frA_addr = ifieldRegA( theInstr );
10647 UChar frB_addr = ifieldRegB( theInstr );
10648 UChar flag_rC = ifieldBIT0( theInstr );
10649
10650 IRTemp frA = newTemp( Ity_D64 );
10651 IRTemp frB = newTemp( Ity_D128 );
10652 IRTemp frS64 = newTemp( Ity_D64 );
10653 IRTemp frS = newTemp( Ity_D128 );
carllcea07cc2013-01-22 20:25:31 +000010654 IRTemp tmp = newTemp( Ity_I64 );
sewardjcdc376d2012-04-23 11:21:12 +000010655 Bool clear_CR1 = True;
10656
10657 assign( frB, getDReg_pair( frB_addr ) );
10658
10659 switch (opc2) {
10660 case 0x162: // dxexq
10661 DIP( "dxexq%s fr%u,fr%u\n",
10662 flag_rC ? ".":"", frS_addr, frB_addr );
10663 /* Instruction actually returns a 64-bit result. So as to be
10664 * consistent and not have to add a new struct, the emulation returns
10665 * the 64-bit result in the upper and lower register.
10666 */
carllcea07cc2013-01-22 20:25:31 +000010667 assign( tmp, unop( Iop_ExtractExpD128, mkexpr( frB ) ) );
10668 assign( frS64, unop( Iop_ReinterpI64asD64, mkexpr( tmp ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010669 putDReg( frS_addr, mkexpr( frS64 ) );
10670 break;
10671 case 0x362: // diexq
10672 DIP( "diexq%s fr%u,fr%u,fr%u\n",
10673 flag_rC ? ".":"", frS_addr, frA_addr, frB_addr );
10674 assign( frA, getDReg( frA_addr ) );
carllcea07cc2013-01-22 20:25:31 +000010675 assign( frS, binop( Iop_InsertExpD128,
10676 unop( Iop_ReinterpD64asI64, mkexpr( frA ) ),
10677 mkexpr( frB ) ) );
sewardjcdc376d2012-04-23 11:21:12 +000010678 putDReg_pair( frS_addr, mkexpr( frS ) );
10679 break;
10680 default:
10681 vex_printf("dis_dfp_extract_insertq(ppc)(opc2)\n");
10682 return False;
10683 }
10684
10685 if (flag_rC && clear_CR1) {
10686 putCR321( 1, mkU8( 0 ) );
10687 putCR0( 1, mkU8( 0 ) );
10688 }
10689
10690 return True;
10691}
10692
10693/* DFP 64-bit comparison instructions */
10694static Bool dis_dfp_compare(UInt theInstr) {
10695 /* X-Form */
10696 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
10697 UChar frA_addr = ifieldRegA( theInstr );
10698 UChar frB_addr = ifieldRegB( theInstr );
10699 UInt opc1 = ifieldOPC( theInstr );
10700 IRTemp frA;
10701 IRTemp frB;
10702
10703 IRTemp ccIR = newTemp( Ity_I32 );
10704 IRTemp ccPPC32 = newTemp( Ity_I32 );
10705
10706
10707 /* Note: Differences between dcmpu and dcmpo are only in exception
10708 flag settings, which aren't supported anyway. */
10709 switch (opc1) {
10710 case 0x3B: /* dcmpo and dcmpu, DFP 64-bit */
10711 DIP( "dcmpo %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
10712 frA = newTemp( Ity_D64 );
10713 frB = newTemp( Ity_D64 );
10714
10715 assign( frA, getDReg( frA_addr ) );
10716 assign( frB, getDReg( frB_addr ) );
10717
10718 assign( ccIR, binop( Iop_CmpD64, mkexpr( frA ), mkexpr( frB ) ) );
10719 break;
10720 case 0x3F: /* dcmpoq and dcmpuq,DFP 128-bit */
10721 DIP( "dcmpoq %u,fr%u,fr%u\n", crfD, frA_addr, frB_addr );
10722 frA = newTemp( Ity_D128 );
10723 frB = newTemp( Ity_D128 );
10724
10725 assign( frA, getDReg_pair( frA_addr ) );
10726 assign( frB, getDReg_pair( frB_addr ) );
10727 assign( ccIR, binop( Iop_CmpD128, mkexpr( frA ), mkexpr( frB ) ) );
10728 break;
10729 default:
10730 vex_printf("dis_dfp_compare(ppc)(opc2)\n");
10731 return False;
10732 }
10733
10734 /* Map compare result from IR to PPC32 */
10735 /*
10736 FP cmp result | PPC | IR
10737 --------------------------
10738 UN | 0x1 | 0x45
10739 EQ | 0x2 | 0x40
10740 GT | 0x4 | 0x00
10741 LT | 0x8 | 0x01
10742 */
10743
10744 assign( ccPPC32,
10745 binop( Iop_Shl32,
10746 mkU32( 1 ),
10747 unop( Iop_32to8,
10748 binop( Iop_Or32,
10749 binop( Iop_And32,
10750 unop( Iop_Not32,
10751 binop( Iop_Shr32,
10752 mkexpr( ccIR ),
10753 mkU8( 5 ) ) ),
10754 mkU32( 2 ) ),
10755 binop( Iop_And32,
10756 binop( Iop_Xor32,
10757 mkexpr( ccIR ),
10758 binop( Iop_Shr32,
10759 mkexpr( ccIR ),
10760 mkU8( 6 ) ) ),
10761 mkU32( 1 ) ) ) ) ) );
10762
10763 putGST_field( PPC_GST_CR, mkexpr( ccPPC32 ), crfD );
10764 return True;
10765}
10766
sewardj5eff1c52012-04-29 20:19:17 +000010767/* Test class/group/exponent/significance instructions. */
10768static Bool dis_dfp_exponent_test ( UInt theInstr )
10769{
10770 UChar frA_addr = ifieldRegA( theInstr );
10771 UChar frB_addr = ifieldRegB( theInstr );
10772 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
10773 IRTemp frA = newTemp( Ity_D64 );
10774 IRTemp frB = newTemp( Ity_D64 );
10775 IRTemp frA128 = newTemp( Ity_D128 );
10776 IRTemp frB128 = newTemp( Ity_D128 );
10777 UInt opc1 = ifieldOPC( theInstr );
10778 IRTemp gfield_A = newTemp( Ity_I32 );
10779 IRTemp gfield_B = newTemp( Ity_I32 );
10780 IRTemp gfield_mask = newTemp( Ity_I32 );
10781 IRTemp exponent_A = newTemp( Ity_I32 );
10782 IRTemp exponent_B = newTemp( Ity_I32 );
10783 IRTemp A_NaN_true = newTemp( Ity_I32 );
10784 IRTemp B_NaN_true = newTemp( Ity_I32 );
10785 IRTemp A_inf_true = newTemp( Ity_I32 );
10786 IRTemp B_inf_true = newTemp( Ity_I32 );
10787 IRTemp A_equals_B = newTemp( Ity_I32 );
10788 IRTemp finite_number = newTemp( Ity_I32 );
10789 IRTemp cc0 = newTemp( Ity_I32 );
10790 IRTemp cc1 = newTemp( Ity_I32 );
10791 IRTemp cc2 = newTemp( Ity_I32 );
10792 IRTemp cc3 = newTemp( Ity_I32 );
10793
10794 /* The dtstex and dtstexg instructions only differ in the size of the
10795 * exponent field. The following switch statement takes care of the size
10796 * specific setup. Once the value of the exponents, the G-field shift
10797 * and mask is setup the remaining code is identical.
10798 */
10799 switch (opc1) {
10800 case 0x3b: // dtstex Extended instruction setup
10801 DIP("dtstex %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
10802 assign( frA, getDReg( frA_addr ) );
10803 assign( frB, getDReg( frB_addr ) );
10804 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
carllcea07cc2013-01-22 20:25:31 +000010805 assign(exponent_A, unop( Iop_64to32,
10806 unop( Iop_ExtractExpD64,
10807 mkexpr( frA ) ) ) );
10808 assign(exponent_B, unop( Iop_64to32,
10809 unop( Iop_ExtractExpD64,
10810 mkexpr( frB ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000010811 break;
10812
10813 case 0x3F: // dtstexq Quad instruction setup
10814 DIP("dtstexq %u,r%u,r%d\n", crfD, frA_addr, frB_addr);
10815 assign( frA128, getDReg_pair( frA_addr ) );
10816 assign( frB128, getDReg_pair( frB_addr ) );
10817 assign( frA, unop( Iop_D128HItoD64, mkexpr( frA128 ) ) );
10818 assign( frB, unop( Iop_D128HItoD64, mkexpr( frB128 ) ) );
10819 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
carllcea07cc2013-01-22 20:25:31 +000010820 assign( exponent_A, unop( Iop_64to32,
10821 unop( Iop_ExtractExpD128,
10822 mkexpr( frA128 ) ) ) );
10823 assign( exponent_B, unop( Iop_64to32,
10824 unop( Iop_ExtractExpD128,
10825 mkexpr( frB128 ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000010826 break;
10827 default:
10828 vex_printf("dis_dfp_exponent_test(ppc)(opc2)\n");
10829 return False;
10830 }
10831
10832 /* Extract the Gfield */
10833 assign( gfield_A, binop( Iop_And32,
10834 mkexpr( gfield_mask ),
10835 unop( Iop_64HIto32,
10836 unop( Iop_ReinterpD64asI64,
10837 mkexpr(frA) ) ) ) );
10838
10839 assign( gfield_B, binop( Iop_And32,
10840 mkexpr( gfield_mask ),
10841 unop( Iop_64HIto32,
10842 unop( Iop_ReinterpD64asI64,
10843 mkexpr(frB) ) ) ) );
10844
10845 /* check for NAN */
10846 assign( A_NaN_true, binop(Iop_Or32,
10847 unop( Iop_1Sto32,
10848 binop( Iop_CmpEQ32,
10849 mkexpr( gfield_A ),
10850 mkU32( 0x7C000000 ) ) ),
10851 unop( Iop_1Sto32,
10852 binop( Iop_CmpEQ32,
10853 mkexpr( gfield_A ),
10854 mkU32( 0x7E000000 ) )
10855 ) ) );
10856 assign( B_NaN_true, binop(Iop_Or32,
10857 unop( Iop_1Sto32,
10858 binop( Iop_CmpEQ32,
10859 mkexpr( gfield_B ),
10860 mkU32( 0x7C000000 ) ) ),
10861 unop( Iop_1Sto32,
10862 binop( Iop_CmpEQ32,
10863 mkexpr( gfield_B ),
10864 mkU32( 0x7E000000 ) )
10865 ) ) );
10866
10867 /* check for infinity */
10868 assign( A_inf_true,
10869 unop( Iop_1Sto32,
10870 binop( Iop_CmpEQ32,
10871 mkexpr( gfield_A ),
10872 mkU32( 0x78000000 ) ) ) );
10873
10874 assign( B_inf_true,
10875 unop( Iop_1Sto32,
10876 binop( Iop_CmpEQ32,
10877 mkexpr( gfield_B ),
10878 mkU32( 0x78000000 ) ) ) );
10879
10880 assign( finite_number,
10881 unop( Iop_Not32,
10882 binop( Iop_Or32,
10883 binop( Iop_Or32,
10884 mkexpr( A_NaN_true ),
10885 mkexpr( B_NaN_true ) ),
10886 binop( Iop_Or32,
10887 mkexpr( A_inf_true ),
10888 mkexpr( B_inf_true ) ) ) ) );
10889
10890 /* Calculate the condition code bits
10891 * If QNaN,SNaN, +infinity, -infinity then cc0, cc1 and cc2 are zero
10892 * regardless of the value of the comparisons and cc3 is 1. Otherwise,
10893 * cc0, cc1 and cc0 reflect the results of the comparisons.
10894 */
10895 assign( A_equals_B,
10896 binop( Iop_Or32,
10897 unop( Iop_1Uto32,
10898 binop( Iop_CmpEQ32,
10899 mkexpr( exponent_A ),
10900 mkexpr( exponent_B ) ) ),
10901 binop( Iop_Or32,
10902 binop( Iop_And32,
10903 mkexpr( A_inf_true ),
10904 mkexpr( B_inf_true ) ),
10905 binop( Iop_And32,
10906 mkexpr( A_NaN_true ),
10907 mkexpr( B_NaN_true ) ) ) ) );
10908
10909 assign( cc0, binop( Iop_And32,
10910 mkexpr( finite_number ),
10911 binop( Iop_Shl32,
10912 unop( Iop_1Uto32,
10913 binop( Iop_CmpLT32U,
10914 mkexpr( exponent_A ),
10915 mkexpr( exponent_B ) ) ),
10916 mkU8( 3 ) ) ) );
10917
10918 assign( cc1, binop( Iop_And32,
10919 mkexpr( finite_number ),
10920 binop( Iop_Shl32,
10921 unop( Iop_1Uto32,
10922 binop( Iop_CmpLT32U,
10923 mkexpr( exponent_B ),
10924 mkexpr( exponent_A ) ) ),
10925 mkU8( 2 ) ) ) );
10926
10927 assign( cc2, binop( Iop_Shl32,
10928 binop( Iop_And32,
10929 mkexpr( A_equals_B ),
10930 mkU32( 1 ) ),
10931 mkU8( 1 ) ) );
10932
10933 assign( cc3, binop( Iop_And32,
10934 unop( Iop_Not32, mkexpr( A_equals_B ) ),
10935 binop( Iop_And32,
10936 mkU32( 0x1 ),
10937 binop( Iop_Or32,
10938 binop( Iop_Or32,
10939 mkexpr ( A_inf_true ),
10940 mkexpr ( B_inf_true ) ),
10941 binop( Iop_Or32,
10942 mkexpr ( A_NaN_true ),
10943 mkexpr ( B_NaN_true ) ) )
10944 ) ) );
10945
10946 /* store the condition code */
10947 putGST_field( PPC_GST_CR,
10948 binop( Iop_Or32,
10949 mkexpr( cc0 ),
10950 binop( Iop_Or32,
10951 mkexpr( cc1 ),
10952 binop( Iop_Or32,
10953 mkexpr( cc2 ),
10954 mkexpr( cc3 ) ) ) ),
10955 crfD );
10956 return True;
10957}
10958
10959/* Test class/group/exponent/significance instructions. */
10960static Bool dis_dfp_class_test ( UInt theInstr )
10961{
10962 UChar frA_addr = ifieldRegA( theInstr );
10963 IRTemp frA = newTemp( Ity_D64 );
10964 IRTemp abs_frA = newTemp( Ity_D64 );
10965 IRTemp frAI64_hi = newTemp( Ity_I64 );
10966 IRTemp frAI64_lo = newTemp( Ity_I64 );
10967 UInt opc1 = ifieldOPC( theInstr );
10968 UInt opc2 = ifieldOPClo9( theInstr );
10969 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
10970 UInt DCM = IFIELD( theInstr, 10, 6 );
10971 IRTemp DCM_calc = newTemp( Ity_I32 );
10972 UInt max_exp = 0;
10973 UInt min_exp = 0;
10974 IRTemp min_subnormalD64 = newTemp( Ity_D64 );
10975 IRTemp min_subnormalD128 = newTemp( Ity_D128 );
10976 IRTemp significand64 = newTemp( Ity_D64 );
10977 IRTemp significand128 = newTemp( Ity_D128 );
carllcea07cc2013-01-22 20:25:31 +000010978 IRTemp exp_min_normal = newTemp( Ity_I64 );
sewardj5eff1c52012-04-29 20:19:17 +000010979 IRTemp exponent = newTemp( Ity_I32 );
10980
10981 IRTemp infinity_true = newTemp( Ity_I32 );
10982 IRTemp SNaN_true = newTemp( Ity_I32 );
10983 IRTemp QNaN_true = newTemp( Ity_I32 );
10984 IRTemp subnormal_true = newTemp( Ity_I32 );
10985 IRTemp normal_true = newTemp( Ity_I32 );
10986 IRTemp extreme_true = newTemp( Ity_I32 );
10987 IRTemp lmd = newTemp( Ity_I32 );
10988 IRTemp lmd_zero_true = newTemp( Ity_I32 );
10989 IRTemp zero_true = newTemp( Ity_I32 );
10990 IRTemp sign = newTemp( Ity_I32 );
10991 IRTemp field = newTemp( Ity_I32 );
10992 IRTemp ccIR_zero = newTemp( Ity_I32 );
10993 IRTemp ccIR_subnormal = newTemp( Ity_I32 );
10994
10995 /* UInt size = DFP_LONG; JRS:unused */
10996 IRTemp gfield = newTemp( Ity_I32 );
10997 IRTemp gfield_0_4_shift = newTemp( Ity_I8 );
10998 IRTemp gfield_mask = newTemp( Ity_I32 );
10999 IRTemp dcm0 = newTemp( Ity_I32 );
11000 IRTemp dcm1 = newTemp( Ity_I32 );
11001 IRTemp dcm2 = newTemp( Ity_I32 );
11002 IRTemp dcm3 = newTemp( Ity_I32 );
11003 IRTemp dcm4 = newTemp( Ity_I32 );
11004 IRTemp dcm5 = newTemp( Ity_I32 );
11005
11006 /* The only difference between the dtstdc and dtstdcq instructions is
11007 * size of the T and G fields. The calculation of the 4 bit field
11008 * is the same. Setup the parameters and values that are DFP size
11009 * specific. The rest of the code is independent of the DFP size.
11010 *
11011 * The Io_CmpD64 is used below. The instruction sets the ccIR values.
11012 * The interpretation of the ccIR values is as follows:
11013 *
11014 * DFP cmp result | IR
11015 * --------------------------
11016 * UN | 0x45
11017 * EQ | 0x40
11018 * GT | 0x00
11019 * LT | 0x01
11020 */
11021
11022 assign( frA, getDReg( frA_addr ) );
11023 assign( frAI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frA ) ) );
11024
11025 assign( abs_frA, unop( Iop_ReinterpI64asD64,
11026 binop( Iop_And64,
11027 unop( Iop_ReinterpD64asI64,
11028 mkexpr( frA ) ),
11029 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ) );
11030 assign( gfield_0_4_shift, mkU8( 31 - 5 ) ); // G-field[0:4]
11031 switch (opc1) {
11032 case 0x3b: // dtstdc, dtstdg
11033 DIP("dtstd%s %u,r%u,%d\n", opc2 == 0xc2 ? "c" : "g",
11034 crfD, frA_addr, DCM);
11035 /* setup the parameters for the long format of the two instructions */
11036 assign( frAI64_lo, mkU64( 0 ) );
11037 assign( gfield_mask, mkU32( DFP_G_FIELD_LONG_MASK ) );
11038 max_exp = DFP_LONG_EXP_MAX;
11039 min_exp = DFP_LONG_EXP_MIN;
11040
carllcea07cc2013-01-22 20:25:31 +000011041 assign( exponent, unop( Iop_64to32,
11042 unop( Iop_ExtractExpD64,
11043 mkexpr( frA ) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000011044 assign( significand64,
11045 unop( Iop_ReinterpI64asD64,
11046 mkU64( 0x2234000000000001ULL ) ) ); // dfp 1.0
carllcea07cc2013-01-22 20:25:31 +000011047 assign( exp_min_normal,mkU64( 398 - 383 ) );
sewardj5eff1c52012-04-29 20:19:17 +000011048 assign( min_subnormalD64,
11049 binop( Iop_InsertExpD64,
11050 mkexpr( exp_min_normal ),
11051 mkexpr( significand64 ) ) );
11052
11053 assign( ccIR_subnormal,
11054 binop( Iop_CmpD64,
11055 mkexpr( abs_frA ),
11056 mkexpr( min_subnormalD64 ) ) );
11057
11058 /* compare absolute value of frA with zero */
11059 assign( ccIR_zero,
11060 binop( Iop_CmpD64,
11061 mkexpr( abs_frA ),
11062 unop( Iop_ReinterpI64asD64,
11063 mkU64( 0x2238000000000000ULL ) ) ) );
11064
11065 /* size = DFP_LONG; JRS: unused */
11066 break;
11067
11068 case 0x3F: // dtstdcq, dtstdgq
11069 DIP("dtstd%sq %u,r%u,%d\n", opc2 == 0xc2 ? "c" : "g",
11070 crfD, frA_addr, DCM);
11071 /* setup the parameters for the extended format of the
11072 * two instructions
11073 */
11074 assign( frAI64_lo, unop( Iop_ReinterpD64asI64,
11075 getDReg( frA_addr+1 ) ) );
11076
11077 assign( gfield_mask, mkU32( DFP_G_FIELD_EXTND_MASK ) );
11078 max_exp = DFP_EXTND_EXP_MAX;
11079 min_exp = DFP_EXTND_EXP_MIN;
11080 assign( exponent, unop( Iop_64to32,
carllcea07cc2013-01-22 20:25:31 +000011081 unop( Iop_ExtractExpD128,
11082 getDReg_pair( frA_addr) ) ) );
sewardj5eff1c52012-04-29 20:19:17 +000011083
11084 /* create quand exponent for minimum normal number */
carllcea07cc2013-01-22 20:25:31 +000011085 assign( exp_min_normal, mkU64( 6176 - 6143 ) );
sewardj5eff1c52012-04-29 20:19:17 +000011086 assign( significand128,
11087 unop( Iop_D64toD128,
11088 unop( Iop_ReinterpI64asD64,
11089 mkU64( 0x2234000000000001ULL ) ) ) ); // dfp 1.0
11090
11091 assign( min_subnormalD128,
11092 binop( Iop_InsertExpD128,
11093 mkexpr( exp_min_normal ),
11094 mkexpr( significand128 ) ) );
11095
11096 assign( ccIR_subnormal,
11097 binop( Iop_CmpD128,
11098 binop( Iop_D64HLtoD128,
11099 unop( Iop_ReinterpI64asD64,
11100 binop( Iop_And64,
11101 unop( Iop_ReinterpD64asI64,
11102 mkexpr( frA ) ),
11103 mkU64( 0x7FFFFFFFFFFFFFFFULL ) ) ),
11104 getDReg( frA_addr+1 ) ),
11105 mkexpr( min_subnormalD128 ) ) );
11106 assign( ccIR_zero,
11107 binop( Iop_CmpD128,
11108 binop( Iop_D64HLtoD128,
11109 mkexpr( abs_frA ),
11110 getDReg( frA_addr+1 ) ),
11111 unop( Iop_D64toD128,
11112 unop( Iop_ReinterpI64asD64,
11113 mkU64( 0x0ULL ) ) ) ) );
11114
11115 /* size = DFP_EXTND; JRS:unused */
11116 break;
11117 default:
11118 vex_printf("dis_dfp_class_test(ppc)(opc2)\n");
11119 return False;
11120 }
11121
11122 /* The G-field is in the upper 32-bits. The I64 logical operations
11123 * do not seem to be supported in 32-bit mode so keep things as 32-bit
11124 * operations.
11125 */
11126 assign( gfield, binop( Iop_And32,
11127 mkexpr( gfield_mask ),
11128 unop( Iop_64HIto32,
11129 mkexpr(frAI64_hi) ) ) );
11130
11131 /* There is a lot of code that is the same to do the class and group
11132 * instructions. Later there is an if statement to handle the specific
11133 * instruction.
11134 *
11135 * Will be using I32 values, compares, shifts and logical operations for
11136 * this code as the 64-bit compare, shifts, logical operations are not
11137 * supported in 32-bit mode.
11138 */
11139
11140 /* Check the bits for Infinity, QNaN or Signaling NaN */
11141 assign( infinity_true,
11142 unop( Iop_1Sto32,
11143 binop( Iop_CmpEQ32,
11144 binop( Iop_And32,
11145 mkU32( 0x7C000000 ),
11146 mkexpr( gfield ) ),
11147 mkU32( 0x78000000 ) ) ) );
11148
11149 assign( SNaN_true,
11150 unop( Iop_1Sto32,
11151 binop( Iop_CmpEQ32,
11152 binop( Iop_And32,
11153 mkU32( 0x7E000000 ),
11154 mkexpr( gfield ) ),
11155 mkU32( 0x7E000000 ) ) ) );
11156
11157 assign( QNaN_true,
11158 binop( Iop_And32,
11159 unop( Iop_1Sto32,
11160 binop( Iop_CmpEQ32,
11161 binop( Iop_And32,
11162 mkU32( 0x7E000000 ),
11163 mkexpr( gfield ) ),
11164 mkU32( 0x7C000000 ) ) ),
11165 unop( Iop_Not32,
11166 mkexpr( SNaN_true ) ) ) );
11167
11168 assign( zero_true,
11169 binop( Iop_And32,
11170 unop(Iop_1Sto32,
11171 binop( Iop_CmpEQ32,
11172 mkexpr( ccIR_zero ),
11173 mkU32( 0x40 ) ) ), // ccIR code for Equal
11174 unop( Iop_Not32,
11175 binop( Iop_Or32,
11176 mkexpr( infinity_true ),
11177 binop( Iop_Or32,
11178 mkexpr( QNaN_true ),
11179 mkexpr( SNaN_true ) ) ) ) ) );
11180
11181 /* Do compare of frA the minimum normal value. Comparison is size
11182 * depenent and was done above to get the ccIR value.
11183 */
11184 assign( subnormal_true,
11185 binop( Iop_And32,
11186 binop( Iop_Or32,
11187 unop( Iop_1Sto32,
11188 binop( Iop_CmpEQ32,
11189 mkexpr( ccIR_subnormal ),
11190 mkU32( 0x40 ) ) ), // ccIR code for Equal
11191 unop( Iop_1Sto32,
11192 binop( Iop_CmpEQ32,
11193 mkexpr( ccIR_subnormal ),
11194 mkU32( 0x1 ) ) ) ), // ccIR code for LT
11195 unop( Iop_Not32,
11196 binop( Iop_Or32,
11197 binop( Iop_Or32,
11198 mkexpr( infinity_true ),
11199 mkexpr( zero_true) ),
11200 binop( Iop_Or32,
11201 mkexpr( QNaN_true ),
11202 mkexpr( SNaN_true ) ) ) ) ) );
11203
11204 /* Normal number is not subnormal, infinity, NaN or Zero */
11205 assign( normal_true,
11206 unop( Iop_Not32,
11207 binop( Iop_Or32,
11208 binop( Iop_Or32,
11209 mkexpr( infinity_true ),
11210 mkexpr( zero_true ) ),
11211 binop( Iop_Or32,
11212 mkexpr( subnormal_true ),
11213 binop( Iop_Or32,
11214 mkexpr( QNaN_true ),
11215 mkexpr( SNaN_true ) ) ) ) ) );
11216
11217 /* Calculate the DCM bit field based on the tests for the specific
11218 * instruction
11219 */
11220 if (opc2 == 0xC2) { // dtstdc, dtstdcq
11221 /* DCM[0:5] Bit Data Class definition
11222 * 0 Zero
11223 * 1 Subnormal
11224 * 2 Normal
11225 * 3 Infinity
11226 * 4 Quiet NaN
11227 * 5 Signaling NaN
11228 */
11229
11230 assign( dcm0, binop( Iop_Shl32,
11231 mkexpr( zero_true ),
11232 mkU8( 5 ) ) );
11233 assign( dcm1, binop( Iop_Shl32,
11234 binop( Iop_And32,
11235 mkexpr( subnormal_true ),
11236 mkU32( 1 ) ),
11237 mkU8( 4 ) ) );
11238 assign( dcm2, binop( Iop_Shl32,
11239 binop( Iop_And32,
11240 mkexpr( normal_true ),
11241 mkU32( 1 ) ),
11242 mkU8( 3 ) ) );
11243 assign( dcm3, binop( Iop_Shl32,
11244 binop( Iop_And32,
11245 mkexpr( infinity_true),
11246 mkU32( 1 ) ),
11247 mkU8( 2 ) ) );
11248 assign( dcm4, binop( Iop_Shl32,
11249 binop( Iop_And32,
11250 mkexpr( QNaN_true ),
11251 mkU32( 1 ) ),
11252 mkU8( 1 ) ) );
11253 assign( dcm5, binop( Iop_And32, mkexpr( SNaN_true), mkU32( 1 ) ) );
11254
11255 } else if (opc2 == 0xE2) { // dtstdg, dtstdgq
11256 /* check if the exponent is extreme */
11257 assign( extreme_true, binop( Iop_Or32,
11258 unop( Iop_1Sto32,
11259 binop( Iop_CmpEQ32,
11260 mkexpr( exponent ),
11261 mkU32( max_exp ) ) ),
11262 unop( Iop_1Sto32,
11263 binop( Iop_CmpEQ32,
11264 mkexpr( exponent ),
11265 mkU32( min_exp ) ) ) ) );
11266
11267 /* Check if LMD is zero */
11268 Get_lmd( &lmd, binop( Iop_Shr32,
11269 mkexpr( gfield ), mkU8( 31 - 5 ) ) );
11270
11271 assign( lmd_zero_true, unop( Iop_1Sto32,
11272 binop( Iop_CmpEQ32,
11273 mkexpr( lmd ),
11274 mkU32( 0 ) ) ) );
11275
11276 /* DCM[0:5] Bit Data Class definition
11277 * 0 Zero with non-extreme exponent
11278 * 1 Zero with extreme exponent
11279 * 2 Subnormal or (Normal with extreme exponent)
11280 * 3 Normal with non-extreme exponent and
11281 * leftmost zero digit in significand
11282 * 4 Normal with non-extreme exponent and
11283 * leftmost nonzero digit in significand
11284 * 5 Special symbol (Infinity, QNaN, or SNaN)
11285 */
11286 assign( dcm0, binop( Iop_Shl32,
11287 binop( Iop_And32,
11288 binop( Iop_And32,
11289 unop( Iop_Not32,
11290 mkexpr( extreme_true ) ),
11291 mkexpr( zero_true ) ),
11292 mkU32( 0x1 ) ),
11293 mkU8( 5 ) ) );
11294
11295 assign( dcm1, binop( Iop_Shl32,
11296 binop( Iop_And32,
11297 binop( Iop_And32,
11298 mkexpr( extreme_true ),
11299 mkexpr( zero_true ) ),
11300 mkU32( 0x1 ) ),
11301 mkU8( 4 ) ) );
11302
11303 assign( dcm2, binop( Iop_Shl32,
11304 binop( Iop_And32,
11305 binop( Iop_Or32,
11306 binop( Iop_And32,
11307 mkexpr( extreme_true ),
11308 mkexpr( normal_true ) ),
11309 mkexpr( subnormal_true ) ),
11310 mkU32( 0x1 ) ),
11311 mkU8( 3 ) ) );
11312
11313 assign( dcm3, binop( Iop_Shl32,
11314 binop( Iop_And32,
11315 binop( Iop_And32,
11316 binop( Iop_And32,
11317 unop( Iop_Not32,
11318 mkexpr( extreme_true ) ),
11319 mkexpr( normal_true ) ),
11320 unop( Iop_1Sto32,
11321 binop( Iop_CmpEQ32,
11322 mkexpr( lmd ),
11323 mkU32( 0 ) ) ) ),
11324 mkU32( 0x1 ) ),
11325 mkU8( 2 ) ) );
11326
11327 assign( dcm4, binop( Iop_Shl32,
11328 binop( Iop_And32,
11329 binop( Iop_And32,
11330 binop( Iop_And32,
11331 unop( Iop_Not32,
11332 mkexpr( extreme_true ) ),
11333 mkexpr( normal_true ) ),
11334 unop( Iop_1Sto32,
11335 binop( Iop_CmpNE32,
11336 mkexpr( lmd ),
sewardj4c96e612012-06-02 23:47:02 +000011337 mkU32( 0 ) ) ) ),
sewardj5eff1c52012-04-29 20:19:17 +000011338 mkU32( 0x1 ) ),
11339 mkU8( 1 ) ) );
11340
11341 assign( dcm5, binop( Iop_And32,
11342 binop( Iop_Or32,
11343 mkexpr( SNaN_true),
11344 binop( Iop_Or32,
11345 mkexpr( QNaN_true),
11346 mkexpr( infinity_true) ) ),
11347 mkU32( 0x1 ) ) );
11348 }
11349
11350 /* create DCM field */
11351 assign( DCM_calc,
11352 binop( Iop_Or32,
11353 mkexpr( dcm0 ),
11354 binop( Iop_Or32,
11355 mkexpr( dcm1 ),
11356 binop( Iop_Or32,
11357 mkexpr( dcm2 ),
11358 binop( Iop_Or32,
11359 mkexpr( dcm3 ),
11360 binop( Iop_Or32,
11361 mkexpr( dcm4 ),
11362 mkexpr( dcm5 ) ) ) ) ) ) );
11363
11364 /* Get the sign of the DFP number, ignore sign for QNaN */
11365 assign( sign,
11366 unop( Iop_1Uto32,
11367 binop( Iop_CmpEQ32,
11368 binop( Iop_Shr32,
11369 unop( Iop_64HIto32, mkexpr( frAI64_hi ) ),
11370 mkU8( 63 - 32 ) ),
11371 mkU32( 1 ) ) ) );
11372
11373 /* This instruction generates a four bit field to be stored in the
11374 * condition code register. The condition code register consists of 7
11375 * fields. The field to be written to is specified by the BF (AKA crfD)
11376 * field.
11377 *
11378 * The field layout is as follows:
11379 *
11380 * Field Meaning
11381 * 0000 Operand positive with no match
11382 * 0100 Operand positive with at least one match
11383 * 0001 Operand negative with no match
11384 * 0101 Operand negative with at least one match
11385 */
11386 assign( field, binop( Iop_Or32,
11387 binop( Iop_Shl32,
11388 mkexpr( sign ),
11389 mkU8( 3 ) ),
11390 binop( Iop_Shl32,
11391 unop( Iop_1Uto32,
11392 binop( Iop_CmpNE32,
11393 binop( Iop_And32,
11394 mkU32( DCM ),
11395 mkexpr( DCM_calc ) ),
11396 mkU32( 0 ) ) ),
11397 mkU8( 1 ) ) ) );
11398
11399 putGST_field( PPC_GST_CR, mkexpr( field ), crfD );
11400 return True;
11401}
11402
sewardj4c96e612012-06-02 23:47:02 +000011403static Bool dis_dfp_bcd(UInt theInstr) {
11404 UInt opc2 = ifieldOPClo10( theInstr );
11405 ULong sp = IFIELD(theInstr, 19, 2);
11406 ULong s = IFIELD(theInstr, 20, 1);
11407 UChar frT_addr = ifieldRegDS( theInstr );
11408 UChar frB_addr = ifieldRegB( theInstr );
11409 IRTemp frB = newTemp( Ity_D64 );
11410 IRTemp frBI64 = newTemp( Ity_I64 );
11411 IRTemp result = newTemp( Ity_I64 );
11412 IRTemp resultD64 = newTemp( Ity_D64 );
11413 IRTemp bcd64 = newTemp( Ity_I64 );
11414 IRTemp bcd_u = newTemp( Ity_I32 );
11415 IRTemp bcd_l = newTemp( Ity_I32 );
11416 IRTemp dbcd_u = newTemp( Ity_I32 );
11417 IRTemp dbcd_l = newTemp( Ity_I32 );
11418 IRTemp lmd = newTemp( Ity_I32 );
11419
11420 assign( frB, getDReg( frB_addr ) );
11421 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
11422
11423 switch ( opc2 ) {
11424 case 0x142: // ddedpd DFP Decode DPD to BCD
11425 DIP( "ddedpd %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
11426
11427 assign( bcd64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
11428 assign( bcd_u, unop( Iop_64HIto32, mkexpr( bcd64 ) ) );
11429 assign( bcd_l, unop( Iop_64to32, mkexpr( bcd64 ) ) );
11430
11431 if ( ( sp == 0 ) || ( sp == 1 ) ) {
11432 /* Unsigned BCD string */
11433 Get_lmd( &lmd,
11434 binop( Iop_Shr32,
11435 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11436 mkU8( 31 - 5 ) ) ); // G-field[0:4]
11437
11438 assign( result,
11439 binop( Iop_32HLto64,
11440 binop( Iop_Or32,
11441 binop( Iop_Shl32, mkexpr( lmd ), mkU8( 28 ) ),
11442 mkexpr( bcd_u ) ),
11443 mkexpr( bcd_l ) ) );
11444
11445 } else {
11446 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
11447 * the positive and negative values are encoded in the least
11448 * significant bits.
11449 */
11450 IRTemp sign = newTemp( Ity_I32 );
11451
11452 if (sp == 2) {
11453 /* Positive sign = 0xC, negative sign = 0xD */
11454
11455 assign( sign,
11456 binop( Iop_Or32,
11457 binop( Iop_Shr32,
11458 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11459 mkU8( 31 ) ),
11460 mkU32( 0xC ) ) );
11461
11462 } else if ( sp == 3 ) {
11463 /* Positive sign = 0xF, negative sign = 0xD */
11464 IRTemp tmp32 = newTemp( Ity_I32 );
11465
11466 /* Complement sign bit then OR into bit position 1 */
11467 assign( tmp32,
11468 binop( Iop_Xor32,
11469 binop( Iop_Shr32,
11470 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11471 mkU8( 30 ) ),
11472 mkU32( 0x2 ) ) );
11473
11474 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
11475
11476 } else {
11477 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
11478 }
11479
11480 /* Put sign in bottom 4 bits, move most significant 4-bits from
11481 * bcd_l to bcd_u.
11482 */
11483 assign( result,
11484 binop( Iop_32HLto64,
11485 binop( Iop_Or32,
11486 binop( Iop_Shr32,
11487 mkexpr( bcd_l ),
11488 mkU8( 28 ) ),
11489 binop( Iop_Shl32,
11490 mkexpr( bcd_u ),
11491 mkU8( 4 ) ) ),
11492 binop( Iop_Or32,
11493 mkexpr( sign ),
11494 binop( Iop_Shl32,
11495 mkexpr( bcd_l ),
11496 mkU8( 4 ) ) ) ) );
11497 }
11498
11499 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result ) ) );
11500 break;
11501
11502 case 0x342: // denbcd DFP Encode BCD to DPD
11503 {
11504 IRTemp valid_mask = newTemp( Ity_I32 );
11505 IRTemp invalid_mask = newTemp( Ity_I32 );
11506 IRTemp without_lmd = newTemp( Ity_I64 );
11507 IRTemp tmp64 = newTemp( Ity_I64 );
11508 IRTemp dbcd64 = newTemp( Ity_I64 );
11509 IRTemp left_exp = newTemp( Ity_I32 );
11510 IRTemp g0_4 = newTemp( Ity_I32 );
11511
11512 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
11513
11514 if ( s == 0 ) {
11515 /* Unsigned BCD string */
11516 assign( dbcd64, unop( Iop_BCDtoDPB, mkexpr(frBI64 ) ) );
11517 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( dbcd64 ) ) );
11518 assign( dbcd_l, unop( Iop_64to32, mkexpr( dbcd64 ) ) );
11519
11520 assign( lmd,
11521 binop( Iop_Shr32,
11522 binop( Iop_And32,
11523 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11524 mkU32( 0xF0000000 ) ),
11525 mkU8( 28 ) ) );
11526
11527 assign( invalid_mask,
11528 bcd_digit_inval( unop( Iop_64HIto32, mkexpr( frBI64 ) ),
11529 unop( Iop_64to32, mkexpr( frBI64 ) ) ) );
11530 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
11531
11532 assign( without_lmd,
11533 unop( Iop_ReinterpD64asI64,
11534 binop( Iop_InsertExpD64,
carllcea07cc2013-01-22 20:25:31 +000011535 mkU64( DFP_LONG_BIAS ),
sewardj4c96e612012-06-02 23:47:02 +000011536 unop( Iop_ReinterpI64asD64,
11537 binop( Iop_32HLto64,
11538 mkexpr( dbcd_u ),
11539 mkexpr( dbcd_l ) ) ) ) ) );
11540 assign( left_exp,
11541 binop( Iop_Shr32,
11542 binop( Iop_And32,
11543 unop( Iop_64HIto32, mkexpr( without_lmd ) ),
11544 mkU32( 0x60000000 ) ),
11545 mkU8( 29 ) ) );
11546
11547 assign( g0_4,
11548 binop( Iop_Shl32,
11549 Gfield_encoding( mkexpr( left_exp ), mkexpr( lmd ) ),
11550 mkU8( 26 ) ) );
11551
11552 assign( tmp64,
11553 binop( Iop_32HLto64,
11554 binop( Iop_Or32,
11555 binop( Iop_And32,
11556 unop( Iop_64HIto32,
11557 mkexpr( without_lmd ) ),
11558 mkU32( 0x83FFFFFF ) ),
11559 mkexpr( g0_4 ) ),
11560 unop( Iop_64to32, mkexpr( without_lmd ) ) ) );
11561
11562 } else if ( s == 1 ) {
11563 IRTemp sign = newTemp( Ity_I32 );
11564 IRTemp sign_bit = newTemp( Ity_I32 );
11565 IRTemp pos_sign_mask = newTemp( Ity_I32 );
11566 IRTemp neg_sign_mask = newTemp( Ity_I32 );
11567 IRTemp tmp = newTemp( Ity_I64 );
11568
11569 /* Signed BCD string, least significant 4 bits are sign bits
11570 * positive sign = 0xC, negative sign = 0xD
11571 */
11572 assign( tmp, unop( Iop_BCDtoDPB,
11573 binop( Iop_32HLto64,
11574 binop( Iop_Shr32,
11575 unop( Iop_64HIto32,
11576 mkexpr( frBI64 ) ),
11577 mkU8( 4 ) ),
11578 binop( Iop_Or32,
11579 binop( Iop_Shr32,
11580 unop( Iop_64to32,
11581 mkexpr( frBI64 ) ),
11582 mkU8( 4 ) ),
11583 binop( Iop_Shl32,
11584 unop( Iop_64HIto32,
11585 mkexpr( frBI64 ) ),
11586 mkU8( 28 ) ) ) ) ) );
11587
11588 assign( dbcd_u, unop( Iop_64HIto32, mkexpr( tmp ) ) );
11589 assign( dbcd_l, unop( Iop_64to32, mkexpr( tmp ) ) );
11590
11591 /* Get the sign of the BCD string. */
11592 assign( sign,
11593 binop( Iop_And32,
11594 unop( Iop_64to32, mkexpr( frBI64 ) ),
11595 mkU32( 0xF ) ) );
11596
11597 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
11598 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
11599 assign( sign_bit,
11600 Generate_sign_bit( mkexpr( pos_sign_mask ),
11601 mkexpr( neg_sign_mask ) ) );
11602
11603 /* Check for invalid sign and BCD digit. Don't check the bottom
11604 * four bits of bcd_l as that is the sign value.
11605 */
11606 assign( invalid_mask,
11607 Generate_inv_mask(
11608 bcd_digit_inval( unop( Iop_64HIto32,
11609 mkexpr( frBI64 ) ),
11610 binop( Iop_Shr32,
11611 unop( Iop_64to32,
11612 mkexpr( frBI64 ) ),
11613 mkU8( 4 ) ) ),
11614 mkexpr( pos_sign_mask ),
11615 mkexpr( neg_sign_mask ) ) );
11616
11617 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
11618
11619 /* Generate the result assuming the sign value was valid. */
11620 assign( tmp64,
11621 unop( Iop_ReinterpD64asI64,
11622 binop( Iop_InsertExpD64,
carllcea07cc2013-01-22 20:25:31 +000011623 mkU64( DFP_LONG_BIAS ),
sewardj4c96e612012-06-02 23:47:02 +000011624 unop( Iop_ReinterpI64asD64,
11625 binop( Iop_32HLto64,
11626 binop( Iop_Or32,
11627 mkexpr( dbcd_u ),
11628 mkexpr( sign_bit ) ),
11629 mkexpr( dbcd_l ) ) ) ) ) );
11630 }
11631
11632 /* Generate the value to store depending on the validity of the
11633 * sign value and the validity of the BCD digits.
11634 */
11635 assign( resultD64,
11636 unop( Iop_ReinterpI64asD64,
11637 binop( Iop_32HLto64,
11638 binop( Iop_Or32,
11639 binop( Iop_And32,
11640 mkexpr( valid_mask ),
11641 unop( Iop_64HIto32,
11642 mkexpr( tmp64 ) ) ),
11643 binop( Iop_And32,
11644 mkU32( 0x7C000000 ),
11645 mkexpr( invalid_mask ) ) ),
11646 binop( Iop_Or32,
11647 binop( Iop_And32,
11648 mkexpr( valid_mask ),
11649 unop( Iop_64to32, mkexpr( tmp64 ) ) ),
11650 binop( Iop_And32,
11651 mkU32( 0x0 ),
11652 mkexpr( invalid_mask ) ) ) ) ) );
11653 putDReg( frT_addr, mkexpr( resultD64 ) );
11654 }
11655 break;
11656 default:
11657 vpanic( "ERROR: dis_dfp_bcd(ppc), undefined opc2 case " );
11658 return False;
11659 }
11660 return True;
11661}
11662
11663static Bool dis_dfp_bcdq( UInt theInstr )
11664{
11665 UInt opc2 = ifieldOPClo10( theInstr );
11666 ULong sp = IFIELD(theInstr, 19, 2);
11667 ULong s = IFIELD(theInstr, 20, 1);
11668 IRTemp frB_hi = newTemp( Ity_D64 );
11669 IRTemp frB_lo = newTemp( Ity_D64 );
11670 IRTemp frBI64_hi = newTemp( Ity_I64 );
11671 IRTemp frBI64_lo = newTemp( Ity_I64 );
11672 UChar frT_addr = ifieldRegDS( theInstr );
11673 UChar frB_addr = ifieldRegB( theInstr );
11674
11675 IRTemp lmd = newTemp( Ity_I32 );
11676 IRTemp result_hi = newTemp( Ity_I64 );
11677 IRTemp result_lo = newTemp( Ity_I64 );
11678
11679 assign( frB_hi, getDReg( frB_addr ) );
11680 assign( frB_lo, getDReg( frB_addr + 1 ) );
11681 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
11682 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
11683
11684 switch ( opc2 ) {
11685 case 0x142: // ddedpdq DFP Decode DPD to BCD
11686 {
11687 IRTemp low_60_u = newTemp( Ity_I32 );
11688 IRTemp low_60_l = newTemp( Ity_I32 );
11689 IRTemp mid_60_u = newTemp( Ity_I32 );
11690 IRTemp mid_60_l = newTemp( Ity_I32 );
11691 IRTemp top_12_l = newTemp( Ity_I32 );
11692
11693 DIP( "ddedpdq %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
11694
11695 /* Note, instruction only stores the lower 32 BCD digits in
11696 * the result
11697 */
11698 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
11699 mkexpr( frBI64_lo ),
11700 &top_12_l,
11701 &mid_60_u,
11702 &mid_60_l,
11703 &low_60_u,
11704 &low_60_l );
11705
11706 if ( ( sp == 0 ) || ( sp == 1 ) ) {
11707 /* Unsigned BCD string */
11708 assign( result_hi,
11709 binop( Iop_32HLto64,
11710 binop( Iop_Or32,
11711 binop( Iop_Shl32,
11712 mkexpr( top_12_l ),
11713 mkU8( 24 ) ),
11714 binop( Iop_Shr32,
11715 mkexpr( mid_60_u ),
11716 mkU8( 4 ) ) ),
11717 binop( Iop_Or32,
11718 binop( Iop_Shl32,
11719 mkexpr( mid_60_u ),
11720 mkU8( 28 ) ),
11721 binop( Iop_Shr32,
11722 mkexpr( mid_60_l ),
11723 mkU8( 4 ) ) ) ) );
11724
11725 assign( result_lo,
11726 binop( Iop_32HLto64,
11727 binop( Iop_Or32,
11728 binop( Iop_Shl32,
11729 mkexpr( mid_60_l ),
11730 mkU8( 28 ) ),
11731 mkexpr( low_60_u ) ),
11732 mkexpr( low_60_l ) ) );
11733
11734 } else {
11735 /* Signed BCD string, the cases for sp 2 and 3 only differ in how
11736 * the positive and negative values are encoded in the least
11737 * significant bits.
11738 */
11739 IRTemp sign = newTemp( Ity_I32 );
11740
11741 if ( sp == 2 ) {
11742 /* Positive sign = 0xC, negative sign = 0xD */
11743 assign( sign,
11744 binop( Iop_Or32,
11745 binop( Iop_Shr32,
11746 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
11747 mkU8( 31 ) ),
11748 mkU32( 0xC ) ) );
11749
11750 } else if ( sp == 3 ) {
11751 IRTemp tmp32 = newTemp( Ity_I32 );
11752
11753 /* Positive sign = 0xF, negative sign = 0xD.
11754 * Need to complement sign bit then OR into bit position 1.
11755 */
11756 assign( tmp32,
11757 binop( Iop_Xor32,
11758 binop( Iop_Shr32,
11759 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
11760 mkU8( 30 ) ),
11761 mkU32( 0x2 ) ) );
11762
11763 assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
11764
11765 } else {
11766 vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
11767 }
11768
11769 assign( result_hi,
11770 binop( Iop_32HLto64,
11771 binop( Iop_Or32,
11772 binop( Iop_Shl32,
11773 mkexpr( top_12_l ),
11774 mkU8( 28 ) ),
11775 mkexpr( mid_60_u ) ),
11776 mkexpr( mid_60_l ) ) );
11777
11778 assign( result_lo,
11779 binop( Iop_32HLto64,
11780 binop( Iop_Or32,
11781 binop( Iop_Shl32,
11782 mkexpr( low_60_u ),
11783 mkU8( 4 ) ),
11784 binop( Iop_Shr32,
11785 mkexpr( low_60_l ),
11786 mkU8( 28 ) ) ),
11787 binop( Iop_Or32,
11788 binop( Iop_Shl32,
11789 mkexpr( low_60_l ),
11790 mkU8( 4 ) ),
11791 mkexpr( sign ) ) ) );
11792 }
11793
11794 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
11795 putDReg( frT_addr + 1,
11796 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
11797 }
11798 break;
11799 case 0x342: // denbcdq DFP Encode BCD to DPD
11800 {
11801 IRTemp valid_mask = newTemp( Ity_I32 );
11802 IRTemp invalid_mask = newTemp( Ity_I32 );
11803 IRTemp result128 = newTemp( Ity_D128 );
11804 IRTemp dfp_significand = newTemp( Ity_D128 );
11805 IRTemp tmp_hi = newTemp( Ity_I64 );
11806 IRTemp tmp_lo = newTemp( Ity_I64 );
11807 IRTemp dbcd_top_l = newTemp( Ity_I32 );
11808 IRTemp dbcd_mid_u = newTemp( Ity_I32 );
11809 IRTemp dbcd_mid_l = newTemp( Ity_I32 );
11810 IRTemp dbcd_low_u = newTemp( Ity_I32 );
11811 IRTemp dbcd_low_l = newTemp( Ity_I32 );
11812 IRTemp bcd_top_8 = newTemp( Ity_I64 );
11813 IRTemp bcd_mid_60 = newTemp( Ity_I64 );
11814 IRTemp bcd_low_60 = newTemp( Ity_I64 );
11815 IRTemp sign_bit = newTemp( Ity_I32 );
11816 IRTemp tmptop10 = newTemp( Ity_I64 );
11817 IRTemp tmpmid50 = newTemp( Ity_I64 );
11818 IRTemp tmplow50 = newTemp( Ity_I64 );
11819 IRTemp inval_bcd_digit_mask = newTemp( Ity_I32 );
11820
11821 DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
11822
11823 if ( s == 0 ) {
11824 /* Unsigned BCD string */
11825 assign( sign_bit, mkU32( 0 ) ); // set to zero for unsigned string
11826
11827 assign( bcd_top_8,
11828 binop( Iop_32HLto64,
11829 mkU32( 0 ),
11830 binop( Iop_And32,
11831 binop( Iop_Shr32,
11832 unop( Iop_64HIto32,
11833 mkexpr( frBI64_hi ) ),
11834 mkU8( 24 ) ),
11835 mkU32( 0xFF ) ) ) );
11836 assign( bcd_mid_60,
11837 binop( Iop_32HLto64,
11838 binop( Iop_Or32,
11839 binop( Iop_Shr32,
11840 unop( Iop_64to32,
11841 mkexpr( frBI64_hi ) ),
11842 mkU8( 28 ) ),
11843 binop( Iop_Shl32,
11844 unop( Iop_64HIto32,
11845 mkexpr( frBI64_hi ) ),
11846 mkU8( 4 ) ) ),
11847 binop( Iop_Or32,
11848 binop( Iop_Shl32,
11849 unop( Iop_64to32,
11850 mkexpr( frBI64_hi ) ),
11851 mkU8( 4 ) ),
11852 binop( Iop_Shr32,
11853 unop( Iop_64HIto32,
11854 mkexpr( frBI64_lo ) ),
11855 mkU8( 28 ) ) ) ) );
11856
11857 /* Note, the various helper functions ignores top 4-bits */
11858 assign( bcd_low_60, mkexpr( frBI64_lo ) );
11859
11860 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr( bcd_top_8 ) ) );
11861 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
11862
11863 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr( bcd_mid_60 ) ) );
11864 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
11865 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
11866
11867 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
11868 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
11869 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
11870
11871 /* The entire BCD string fits in lower 110-bits. The LMD = 0,
11872 * value is not part of the final result. Only the right most
11873 * BCD digits are stored.
11874 */
11875 assign( lmd, mkU32( 0 ) );
11876
11877 assign( invalid_mask,
11878 binop( Iop_Or32,
11879 bcd_digit_inval( mkU32( 0 ),
11880 unop( Iop_64to32,
11881 mkexpr( bcd_top_8 ) ) ),
11882 binop( Iop_Or32,
11883 bcd_digit_inval( unop( Iop_64HIto32,
11884 mkexpr( bcd_mid_60 ) ),
11885 unop( Iop_64to32,
11886 mkexpr( bcd_mid_60 ) ) ),
11887 bcd_digit_inval( unop( Iop_64HIto32,
11888 mkexpr( bcd_low_60 ) ),
11889 unop( Iop_64to32,
11890 mkexpr( bcd_low_60 ) )
11891 ) ) ) );
11892
11893 } else if ( s == 1 ) {
11894 IRTemp sign = newTemp( Ity_I32 );
11895 IRTemp zero = newTemp( Ity_I32 );
11896 IRTemp pos_sign_mask = newTemp( Ity_I32 );
11897 IRTemp neg_sign_mask = newTemp( Ity_I32 );
11898
11899 /* The sign of the BCD string is stored in lower 4 bits */
11900 assign( sign,
11901 binop( Iop_And32,
11902 unop( Iop_64to32, mkexpr( frBI64_lo ) ),
11903 mkU32( 0xF ) ) );
11904 assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
11905 assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
11906 assign( sign_bit,
11907 Generate_sign_bit( mkexpr( pos_sign_mask ),
11908 mkexpr( neg_sign_mask ) ) );
11909
11910 /* Generate the value assuminig the sign and BCD digits are vaild */
11911 assign( bcd_top_8,
11912 binop( Iop_32HLto64,
11913 mkU32( 0x0 ),
11914 binop( Iop_Shr32,
11915 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
11916 mkU8( 28 ) ) ) );
11917
11918 /* The various helper routines ignore the upper 4-bits */
11919 assign( bcd_mid_60, mkexpr( frBI64_hi ) );
11920
11921 /* Remove bottom four sign bits */
11922 assign( bcd_low_60,
11923 binop( Iop_32HLto64,
11924 binop( Iop_Shr32,
11925 unop( Iop_64HIto32,
11926 mkexpr( frBI64_lo ) ),
11927 mkU8( 4 ) ),
11928 binop( Iop_Or32,
11929 binop( Iop_Shl32,
11930 unop( Iop_64HIto32,
11931 mkexpr( frBI64_lo ) ),
11932 mkU8( 28 ) ),
11933 binop( Iop_Shr32,
11934 unop( Iop_64to32,
11935 mkexpr( frBI64_lo ) ),
11936 mkU8( 4 ) ) ) ) );
11937 assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr(bcd_top_8 ) ) );
11938 assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
11939
11940 assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr(bcd_mid_60 ) ) );
11941 assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
11942 assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
11943
11944 assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
11945 assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
11946 assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
11947
11948 /* The entire BCD string fits in lower 110-bits. The LMD value
11949 * is not stored in the final result for the DFP Long instruction.
11950 */
11951 assign( lmd, mkU32( 0 ) );
11952
11953 /* Check for invalid sign and invalid BCD digit. Don't check the
11954 * bottom four bits of frBI64_lo as that is the sign value.
11955 */
11956 assign( zero, mkU32( 0 ) );
11957 assign( inval_bcd_digit_mask,
11958 binop( Iop_Or32,
11959 bcd_digit_inval( mkexpr( zero ),
11960 unop( Iop_64to32,
11961 mkexpr( bcd_top_8 ) ) ),
11962 binop( Iop_Or32,
11963 bcd_digit_inval( unop( Iop_64HIto32,
11964 mkexpr( bcd_mid_60 ) ),
11965 unop( Iop_64to32,
11966 mkexpr( bcd_mid_60 ) ) ),
11967 bcd_digit_inval( unop( Iop_64HIto32,
11968 mkexpr( frBI64_lo ) ),
11969 binop( Iop_Shr32,
11970 unop( Iop_64to32,
11971 mkexpr( frBI64_lo ) ),
11972 mkU8( 4 ) ) ) ) ) );
11973 assign( invalid_mask,
11974 Generate_inv_mask( mkexpr( inval_bcd_digit_mask ),
11975 mkexpr( pos_sign_mask ),
11976 mkexpr( neg_sign_mask ) ) );
11977
11978 }
11979
11980 assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
11981
11982 /* Calculate the value of the result assuming sign and BCD digits
11983 * are all valid.
11984 */
11985 assign( dfp_significand,
11986 binop( Iop_D64HLtoD128,
11987 unop( Iop_ReinterpI64asD64,
11988 binop( Iop_32HLto64,
11989 binop( Iop_Or32,
11990 mkexpr( sign_bit ),
11991 mkexpr( dbcd_top_l ) ),
11992 binop( Iop_Or32,
11993 binop( Iop_Shl32,
11994 mkexpr( dbcd_mid_u ),
11995 mkU8( 18 ) ),
11996 binop( Iop_Shr32,
11997 mkexpr( dbcd_mid_l ),
11998 mkU8( 14 ) ) ) ) ),
11999 unop( Iop_ReinterpI64asD64,
12000 binop( Iop_32HLto64,
12001 binop( Iop_Or32,
12002 mkexpr( dbcd_low_u ),
12003 binop( Iop_Shl32,
12004 mkexpr( dbcd_mid_l ),
12005 mkU8( 18 ) ) ),
12006 mkexpr( dbcd_low_l ) ) ) ) );
12007
12008 /* Break the result back down to 32-bit chunks and replace chunks.
12009 * If there was an invalid BCD digit or invalid sign value, replace
12010 * the calculated result with the invalid bit string.
12011 */
12012 assign( result128,
12013 binop( Iop_InsertExpD128,
carllcea07cc2013-01-22 20:25:31 +000012014 mkU64( DFP_EXTND_BIAS ),
sewardj4c96e612012-06-02 23:47:02 +000012015 mkexpr( dfp_significand ) ) );
12016
12017 assign( tmp_hi,
12018 unop( Iop_ReinterpD64asI64,
12019 unop( Iop_D128HItoD64, mkexpr( result128 ) ) ) );
12020
12021 assign( tmp_lo,
12022 unop( Iop_ReinterpD64asI64,
12023 unop( Iop_D128LOtoD64, mkexpr( result128 ) ) ) );
12024
12025 assign( result_hi,
12026 binop( Iop_32HLto64,
12027 binop( Iop_Or32,
12028 binop( Iop_And32,
12029 mkexpr( valid_mask ),
12030 unop( Iop_64HIto32, mkexpr( tmp_hi ) ) ),
12031 binop( Iop_And32,
12032 mkU32( 0x7C000000 ),
12033 mkexpr( invalid_mask ) ) ),
12034 binop( Iop_Or32,
12035 binop( Iop_And32,
12036 mkexpr( valid_mask ),
12037 unop( Iop_64to32, mkexpr( tmp_hi ) ) ),
12038 binop( Iop_And32,
12039 mkU32( 0x0 ),
12040 mkexpr( invalid_mask ) ) ) ) );
12041
12042 assign( result_lo,
12043 binop( Iop_32HLto64,
12044 binop( Iop_Or32,
12045 binop( Iop_And32,
12046 mkexpr( valid_mask ),
12047 unop( Iop_64HIto32, mkexpr( tmp_lo ) ) ),
12048 binop( Iop_And32,
12049 mkU32( 0x0 ),
12050 mkexpr( invalid_mask ) ) ),
12051 binop( Iop_Or32,
12052 binop( Iop_And32,
12053 mkexpr( valid_mask ),
12054 unop( Iop_64to32, mkexpr( tmp_lo ) ) ),
12055 binop( Iop_And32,
12056 mkU32( 0x0 ),
12057 mkexpr( invalid_mask ) ) ) ) );
12058
12059 putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
12060 putDReg( frT_addr + 1,
12061 unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
12062
12063 }
12064 break;
12065 default:
12066 vpanic( "ERROR: dis_dfp_bcdq(ppc), undefined opc2 case " );
12067 break;
12068 }
12069 return True;
12070}
12071
12072static Bool dis_dfp_significant_digits( UInt theInstr )
12073{
12074 UChar frA_addr = ifieldRegA( theInstr );
12075 UChar frB_addr = ifieldRegB( theInstr );
12076 IRTemp frA = newTemp( Ity_D64 );
12077 UInt opc1 = ifieldOPC( theInstr );
12078 IRTemp B_sig = newTemp( Ity_I8 );
12079 IRTemp K = newTemp( Ity_I8 );
12080 IRTemp lmd_B = newTemp( Ity_I32 );
12081 IRTemp field = newTemp( Ity_I32 );
12082 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
12083 IRTemp Unordered_true = newTemp( Ity_I32 );
12084 IRTemp Eq_true_mask = newTemp( Ity_I32 );
12085 IRTemp Lt_true_mask = newTemp( Ity_I32 );
12086 IRTemp Gt_true_mask = newTemp( Ity_I32 );
12087 IRTemp KisZero_true_mask = newTemp( Ity_I32 );
12088 IRTemp KisZero_false_mask = newTemp( Ity_I32 );
12089
12090 /* Get the reference singificance stored in frA */
12091 assign( frA, getDReg( frA_addr ) );
12092
12093 /* Convert from 64 bit to 8 bits in two steps. The Iop_64to8 is not
12094 * supported in 32-bit mode.
12095 */
12096 assign( K, unop( Iop_32to8,
12097 binop( Iop_And32,
12098 unop( Iop_64to32,
12099 unop( Iop_ReinterpD64asI64,
12100 mkexpr( frA ) ) ),
12101 mkU32( 0x3F ) ) ) );
12102
12103 switch ( opc1 ) {
12104 case 0x3b: // dtstsf DFP Test Significance
12105 {
12106 IRTemp frB = newTemp( Ity_D64 );
12107 IRTemp frBI64 = newTemp( Ity_I64 );
12108 IRTemp B_bcd_u = newTemp( Ity_I32 );
12109 IRTemp B_bcd_l = newTemp( Ity_I32 );
12110 IRTemp tmp64 = newTemp( Ity_I64 );
12111
12112 DIP( "dtstsf %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
12113
12114 assign( frB, getDReg( frB_addr ) );
12115 assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
12116
12117 /* Get the BCD string for the value stored in a series of I32 values.
12118 * Count the number of leading zeros. Subtract the number of leading
12119 * zeros from 16 (maximum number of significant digits in DFP
12120 * Long).
12121 */
12122 Get_lmd( &lmd_B,
12123 binop( Iop_Shr32,
12124 unop( Iop_64HIto32, mkexpr( frBI64 ) ),
12125 mkU8( 31 - 5 ) ) ); // G-field[0:4]
12126
12127 assign( tmp64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
12128 assign( B_bcd_u, unop( Iop_64HIto32, mkexpr( tmp64 ) ) );
12129 assign( B_bcd_l, unop( Iop_64to32, mkexpr( tmp64 ) ) );
12130
12131 assign( B_sig,
12132 binop( Iop_Sub8,
12133 mkU8( DFP_LONG_MAX_SIG_DIGITS ),
12134 Count_leading_zeros_60( mkexpr( lmd_B ),
12135 mkexpr( B_bcd_u ),
12136 mkexpr( B_bcd_l ) ) ) );
12137 assign( Unordered_true, Check_unordered( mkexpr( frBI64 ) ) );
12138 }
12139 break;
12140 case 0x3F: // dtstsfq DFP Test Significance
12141 {
12142 IRTemp frB_hi = newTemp( Ity_D64 );
12143 IRTemp frB_lo = newTemp( Ity_D64 );
12144 IRTemp frBI64_hi = newTemp( Ity_I64 );
12145 IRTemp frBI64_lo = newTemp( Ity_I64 );
12146 IRTemp B_low_60_u = newTemp( Ity_I32 );
12147 IRTemp B_low_60_l = newTemp( Ity_I32 );
12148 IRTemp B_mid_60_u = newTemp( Ity_I32 );
12149 IRTemp B_mid_60_l = newTemp( Ity_I32 );
12150 IRTemp B_top_12_l = newTemp( Ity_I32 );
12151
12152 DIP( "dtstsfq %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
12153
12154 assign( frB_hi, getDReg( frB_addr ) );
12155 assign( frB_lo, getDReg( frB_addr + 1 ) );
12156
12157 assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
12158 assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
12159
12160 /* Get the BCD string for the value stored in a series of I32 values.
12161 * Count the number of leading zeros. Subtract the number of leading
12162 * zeros from 32 (maximum number of significant digits in DFP
12163 * extended).
12164 */
12165 Get_lmd( &lmd_B,
12166 binop( Iop_Shr32,
12167 unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
12168 mkU8( 31 - 5 ) ) ); // G-field[0:4]
12169
12170 Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
12171 mkexpr( frBI64_lo ),
12172 &B_top_12_l,
12173 &B_mid_60_u,
12174 &B_mid_60_l,
12175 &B_low_60_u,
12176 &B_low_60_l );
12177
12178 assign( B_sig,
12179 binop( Iop_Sub8,
12180 mkU8( DFP_EXTND_MAX_SIG_DIGITS ),
12181 Count_leading_zeros_128( mkexpr( lmd_B ),
12182 mkexpr( B_top_12_l ),
12183 mkexpr( B_mid_60_u ),
12184 mkexpr( B_mid_60_l ),
12185 mkexpr( B_low_60_u ),
12186 mkexpr( B_low_60_l ) ) ) );
12187
12188 assign( Unordered_true, Check_unordered( mkexpr( frBI64_hi ) ) );
12189 }
12190 break;
12191 }
12192
12193 /* Compare (16 - cnt[0]) against K and set the condition code field
12194 * accordingly.
12195 *
12196 * The field layout is as follows:
12197 *
12198 * bit[3:0] Description
12199 * 3 K != 0 and K < Number of significant digits if FRB
12200 * 2 K != 0 and K > Number of significant digits if FRB OR K = 0
12201 * 1 K != 0 and K = Number of significant digits if FRB
12202 * 0 K ? Number of significant digits if FRB
12203 */
12204 assign( Eq_true_mask,
12205 unop( Iop_1Sto32,
12206 binop( Iop_CmpEQ32,
12207 unop( Iop_8Uto32, mkexpr( K ) ),
12208 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
12209 assign( Lt_true_mask,
12210 unop( Iop_1Sto32,
12211 binop( Iop_CmpLT32U,
12212 unop( Iop_8Uto32, mkexpr( K ) ),
12213 unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
12214 assign( Gt_true_mask,
12215 unop( Iop_1Sto32,
12216 binop( Iop_CmpLT32U,
12217 unop( Iop_8Uto32, mkexpr( B_sig ) ),
12218 unop( Iop_8Uto32, mkexpr( K ) ) ) ) );
12219
12220 assign( KisZero_true_mask,
12221 unop( Iop_1Sto32,
12222 binop( Iop_CmpEQ32,
12223 unop( Iop_8Uto32, mkexpr( K ) ),
12224 mkU32( 0 ) ) ) );
12225 assign( KisZero_false_mask,
12226 unop( Iop_1Sto32,
12227 binop( Iop_CmpNE32,
12228 unop( Iop_8Uto32, mkexpr( K ) ),
12229 mkU32( 0 ) ) ) );
12230
12231 assign( field,
12232 binop( Iop_Or32,
12233 binop( Iop_And32,
12234 mkexpr( KisZero_false_mask ),
12235 binop( Iop_Or32,
12236 binop( Iop_And32,
12237 mkexpr( Lt_true_mask ),
12238 mkU32( 0x8 ) ),
12239 binop( Iop_Or32,
12240 binop( Iop_And32,
12241 mkexpr( Gt_true_mask ),
12242 mkU32( 0x4 ) ),
12243 binop( Iop_And32,
12244 mkexpr( Eq_true_mask ),
12245 mkU32( 0x2 ) ) ) ) ),
12246 binop( Iop_And32,
12247 mkexpr( KisZero_true_mask ),
12248 mkU32( 0x4 ) ) ) );
12249
12250 putGST_field( PPC_GST_CR,
12251 binop( Iop_Or32,
12252 binop( Iop_And32,
12253 mkexpr( Unordered_true ),
12254 mkU32( 0x1 ) ),
12255 binop( Iop_And32,
12256 unop( Iop_Not32, mkexpr( Unordered_true ) ),
12257 mkexpr( field ) ) ),
12258 crfD );
12259
12260 return True;
12261}
sewardj5eff1c52012-04-29 20:19:17 +000012262
cerion32aad402005-09-10 12:02:24 +000012263/*------------------------------------------------------------*/
12264/*--- AltiVec Instruction Translation ---*/
12265/*------------------------------------------------------------*/
12266
12267/*
12268 Altivec Cache Control Instructions (Data Streams)
12269*/
12270static Bool dis_av_datastream ( UInt theInstr )
12271{
cerion76de5cf2005-11-18 18:25:12 +000012272 /* X-Form */
12273 UChar opc1 = ifieldOPC(theInstr);
12274 UChar flag_T = toUChar( IFIELD( theInstr, 25, 1 ) );
12275 UChar flag_A = flag_T;
12276 UChar b23to24 = toUChar( IFIELD( theInstr, 23, 2 ) );
12277 UChar STRM = toUChar( IFIELD( theInstr, 21, 2 ) );
12278 UChar rA_addr = ifieldRegA(theInstr);
12279 UChar rB_addr = ifieldRegB(theInstr);
12280 UInt opc2 = ifieldOPClo10(theInstr);
12281 UChar b0 = ifieldBIT0(theInstr);
cerion32aad402005-09-10 12:02:24 +000012282
12283 if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012284 vex_printf("dis_av_datastream(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000012285 return False;
12286 }
12287
12288 switch (opc2) {
12289 case 0x156: // dst (Data Stream Touch, AV p115)
cerion5b2325f2005-12-23 00:55:09 +000012290 DIP("dst%s r%u,r%u,%d\n", flag_T ? "t" : "",
12291 rA_addr, rB_addr, STRM);
sewardj923c65b2006-12-27 23:59:31 +000012292 break;
cerion32aad402005-09-10 12:02:24 +000012293
12294 case 0x176: // dstst (Data Stream Touch for Store, AV p117)
cerion5b2325f2005-12-23 00:55:09 +000012295 DIP("dstst%s r%u,r%u,%d\n", flag_T ? "t" : "",
12296 rA_addr, rB_addr, STRM);
sewardj923c65b2006-12-27 23:59:31 +000012297 break;
cerion32aad402005-09-10 12:02:24 +000012298
12299 case 0x336: // dss (Data Stream Stop, AV p114)
12300 if (rA_addr != 0 || rB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012301 vex_printf("dis_av_datastream(ppc)(opc2,dst)\n");
cerion32aad402005-09-10 12:02:24 +000012302 return False;
12303 }
12304 if (flag_A == 0) {
12305 DIP("dss %d\n", STRM);
cerion32aad402005-09-10 12:02:24 +000012306 } else {
12307 DIP("dssall\n");
cerion32aad402005-09-10 12:02:24 +000012308 }
sewardj923c65b2006-12-27 23:59:31 +000012309 break;
cerion32aad402005-09-10 12:02:24 +000012310
12311 default:
cerion5b2325f2005-12-23 00:55:09 +000012312 vex_printf("dis_av_datastream(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000012313 return False;
12314 }
12315 return True;
12316}
12317
12318/*
12319 AltiVec Processor Control Instructions
12320*/
12321static Bool dis_av_procctl ( UInt theInstr )
12322{
cerion76de5cf2005-11-18 18:25:12 +000012323 /* VX-Form */
12324 UChar opc1 = ifieldOPC(theInstr);
12325 UChar vD_addr = ifieldRegDS(theInstr);
12326 UChar vA_addr = ifieldRegA(theInstr);
12327 UChar vB_addr = ifieldRegB(theInstr);
12328 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000012329
12330 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000012331 vex_printf("dis_av_procctl(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000012332 return False;
12333 }
12334
12335 switch (opc2) {
12336 case 0x604: // mfvscr (Move from VSCR, AV p129)
12337 if (vA_addr != 0 || vB_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012338 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
cerion32aad402005-09-10 12:02:24 +000012339 return False;
12340 }
12341 DIP("mfvscr v%d\n", vD_addr);
ceriond953ebb2005-11-29 13:27:20 +000012342 putVReg( vD_addr, unop(Iop_32UtoV128, getGST( PPC_GST_VSCR )) );
cerion225a0342005-09-12 20:49:09 +000012343 break;
cerion32aad402005-09-10 12:02:24 +000012344
cerion225a0342005-09-12 20:49:09 +000012345 case 0x644: { // mtvscr (Move to VSCR, AV p130)
sewardj197bd172005-10-12 11:34:33 +000012346 IRTemp vB = newTemp(Ity_V128);
cerion32aad402005-09-10 12:02:24 +000012347 if (vD_addr != 0 || vA_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000012348 vex_printf("dis_av_procctl(ppc)(opc2,dst)\n");
cerion32aad402005-09-10 12:02:24 +000012349 return False;
12350 }
12351 DIP("mtvscr v%d\n", vB_addr);
cerion225a0342005-09-12 20:49:09 +000012352 assign( vB, getVReg(vB_addr));
ceriond953ebb2005-11-29 13:27:20 +000012353 putGST( PPC_GST_VSCR, unop(Iop_V128to32, mkexpr(vB)) );
cerion225a0342005-09-12 20:49:09 +000012354 break;
12355 }
cerion32aad402005-09-10 12:02:24 +000012356 default:
cerion5b2325f2005-12-23 00:55:09 +000012357 vex_printf("dis_av_procctl(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000012358 return False;
12359 }
12360 return True;
12361}
ceriona982c052005-06-28 17:23:09 +000012362
12363/*
sewardj4aa412a2011-07-24 14:13:21 +000012364 * VSX scalar and vector convert instructions
sewardj66d5ef22011-04-15 11:55:00 +000012365 */
12366static Bool
12367dis_vx_conv ( UInt theInstr, UInt opc2 )
12368{
12369 /* XX2-Form */
12370 UChar opc1 = ifieldOPC( theInstr );
12371 UChar XT = ifieldRegXT( theInstr );
12372 UChar XB = ifieldRegXB( theInstr );
sewardje71e56a2011-09-05 12:11:06 +000012373 IRTemp xB, xB2;
12374 IRTemp b3, b2, b1, b0;
12375 xB = xB2 = IRTemp_INVALID;
sewardj66d5ef22011-04-15 11:55:00 +000012376
12377 if (opc1 != 0x3C) {
12378 vex_printf( "dis_vx_conv(ppc)(instr)\n" );
12379 return False;
12380 }
12381
sewardje71e56a2011-09-05 12:11:06 +000012382 /* Create and assign temps only as needed for the given instruction. */
12383 switch (opc2) {
12384 // scalar double-precision floating point argument
carll0c74bb52013-08-12 18:01:40 +000012385 case 0x2B0: case 0x0b0: case 0x290: case 0x212: case 0x216: case 0x090:
sewardje71e56a2011-09-05 12:11:06 +000012386 xB = newTemp(Ity_F64);
12387 assign( xB,
12388 unop( Iop_ReinterpI64asF64,
12389 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
12390 break;
12391 // vector double-precision floating point arguments
12392 case 0x1b0: case 0x312: case 0x390: case 0x190: case 0x3B0:
12393
12394 xB = newTemp(Ity_F64);
12395 xB2 = newTemp(Ity_F64);
12396 assign( xB,
12397 unop( Iop_ReinterpI64asF64,
12398 unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
12399 assign( xB2,
12400 unop( Iop_ReinterpI64asF64,
12401 unop( Iop_V128to64, getVSReg( XB ) ) ) );
12402 break;
12403 // vector single precision or [un]signed integer word arguments
12404 case 0x130: case 0x392: case 0x330: case 0x310: case 0x110:
12405 case 0x1f0: case 0x1d0:
12406 b3 = b2 = b1 = b0 = IRTemp_INVALID;
12407 breakV128to4x32(getVSReg(XB), &b3, &b2, &b1, &b0);
12408 break;
12409 // vector [un]signed integer doubleword argument
12410 case 0x3f0: case 0x370: case 0x3d0: case 0x350:
12411 xB = newTemp(Ity_I64);
12412 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
12413 xB2 = newTemp(Ity_I64);
12414 assign( xB2, unop( Iop_V128to64, getVSReg( XB ) ) );
12415 break;
12416 // scalar [un]signed integer doubleword argument
carll6c758b62013-10-03 21:38:45 +000012417 case 0x250: case 0x270: case 0x2D0: case 0x2F0:
sewardje71e56a2011-09-05 12:11:06 +000012418 xB = newTemp(Ity_I64);
12419 assign( xB, unop( Iop_V128HIto64, getVSReg( XB ) ) );
12420 break;
12421 // scalar single precision argument
12422 case 0x292: // xscvspdp
carll6fef87a2013-09-12 17:26:42 +000012423 xB = newTemp(Ity_I32);
12424
12425 assign( xB, handle_SNaN_to_QNaN_32(unop( Iop_64HIto32,
12426 unop( Iop_V128HIto64,
12427 getVSReg( XB ) ) ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012428 break;
carll0c74bb52013-08-12 18:01:40 +000012429 case 0x296: // xscvspdpn (non signaling version of xscvpdp)
12430 xB = newTemp(Ity_I32);
12431 assign( xB,
12432 unop( Iop_64HIto32, unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
12433 break;
sewardje71e56a2011-09-05 12:11:06 +000012434
12435 /* Certain instructions have their complete implementation in the main switch statement
12436 * that follows this one; thus we have a "do nothing" case for those instructions here.
12437 */
12438 case 0x170: case 0x150:
12439 break; // do nothing
12440
12441 default:
12442 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
12443 return False;
12444 }
12445
sewardj66d5ef22011-04-15 11:55:00 +000012446
12447 switch (opc2) {
sewardje71e56a2011-09-05 12:11:06 +000012448 case 0x2B0:
12449 // xscvdpsxds (VSX Scalar truncate Double-Precision to integer and Convert
12450 // to Signed Integer Doubleword format with Saturate)
12451 DIP("xscvdpsxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12452 putVSReg( XT,
sewardj66d5ef22011-04-15 11:55:00 +000012453 binop( Iop_64HLtoV128, binop( Iop_F64toI64S,
12454 mkU32( Irrm_ZERO ),
sewardje71e56a2011-09-05 12:11:06 +000012455 mkexpr( xB ) ), mkU64( 0 ) ) );
12456 break;
12457 case 0x0b0: // xscvdpsxws (VSX Scalar truncate Double-Precision to integer and
12458 // Convert to Signed Integer Word format with Saturate)
12459 DIP("xscvdpsxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12460 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012461 binop( Iop_64HLtoV128,
12462 unop( Iop_32Sto64,
12463 binop( Iop_F64toI32S,
12464 mkU32( Irrm_ZERO ),
sewardje71e56a2011-09-05 12:11:06 +000012465 mkexpr( xB ) ) ),
12466 mkU64( 0ULL ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000012467 break;
sewardje71e56a2011-09-05 12:11:06 +000012468 case 0x290: // xscvdpuxds (VSX Scalar truncate Double-Precision integer and Convert
12469 // to Unsigned Integer Doubleword format with Saturate)
12470 DIP("xscvdpuxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12471 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012472 binop( Iop_64HLtoV128,
12473 binop( Iop_F64toI64U,
12474 mkU32( Irrm_ZERO ),
sewardje71e56a2011-09-05 12:11:06 +000012475 mkexpr( xB ) ),
12476 mkU64( 0ULL ) ) );
12477 break;
carll6c758b62013-10-03 21:38:45 +000012478 case 0x270:
12479 // xscvsxdsp (VSX Scalar Convert and round Signed Integer Doubleword
12480 // to Single-Precision format)
12481 DIP("xscvsxdsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12482 putVSReg( XT,
12483 binop( Iop_64HLtoV128,
12484 unop( Iop_ReinterpF64asI64,
12485 binop( Iop_RoundF64toF32,
12486 get_IR_roundingmode(),
12487 binop( Iop_I64StoF64,
12488 get_IR_roundingmode(),
12489 mkexpr( xB ) ) ) ),
12490 mkU64( 0 ) ) );
12491 break;
sewardje71e56a2011-09-05 12:11:06 +000012492 case 0x2F0:
12493 // xscvsxddp (VSX Scalar Convert and round Signed Integer Doubleword to
12494 // Double-Precision format)
12495 DIP("xscvsxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12496 putVSReg( XT,
sewardj66d5ef22011-04-15 11:55:00 +000012497 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
sewardj4aa412a2011-07-24 14:13:21 +000012498 binop( Iop_I64StoF64, get_IR_roundingmode(),
sewardje71e56a2011-09-05 12:11:06 +000012499 mkexpr( xB ) ) ),
12500 mkU64( 0 ) ) );
12501 break;
carll6c758b62013-10-03 21:38:45 +000012502 case 0x250:
12503 // xscvuxdsp (VSX Scalar Convert and round Unsigned Integer
12504 // Doubleword to Singel-Precision format)
12505 DIP("xscvuxdsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12506 putVSReg( XT,
12507 binop( Iop_64HLtoV128,
12508 unop( Iop_ReinterpF64asI64,
12509 binop( Iop_RoundF64toF32,
12510 get_IR_roundingmode(),
12511 binop( Iop_I64UtoF64,
12512 get_IR_roundingmode(),
12513 mkexpr( xB ) ) ) ),
12514 mkU64( 0 ) ) );
12515 break;
sewardje71e56a2011-09-05 12:11:06 +000012516 case 0x2D0:
12517 // xscvuxddp (VSX Scalar Convert and round Unsigned Integer Doubleword to
12518 // Double-Precision format)
12519 DIP("xscvuxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12520 putVSReg( XT,
sewardj66d5ef22011-04-15 11:55:00 +000012521 binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
sewardj4aa412a2011-07-24 14:13:21 +000012522 binop( Iop_I64UtoF64, get_IR_roundingmode(),
sewardje71e56a2011-09-05 12:11:06 +000012523 mkexpr( xB ) ) ),
12524 mkU64( 0 ) ) );
12525 break;
12526 case 0x1b0: // xvcvdpsxws (VSX Vector truncate Double-Precision to integer and Convert
12527 // to Signed Integer Word format with Saturate)
12528 {
12529 IRTemp hiResult_32 = newTemp(Ity_I32);
12530 IRTemp loResult_32 = newTemp(Ity_I32);
12531 IRExpr* rmZero = mkU32(Irrm_ZERO);
sewardj66d5ef22011-04-15 11:55:00 +000012532
sewardje71e56a2011-09-05 12:11:06 +000012533 DIP("xvcvdpsxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12534 assign(hiResult_32, binop(Iop_F64toI32S, rmZero, mkexpr(xB)));
12535 assign(loResult_32, binop(Iop_F64toI32S, rmZero, mkexpr(xB2)));
12536 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012537 binop( Iop_64HLtoV128,
12538 unop( Iop_32Sto64, mkexpr( hiResult_32 ) ),
12539 unop( Iop_32Sto64, mkexpr( loResult_32 ) ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012540 break;
12541 }
12542 case 0x130: case 0x110: // xvcvspsxws, xvcvspuxws
12543 // (VSX Vector truncate Single-Precision to integer and
12544 // Convert to [Un]signed Integer Word format with Saturate)
12545 {
12546 IRExpr * b0_result, * b1_result, * b2_result, * b3_result;
12547 IRTemp tempResult = newTemp(Ity_V128);
12548 IRTemp res0 = newTemp(Ity_I32);
12549 IRTemp res1 = newTemp(Ity_I32);
12550 IRTemp res2 = newTemp(Ity_I32);
12551 IRTemp res3 = newTemp(Ity_I32);
12552 IRTemp hi64 = newTemp(Ity_I64);
12553 IRTemp lo64 = newTemp(Ity_I64);
12554 Bool un_signed = (opc2 == 0x110);
12555 IROp op = un_signed ? Iop_QFtoI32Ux4_RZ : Iop_QFtoI32Sx4_RZ;
sewardj4aa412a2011-07-24 14:13:21 +000012556
sewardje71e56a2011-09-05 12:11:06 +000012557 DIP("xvcvsp%sxws v%u,v%u\n", un_signed ? "u" : "s", (UInt)XT, (UInt)XB);
12558 /* The xvcvsp{s|u}xws instruction is similar to vct{s|u}xs, except if src is a NaN,
12559 * then result is set to 0x80000000. */
12560 assign(tempResult, unop(op, getVSReg(XB)));
12561 assign( hi64, unop(Iop_V128HIto64, mkexpr(tempResult)) );
12562 assign( lo64, unop(Iop_V128to64, mkexpr(tempResult)) );
12563 assign( res3, unop(Iop_64HIto32, mkexpr(hi64)) );
12564 assign( res2, unop(Iop_64to32, mkexpr(hi64)) );
12565 assign( res1, unop(Iop_64HIto32, mkexpr(lo64)) );
12566 assign( res0, unop(Iop_64to32, mkexpr(lo64)) );
sewardj4aa412a2011-07-24 14:13:21 +000012567
florian99dd03e2013-01-29 03:56:06 +000012568 b3_result = IRExpr_ITE(is_NaN_32(b3),
12569 // then: result is 0x{8|0}80000000
12570 mkU32(un_signed ? 0x00000000 : 0x80000000),
12571 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12572 mkexpr(res3));
12573 b2_result = IRExpr_ITE(is_NaN_32(b2),
12574 // then: result is 0x{8|0}80000000
12575 mkU32(un_signed ? 0x00000000 : 0x80000000),
12576 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12577 mkexpr(res2));
12578 b1_result = IRExpr_ITE(is_NaN_32(b1),
12579 // then: result is 0x{8|0}80000000
12580 mkU32(un_signed ? 0x00000000 : 0x80000000),
12581 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12582 mkexpr(res1));
12583 b0_result = IRExpr_ITE(is_NaN_32(b0),
12584 // then: result is 0x{8|0}80000000
12585 mkU32(un_signed ? 0x00000000 : 0x80000000),
12586 // else: result is from the Iop_QFtoI32{s|u}x4_RZ
12587 mkexpr(res0));
sewardj4aa412a2011-07-24 14:13:21 +000012588
sewardje71e56a2011-09-05 12:11:06 +000012589 putVSReg( XT,
sewardj4aa412a2011-07-24 14:13:21 +000012590 binop( Iop_64HLtoV128,
12591 binop( Iop_32HLto64, b3_result, b2_result ),
12592 binop( Iop_32HLto64, b1_result, b0_result ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012593 break;
12594 }
12595 case 0x212: // xscvdpsp (VSX Scalar round Double-Precision to single-precision and
12596 // Convert to Single-Precision format
12597 DIP("xscvdpsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12598 putVSReg( XT,
12599 binop( Iop_64HLtoV128,
12600 binop( Iop_32HLto64,
12601 unop( Iop_ReinterpF32asI32,
12602 unop( Iop_TruncF64asF32,
12603 binop( Iop_RoundF64toF32,
12604 get_IR_roundingmode(),
12605 mkexpr( xB ) ) ) ),
12606 mkU32( 0 ) ),
12607 mkU64( 0ULL ) ) );
12608 break;
carll0c74bb52013-08-12 18:01:40 +000012609 case 0x216: /* xscvdpspn (VSX Scalar convert scalar Single-Precision to
carll6c758b62013-10-03 21:38:45 +000012610 vector Single-Precision non-signalling */
carll0c74bb52013-08-12 18:01:40 +000012611 DIP("xscvdpspn v%u,v%u\n", (UInt)XT, (UInt)XB);
12612 putVSReg( XT,
12613 binop( Iop_64HLtoV128,
12614 binop( Iop_32HLto64,
12615 unop( Iop_ReinterpF32asI32,
12616 unop( Iop_TruncF64asF32,
12617 mkexpr( xB ) ) ),
carll6c758b62013-10-03 21:38:45 +000012618 mkU32( 0 ) ),
12619 mkU64( 0ULL ) ) );
carll0c74bb52013-08-12 18:01:40 +000012620 break;
sewardje71e56a2011-09-05 12:11:06 +000012621 case 0x090: // xscvdpuxws (VSX Scalar truncate Double-Precision to integer
12622 // and Convert to Unsigned Integer Word format with Saturate)
12623 DIP("xscvdpuxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12624 putVSReg( XT,
12625 binop( Iop_64HLtoV128,
12626 binop( Iop_32HLto64,
12627 mkU32( 0 ),
12628 binop( Iop_F64toI32U,
12629 mkU32( Irrm_ZERO ),
12630 mkexpr( xB ) ) ),
12631 mkU64( 0ULL ) ) );
12632 break;
carll6c758b62013-10-03 21:38:45 +000012633 case 0x292: // xscvspdp (VSX Scalar Convert Single-Precision to Double-Precision format, signaling)
sewardje71e56a2011-09-05 12:11:06 +000012634 DIP("xscvspdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12635 putVSReg( XT,
12636 binop( Iop_64HLtoV128,
12637 unop( Iop_ReinterpF64asI64,
12638 unop( Iop_F32toF64,
12639 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
12640 mkU64( 0ULL ) ) );
12641 break;
carll0c74bb52013-08-12 18:01:40 +000012642 case 0x296: // xscvspdpn (VSX Scalar Convert Single-Precision to Double-Precision format Non signaling)
12643 DIP("xscvspdpn v%u,v%u\n", (UInt)XT, (UInt)XB);
12644 putVSReg( XT,
12645 binop( Iop_64HLtoV128,
12646 unop( Iop_ReinterpF64asI64,
12647 unop( Iop_F32toF64,
12648 unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
12649 mkU64( 0ULL ) ) );
12650 break;
sewardje71e56a2011-09-05 12:11:06 +000012651 case 0x312: // xvcvdpsp (VSX Vector round Double-Precision to single-precision
12652 // and Convert to Single-Precision format)
12653 DIP("xvcvdpsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12654 putVSReg( XT,
12655 binop( Iop_64HLtoV128,
12656 binop( Iop_32HLto64,
12657 unop( Iop_ReinterpF32asI32,
12658 unop( Iop_TruncF64asF32,
12659 binop( Iop_RoundF64toF32,
12660 get_IR_roundingmode(),
12661 mkexpr( xB ) ) ) ),
12662 mkU32( 0 ) ),
12663 binop( Iop_32HLto64,
12664 unop( Iop_ReinterpF32asI32,
12665 unop( Iop_TruncF64asF32,
12666 binop( Iop_RoundF64toF32,
12667 get_IR_roundingmode(),
12668 mkexpr( xB2 ) ) ) ),
12669 mkU32( 0 ) ) ) );
12670 break;
12671 case 0x390: // xvcvdpuxds (VSX Vector truncate Double-Precision to integer
12672 // and Convert to Unsigned Integer Doubleword format
12673 // with Saturate)
12674 DIP("xvcvdpuxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12675 putVSReg( XT,
12676 binop( Iop_64HLtoV128,
12677 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
12678 binop( Iop_F64toI64U, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
12679 break;
12680 case 0x190: // xvcvdpuxws (VSX Vector truncate Double-Precision to integer and
12681 // Convert to Unsigned Integer Word format with Saturate)
12682 DIP("xvcvdpuxws v%u,v%u\n", (UInt)XT, (UInt)XB);
12683 putVSReg( XT,
12684 binop( Iop_64HLtoV128,
12685 binop( Iop_32HLto64,
12686 binop( Iop_F64toI32U,
12687 mkU32( Irrm_ZERO ),
12688 mkexpr( xB ) ),
12689 mkU32( 0 ) ),
12690 binop( Iop_32HLto64,
12691 binop( Iop_F64toI32U,
12692 mkU32( Irrm_ZERO ),
12693 mkexpr( xB2 ) ),
12694 mkU32( 0 ) ) ) );
12695 break;
12696 case 0x392: // xvcvspdp (VSX Vector Convert Single-Precision to Double-Precision format)
12697 DIP("xvcvspdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12698 putVSReg( XT,
12699 binop( Iop_64HLtoV128,
12700 unop( Iop_ReinterpF64asI64,
12701 unop( Iop_F32toF64,
carll6fef87a2013-09-12 17:26:42 +000012702 unop( Iop_ReinterpI32asF32,
12703 handle_SNaN_to_QNaN_32( mkexpr( b3 ) ) ) ) ),
sewardje71e56a2011-09-05 12:11:06 +000012704 unop( Iop_ReinterpF64asI64,
12705 unop( Iop_F32toF64,
carll6fef87a2013-09-12 17:26:42 +000012706 unop( Iop_ReinterpI32asF32,
12707 handle_SNaN_to_QNaN_32( mkexpr( b1 ) ) ) ) ) ) );
sewardje71e56a2011-09-05 12:11:06 +000012708 break;
12709 case 0x330: // xvcvspsxds (VSX Vector truncate Single-Precision to integer and
12710 // Convert to Signed Integer Doubleword format with Saturate)
12711 DIP("xvcvspsxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12712 putVSReg( XT,
12713 binop( Iop_64HLtoV128,
12714 binop( Iop_F64toI64S,
12715 mkU32( Irrm_ZERO ),
12716 unop( Iop_F32toF64,
12717 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
12718 binop( Iop_F64toI64S,
12719 mkU32( Irrm_ZERO ),
12720 unop( Iop_F32toF64,
12721 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
12722 break;
12723 case 0x310: // xvcvspuxds (VSX Vector truncate Single-Precision to integer and
12724 // Convert to Unsigned Integer Doubleword format with Saturate)
12725 DIP("xvcvspuxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12726 putVSReg( XT,
12727 binop( Iop_64HLtoV128,
12728 binop( Iop_F64toI64U,
12729 mkU32( Irrm_ZERO ),
12730 unop( Iop_F32toF64,
12731 unop( Iop_ReinterpI32asF32, mkexpr( b3 ) ) ) ),
12732 binop( Iop_F64toI64U,
12733 mkU32( Irrm_ZERO ),
12734 unop( Iop_F32toF64,
12735 unop( Iop_ReinterpI32asF32, mkexpr( b1 ) ) ) ) ) );
12736 break;
12737 case 0x3B0: // xvcvdpsxds (VSX Vector truncate Double-Precision to integer and
12738 // Convert to Signed Integer Doubleword format with Saturate)
12739 DIP("xvcvdpsxds v%u,v%u\n", (UInt)XT, (UInt)XB);
12740 putVSReg( XT,
12741 binop( Iop_64HLtoV128,
12742 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB ) ),
12743 binop( Iop_F64toI64S, mkU32( Irrm_ZERO ), mkexpr( xB2 ) ) ) );
12744 break;
12745 case 0x3f0: // xvcvsxddp (VSX Vector Convert and round Signed Integer Doubleword
12746 // to Double-Precision format)
12747 DIP("xvcvsxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12748 putVSReg( XT,
12749 binop( Iop_64HLtoV128,
12750 unop( Iop_ReinterpF64asI64,
12751 binop( Iop_I64StoF64,
12752 get_IR_roundingmode(),
12753 mkexpr( xB ) ) ),
12754 unop( Iop_ReinterpF64asI64,
12755 binop( Iop_I64StoF64,
12756 get_IR_roundingmode(),
12757 mkexpr( xB2 ) ) ) ) );
12758 break;
12759 case 0x3d0: // xvcvuxddp (VSX Vector Convert and round Unsigned Integer Doubleword
12760 // to Double-Precision format)
12761 DIP("xvcvuxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12762 putVSReg( XT,
12763 binop( Iop_64HLtoV128,
12764 unop( Iop_ReinterpF64asI64,
12765 binop( Iop_I64UtoF64,
12766 get_IR_roundingmode(),
12767 mkexpr( xB ) ) ),
12768 unop( Iop_ReinterpF64asI64,
12769 binop( Iop_I64UtoF64,
12770 get_IR_roundingmode(),
12771 mkexpr( xB2 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000012772
sewardje71e56a2011-09-05 12:11:06 +000012773 break;
12774 case 0x370: // xvcvsxdsp (VSX Vector Convert and round Signed Integer Doubleword
12775 // to Single-Precision format)
12776 DIP("xvcvsxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12777 putVSReg( XT,
12778 binop( Iop_64HLtoV128,
12779 binop( Iop_32HLto64,
12780 unop( Iop_ReinterpF32asI32,
12781 unop( Iop_TruncF64asF32,
12782 binop( Iop_RoundF64toF32,
12783 get_IR_roundingmode(),
12784 binop( Iop_I64StoF64,
12785 get_IR_roundingmode(),
12786 mkexpr( xB ) ) ) ) ),
12787 mkU32( 0 ) ),
12788 binop( Iop_32HLto64,
12789 unop( Iop_ReinterpF32asI32,
12790 unop( Iop_TruncF64asF32,
12791 binop( Iop_RoundF64toF32,
12792 get_IR_roundingmode(),
12793 binop( Iop_I64StoF64,
12794 get_IR_roundingmode(),
12795 mkexpr( xB2 ) ) ) ) ),
12796 mkU32( 0 ) ) ) );
12797 break;
12798 case 0x350: // xvcvuxdsp (VSX Vector Convert and round Unsigned Integer Doubleword
12799 // to Single-Precision format)
12800 DIP("xvcvuxddp v%u,v%u\n", (UInt)XT, (UInt)XB);
12801 putVSReg( XT,
12802 binop( Iop_64HLtoV128,
12803 binop( Iop_32HLto64,
12804 unop( Iop_ReinterpF32asI32,
12805 unop( Iop_TruncF64asF32,
12806 binop( Iop_RoundF64toF32,
12807 get_IR_roundingmode(),
12808 binop( Iop_I64UtoF64,
12809 get_IR_roundingmode(),
12810 mkexpr( xB ) ) ) ) ),
12811 mkU32( 0 ) ),
12812 binop( Iop_32HLto64,
12813 unop( Iop_ReinterpF32asI32,
12814 unop( Iop_TruncF64asF32,
12815 binop( Iop_RoundF64toF32,
12816 get_IR_roundingmode(),
12817 binop( Iop_I64UtoF64,
12818 get_IR_roundingmode(),
12819 mkexpr( xB2 ) ) ) ) ),
12820 mkU32( 0 ) ) ) );
12821 break;
12822
12823 case 0x1f0: // xvcvsxwdp (VSX Vector Convert Signed Integer Word to Double-Precision format)
12824 DIP("xvcvsxwdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12825 putVSReg( XT,
12826 binop( Iop_64HLtoV128,
12827 unop( Iop_ReinterpF64asI64,
12828 binop( Iop_I64StoF64, get_IR_roundingmode(),
12829 unop( Iop_32Sto64, mkexpr( b3 ) ) ) ),
12830 unop( Iop_ReinterpF64asI64,
12831 binop( Iop_I64StoF64, get_IR_roundingmode(),
12832 unop( Iop_32Sto64, mkexpr( b1 ) ) ) ) ) );
12833 break;
12834 case 0x1d0: // xvcvuxwdp (VSX Vector Convert Unsigned Integer Word to Double-Precision format)
12835 DIP("xvcvuxwdp v%u,v%u\n", (UInt)XT, (UInt)XB);
12836 putVSReg( XT,
12837 binop( Iop_64HLtoV128,
12838 unop( Iop_ReinterpF64asI64,
12839 binop( Iop_I64UtoF64, get_IR_roundingmode(),
12840 unop( Iop_32Uto64, mkexpr( b3 ) ) ) ),
12841 unop( Iop_ReinterpF64asI64,
12842 binop( Iop_I64UtoF64, get_IR_roundingmode(),
12843 unop( Iop_32Uto64, mkexpr( b1 ) ) ) ) ) );
12844 break;
12845 case 0x170: // xvcvsxwsp (VSX Vector Convert Signed Integer Word to Single-Precision format)
12846 DIP("xvcvsxwsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12847 putVSReg( XT, unop( Iop_I32StoFx4, getVSReg( XB ) ) );
12848 break;
12849 case 0x150: // xvcvuxwsp (VSX Vector Convert Unsigned Integer Word to Single-Precision format)
12850 DIP("xvcvuxwsp v%u,v%u\n", (UInt)XT, (UInt)XB);
12851 putVSReg( XT, unop( Iop_I32UtoFx4, getVSReg( XB ) ) );
12852 break;
12853
12854 default:
12855 vex_printf( "dis_vx_conv(ppc)(opc2)\n" );
12856 return False;
sewardj66d5ef22011-04-15 11:55:00 +000012857 }
12858 return True;
12859}
12860
12861/*
sewardj4aa412a2011-07-24 14:13:21 +000012862 * VSX vector Double Precision Floating Point Arithmetic Instructions
12863 */
12864static Bool
12865dis_vxv_dp_arith ( UInt theInstr, UInt opc2 )
12866{
12867 /* XX3-Form */
12868 UChar opc1 = ifieldOPC( theInstr );
12869 UChar XT = ifieldRegXT( theInstr );
12870 UChar XA = ifieldRegXA( theInstr );
12871 UChar XB = ifieldRegXB( theInstr );
12872 IRExpr* rm = get_IR_roundingmode();
12873 IRTemp frA = newTemp(Ity_F64);
12874 IRTemp frB = newTemp(Ity_F64);
12875 IRTemp frA2 = newTemp(Ity_F64);
12876 IRTemp frB2 = newTemp(Ity_F64);
12877
12878 if (opc1 != 0x3C) {
12879 vex_printf( "dis_vxv_dp_arith(ppc)(instr)\n" );
12880 return False;
12881 }
12882
12883 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
12884 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
12885 assign(frA2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XA ))));
12886 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XB ))));
12887
12888 switch (opc2) {
12889 case 0x1E0: // xvdivdp (VSX Vector Divide Double-Precision)
12890 case 0x1C0: // xvmuldp (VSX Vector Multiply Double-Precision)
12891 case 0x180: // xvadddp (VSX Vector Add Double-Precision)
12892 case 0x1A0: // xvsubdp (VSX Vector Subtract Double-Precision)
12893 {
12894 IROp mOp;
florian55085f82012-11-21 00:36:55 +000012895 const HChar * oper_name;
sewardj4aa412a2011-07-24 14:13:21 +000012896 switch (opc2) {
12897 case 0x1E0:
12898 mOp = Iop_DivF64;
12899 oper_name = "div";
12900 break;
12901 case 0x1C0:
12902 mOp = Iop_MulF64;
12903 oper_name = "mul";
12904 break;
12905 case 0x180:
12906 mOp = Iop_AddF64;
12907 oper_name = "add";
12908 break;
12909 case 0x1A0:
12910 mOp = Iop_SubF64;
12911 oper_name = "sub";
12912 break;
12913
12914 default:
12915 vpanic("The impossible happened: dis_vxv_dp_arith(ppc)");
12916 }
12917 IRTemp hiResult = newTemp(Ity_I64);
12918 IRTemp loResult = newTemp(Ity_I64);
12919 DIP("xv%sdp v%d,v%d,v%d\n", oper_name, (UInt)XT, (UInt)XA, (UInt)XB);
12920
12921 assign( hiResult,
12922 unop( Iop_ReinterpF64asI64,
12923 triop( mOp, rm, mkexpr( frA ), mkexpr( frB ) ) ) );
12924 assign( loResult,
12925 unop( Iop_ReinterpF64asI64,
12926 triop( mOp, rm, mkexpr( frA2 ), mkexpr( frB2 ) ) ) );
12927 putVSReg( XT,
12928 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
12929 break;
12930 }
sewardje71e56a2011-09-05 12:11:06 +000012931 case 0x196: // xvsqrtdp
12932 {
12933 IRTemp hiResult = newTemp(Ity_I64);
12934 IRTemp loResult = newTemp(Ity_I64);
12935 DIP("xvsqrtdp v%d,v%d\n", (UInt)XT, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000012936
sewardje71e56a2011-09-05 12:11:06 +000012937 assign( hiResult,
12938 unop( Iop_ReinterpF64asI64,
12939 binop( Iop_SqrtF64, rm, mkexpr( frB ) ) ) );
12940 assign( loResult,
12941 unop( Iop_ReinterpF64asI64,
12942 binop( Iop_SqrtF64, rm, mkexpr( frB2 ) ) ) );
12943 putVSReg( XT,
12944 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
12945 break;
12946 }
sewardj4aa412a2011-07-24 14:13:21 +000012947 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp (VSX Vector Multiply-Add Double-Precision)
12948 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp (VSX Vector Multiply-Subtract Double-Precision)
12949 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp (VSX Vector Negate Multiply-Add Double-Precision)
12950 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp (VSX Vector Negate Multiply-Subtract Double-Precision)
12951 {
12952 /* xvm{add|sub}mdp XT,XA,XB is element-wise equivalent to fm{add|sub} FRT,FRA,FRC,FRB with . . .
12953 * XT == FRC
12954 * XA == FRA
12955 * XB == FRB
12956 *
12957 * and for xvm{add|sub}adp . . .
12958 * XT == FRB
12959 * XA == FRA
12960 * XB == FRC
12961 */
12962 Bool negate;
12963 IROp mOp = Iop_INVALID;
florian55085f82012-11-21 00:36:55 +000012964 const HChar * oper_name = NULL;
sewardj4aa412a2011-07-24 14:13:21 +000012965 Bool mdp = False;
12966
12967 switch (opc2) {
12968 case 0x184: case 0x1A4:
12969 case 0x384: case 0x3A4:
12970 mOp = Iop_MAddF64;
12971 oper_name = "add";
12972 mdp = (opc2 & 0x0FF) == 0x0A4;
12973 break;
12974
12975 case 0x1C4: case 0x1E4:
12976 case 0x3C4: case 0x3E4:
12977 mOp = Iop_MSubF64;
12978 oper_name = "sub";
12979 mdp = (opc2 & 0x0FF) == 0x0E4;
12980 break;
12981
12982 default:
12983 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
12984 }
12985
12986 switch (opc2) {
12987 case 0x384: case 0x3A4:
12988 case 0x3C4: case 0x3E4:
12989 negate = True;
12990 break;
12991 default:
12992 negate = False;
12993 }
12994 IRTemp hiResult = newTemp(Ity_I64);
12995 IRTemp loResult = newTemp(Ity_I64);
12996 IRTemp frT = newTemp(Ity_F64);
12997 IRTemp frT2 = newTemp(Ity_F64);
12998 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name, mdp ? "mdp" : "adp",
12999 (UInt)XT, (UInt)XA, (UInt)XB);
13000 assign(frT, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XT ) ) ) );
13001 assign(frT2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg( XT ) ) ) );
13002
13003 assign( hiResult,
13004 unop( Iop_ReinterpF64asI64,
13005 qop( mOp,
13006 rm,
13007 mkexpr( frA ),
13008 mkexpr( mdp ? frT : frB ),
13009 mkexpr( mdp ? frB : frT ) ) ) );
13010 assign( loResult,
13011 unop( Iop_ReinterpF64asI64,
13012 qop( mOp,
13013 rm,
13014 mkexpr( frA2 ),
13015 mkexpr( mdp ? frT2 : frB2 ),
13016 mkexpr( mdp ? frB2 : frT2 ) ) ) );
13017 putVSReg( XT,
13018 binop( Iop_64HLtoV128,
13019 mkexpr( negate ? getNegatedResult( hiResult )
13020 : hiResult ),
13021 mkexpr( negate ? getNegatedResult( loResult )
13022 : loResult ) ) );
13023 break;
13024 }
sewardje71e56a2011-09-05 12:11:06 +000013025 case 0x1D4: // xvtsqrtdp (VSX Vector Test for software Square Root Double-Precision)
13026 {
13027 IRTemp frBHi_I64 = newTemp(Ity_I64);
13028 IRTemp frBLo_I64 = newTemp(Ity_I64);
13029 IRTemp flagsHi = newTemp(Ity_I32);
13030 IRTemp flagsLo = newTemp(Ity_I32);
13031 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13032 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
13033 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
13034
13035 DIP("xvtsqrtdp cr%d,v%d\n", (UInt)crfD, (UInt)XB);
13036 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
13037 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
13038 do_fp_tsqrt(frBHi_I64, False /*not single precision*/, &fe_flagHi, &fg_flagHi);
13039 do_fp_tsqrt(frBLo_I64, False /*not single precision*/, &fe_flagLo, &fg_flagLo);
13040 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13041 * where fl_flag == 1 on ppc64.
13042 */
13043 assign( flagsHi,
13044 binop( Iop_Or32,
13045 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13046 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
13047 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
13048 assign( flagsLo,
13049 binop( Iop_Or32,
13050 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13051 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
13052 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
13053 putGST_field( PPC_GST_CR,
13054 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
13055 crfD );
13056 break;
13057 }
13058 case 0x1F4: // xvtdivdp (VSX Vector Test for software Divide Double-Precision)
13059 {
13060 IRTemp frBHi_I64 = newTemp(Ity_I64);
13061 IRTemp frBLo_I64 = newTemp(Ity_I64);
13062 IRTemp frAHi_I64 = newTemp(Ity_I64);
13063 IRTemp frALo_I64 = newTemp(Ity_I64);
13064 IRTemp flagsHi = newTemp(Ity_I32);
13065 IRTemp flagsLo = newTemp(Ity_I32);
13066 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13067 IRTemp fe_flagHi, fg_flagHi, fe_flagLo, fg_flagLo;
13068 fe_flagHi = fg_flagHi = fe_flagLo = fg_flagLo = IRTemp_INVALID;
13069
13070 DIP("xvtdivdp cr%d,v%d,v%d\n", (UInt)crfD, (UInt)XA, (UInt)XB);
13071 assign( frAHi_I64, unop(Iop_V128HIto64, getVSReg( XA )) );
13072 assign( frALo_I64, unop(Iop_V128to64, getVSReg( XA )) );
13073 assign( frBHi_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
13074 assign( frBLo_I64, unop(Iop_V128to64, getVSReg( XB )) );
13075
13076 _do_fp_tdiv(frAHi_I64, frBHi_I64, False/*dp*/, &fe_flagHi, &fg_flagHi);
13077 _do_fp_tdiv(frALo_I64, frBLo_I64, False/*dp*/, &fe_flagLo, &fg_flagLo);
13078 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13079 * where fl_flag == 1 on ppc64.
13080 */
13081 assign( flagsHi,
13082 binop( Iop_Or32,
13083 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13084 binop( Iop_Shl32, mkexpr(fg_flagHi), mkU8( 2 ) ) ),
13085 binop( Iop_Shl32, mkexpr(fe_flagHi), mkU8( 1 ) ) ) );
13086 assign( flagsLo,
13087 binop( Iop_Or32,
13088 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13089 binop( Iop_Shl32, mkexpr(fg_flagLo), mkU8( 2 ) ) ),
13090 binop( Iop_Shl32, mkexpr(fe_flagLo), mkU8( 1 ) ) ) );
13091 putGST_field( PPC_GST_CR,
13092 binop( Iop_Or32, mkexpr( flagsHi ), mkexpr( flagsLo ) ),
13093 crfD );
13094 break;
13095 }
sewardj4aa412a2011-07-24 14:13:21 +000013096
13097 default:
13098 vex_printf( "dis_vxv_dp_arith(ppc)(opc2)\n" );
13099 return False;
13100 }
13101 return True;
13102}
13103
13104/*
13105 * VSX vector Single Precision Floating Point Arithmetic Instructions
13106 */
13107static Bool
13108dis_vxv_sp_arith ( UInt theInstr, UInt opc2 )
13109{
13110 /* XX3-Form */
13111 UChar opc1 = ifieldOPC( theInstr );
13112 UChar XT = ifieldRegXT( theInstr );
13113 UChar XA = ifieldRegXA( theInstr );
13114 UChar XB = ifieldRegXB( theInstr );
13115 IRExpr* rm = get_IR_roundingmode();
13116 IRTemp a3, a2, a1, a0;
13117 IRTemp b3, b2, b1, b0;
13118 IRTemp res0 = newTemp(Ity_I32);
13119 IRTemp res1 = newTemp(Ity_I32);
13120 IRTemp res2 = newTemp(Ity_I32);
13121 IRTemp res3 = newTemp(Ity_I32);
13122
13123 a3 = a2 = a1 = a0 = IRTemp_INVALID;
13124 b3 = b2 = b1 = b0 = IRTemp_INVALID;
13125
13126 if (opc1 != 0x3C) {
13127 vex_printf( "dis_vxv_sp_arith(ppc)(instr)\n" );
13128 return False;
13129 }
13130
13131 switch (opc2) {
13132 case 0x100: // xvaddsp (VSX Vector Add Single-Precision)
13133 DIP("xvaddsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
sewardj20a760e2014-05-05 10:03:56 +000013134 // WARNING: BOGUS! The backend ignores rm on Iop_Add32Fx4
13135 putVSReg( XT, triop(Iop_Add32Fx4, rm,
13136 getVSReg( XA ), getVSReg( XB )) );
sewardj4aa412a2011-07-24 14:13:21 +000013137 break;
13138
13139 case 0x140: // xvmulsp (VSX Vector Multiply Single-Precision)
13140 DIP("xvmulsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
sewardj20a760e2014-05-05 10:03:56 +000013141 // WARNING: BOGUS! The backend ignores rm on Iop_Mul32Fx4
13142 putVSReg( XT, triop(Iop_Mul32Fx4, rm,
13143 getVSReg( XA ), getVSReg( XB )) );
sewardj4aa412a2011-07-24 14:13:21 +000013144 break;
13145
13146 case 0x120: // xvsubsp (VSX Vector Subtract Single-Precision)
13147 DIP("xvsubsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
sewardj20a760e2014-05-05 10:03:56 +000013148 // WARNING: BOGUS! The backend ignores rm on Iop_Sub32Fx4
13149 putVSReg( XT, triop(Iop_Sub32Fx4, rm,
13150 getVSReg( XA ), getVSReg( XB )) );
sewardj4aa412a2011-07-24 14:13:21 +000013151 break;
13152
13153 case 0x160: // xvdivsp (VSX Vector Divide Single-Precision)
13154 {
13155 /* Iop_Div32Fx4 is not implemented for ppc64 (in host_ppc_{isel|defs}.c.
13156 * So there are two choices:
13157 * 1. Implement the xvdivsp with a native insn; or
13158 * 2. Extract the 4 single precision floats from each vector
13159 * register inputs and perform fdivs on each pair
13160 * I will do the latter, due to the general philosophy of
13161 * reusing existing implementations when practical.
13162 */
13163 DIP("xvdivsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
13164 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
13165 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13166
13167 assign( res0,
13168 unop( Iop_ReinterpF32asI32,
13169 unop( Iop_TruncF64asF32,
13170 triop( Iop_DivF64r32, rm, mkexpr( a0 ), mkexpr( b0 ) ) ) ) );
13171 assign( res1,
13172 unop( Iop_ReinterpF32asI32,
13173 unop( Iop_TruncF64asF32,
13174 triop( Iop_DivF64r32, rm, mkexpr( a1 ), mkexpr( b1 ) ) ) ) );
13175 assign( res2,
13176 unop( Iop_ReinterpF32asI32,
13177 unop( Iop_TruncF64asF32,
13178 triop( Iop_DivF64r32, rm, mkexpr( a2 ), mkexpr( b2 ) ) ) ) );
13179 assign( res3,
13180 unop( Iop_ReinterpF32asI32,
13181 unop( Iop_TruncF64asF32,
13182 triop( Iop_DivF64r32, rm, mkexpr( a3 ), mkexpr( b3 ) ) ) ) );
13183
13184 putVSReg( XT,
13185 binop( Iop_64HLtoV128,
13186 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
13187 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
13188 break;
13189 }
sewardje71e56a2011-09-05 12:11:06 +000013190 case 0x116: // xvsqrtsp (VSX Vector Square Root Single-Precision)
13191 {
13192 DIP("xvsqrtsp v%d,v%d\n", (UInt)XT, (UInt)XB);
13193 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13194 /* Note: The native xvsqrtsp insruction does not always give the same precision
13195 * as what we get with Iop_SqrtF64. But it doesn't seem worthwhile to implement
13196 * an Iop_SqrtF32 that would give us a lower precision result, albeit more true
13197 * to the actual instruction.
13198 */
13199
13200 assign( res0,
13201 unop( Iop_ReinterpF32asI32,
13202 unop( Iop_TruncF64asF32,
13203 binop(Iop_SqrtF64, rm, mkexpr( b0 ) ) ) ) );
13204 assign( res1,
13205 unop( Iop_ReinterpF32asI32,
13206 unop( Iop_TruncF64asF32,
13207 binop(Iop_SqrtF64, rm, mkexpr( b1 ) ) ) ) );
13208 assign( res2,
13209 unop( Iop_ReinterpF32asI32,
13210 unop( Iop_TruncF64asF32,
13211 binop(Iop_SqrtF64, rm, mkexpr( b2) ) ) ) );
13212 assign( res3,
13213 unop( Iop_ReinterpF32asI32,
13214 unop( Iop_TruncF64asF32,
13215 binop(Iop_SqrtF64, rm, mkexpr( b3 ) ) ) ) );
13216
13217 putVSReg( XT,
13218 binop( Iop_64HLtoV128,
13219 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
13220 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
13221 break;
13222 }
sewardj4aa412a2011-07-24 14:13:21 +000013223
13224 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp (VSX Vector Multiply-Add Single-Precision)
13225 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp (VSX Vector Multiply-Subtract Single-Precision)
13226 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp (VSX Vector Negate Multiply-Add Single-Precision)
13227 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp (VSX Vector Negate Multiply-Subtract Single-Precision)
13228 {
13229 IRTemp t3, t2, t1, t0;
13230 Bool msp = False;
13231 Bool negate;
florian55085f82012-11-21 00:36:55 +000013232 const HChar * oper_name = NULL;
sewardj4aa412a2011-07-24 14:13:21 +000013233 IROp mOp = Iop_INVALID;
13234 switch (opc2) {
13235 case 0x104: case 0x124:
13236 case 0x304: case 0x324:
13237 msp = (opc2 & 0x0FF) == 0x024;
13238 mOp = Iop_MAddF64r32;
13239 oper_name = "madd";
13240 break;
13241
13242 case 0x144: case 0x164:
13243 case 0x344: case 0x364:
13244 msp = (opc2 & 0x0FF) == 0x064;
13245 mOp = Iop_MSubF64r32;
13246 oper_name = "sub";
13247 break;
13248
13249 default:
13250 vpanic("The impossible happened: dis_vxv_sp_arith(ppc)");
13251 }
13252
13253 switch (opc2) {
13254 case 0x304: case 0x324:
13255 case 0x344: case 0x364:
13256 negate = True;
13257 break;
13258
13259 default:
13260 negate = False;
13261 }
13262
13263 DIP("xv%sm%s%s v%d,v%d,v%d\n", negate ? "n" : "", oper_name, msp ? "msp" : "asp",
13264 (UInt)XT, (UInt)XA, (UInt)XB);
13265
13266 t3 = t2 = t1 = t0 = IRTemp_INVALID;
13267 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
13268 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13269 breakV128to4xF64( getVSReg( XT ), &t3, &t2, &t1, &t0 );
13270
13271 assign( res0,
13272 unop( Iop_ReinterpF32asI32,
13273 unop( Iop_TruncF64asF32,
13274 qop( mOp,
13275 rm,
13276 mkexpr( a0 ),
13277 mkexpr( msp ? t0 : b0 ),
13278 mkexpr( msp ? b0 : t0 ) ) ) ) );
13279 assign( res1,
13280 unop( Iop_ReinterpF32asI32,
13281 unop( Iop_TruncF64asF32,
13282 qop( mOp,
13283 rm,
13284 mkexpr( a1 ),
13285 mkexpr( msp ? t1 : b1 ),
13286 mkexpr( msp ? b1 : t1 ) ) ) ) );
13287 assign( res2,
13288 unop( Iop_ReinterpF32asI32,
13289 unop( Iop_TruncF64asF32,
13290 qop( mOp,
13291 rm,
13292 mkexpr( a2 ),
13293 mkexpr( msp ? t2 : b2 ),
13294 mkexpr( msp ? b2 : t2 ) ) ) ) );
13295 assign( res3,
13296 unop( Iop_ReinterpF32asI32,
13297 unop( Iop_TruncF64asF32,
13298 qop( mOp,
13299 rm,
13300 mkexpr( a3 ),
13301 mkexpr( msp ? t3 : b3 ),
13302 mkexpr( msp ? b3 : t3 ) ) ) ) );
13303
13304 putVSReg( XT,
13305 binop( Iop_64HLtoV128,
13306 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res3 ) : res3 ),
13307 mkexpr( negate ? getNegatedResult_32( res2 ) : res2 ) ),
13308 binop( Iop_32HLto64, mkexpr( negate ? getNegatedResult_32( res1 ) : res1 ),
13309 mkexpr( negate ? getNegatedResult_32( res0 ) : res0 ) ) ) );
13310
13311 break;
13312 }
sewardje71e56a2011-09-05 12:11:06 +000013313 case 0x154: // xvtsqrtsp (VSX Vector Test for software Square Root Single-Precision)
13314 {
13315 IRTemp flags0 = newTemp(Ity_I32);
13316 IRTemp flags1 = newTemp(Ity_I32);
13317 IRTemp flags2 = newTemp(Ity_I32);
13318 IRTemp flags3 = newTemp(Ity_I32);
13319 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13320 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
13321 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
13322 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
13323 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
13324 DIP("xvtsqrtsp cr%d,v%d\n", (UInt)crfD, (UInt)XB);
13325
13326 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13327 do_fp_tsqrt(b0, True /* single precision*/, &fe_flag0, &fg_flag0);
13328 do_fp_tsqrt(b1, True /* single precision*/, &fe_flag1, &fg_flag1);
13329 do_fp_tsqrt(b2, True /* single precision*/, &fe_flag2, &fg_flag2);
13330 do_fp_tsqrt(b3, True /* single precision*/, &fe_flag3, &fg_flag3);
13331
13332 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13333 * where fl_flag == 1 on ppc64.
13334 */
13335 assign( flags0,
13336 binop( Iop_Or32,
13337 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13338 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
13339 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
13340 assign( flags1,
13341 binop( Iop_Or32,
13342 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13343 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
13344 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
13345 assign( flags2,
13346 binop( Iop_Or32,
13347 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13348 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
13349 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
13350 assign( flags3,
13351 binop( Iop_Or32,
13352 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13353 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
13354 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
13355 putGST_field( PPC_GST_CR,
13356 binop( Iop_Or32,
13357 mkexpr( flags0 ),
13358 binop( Iop_Or32,
13359 mkexpr( flags1 ),
13360 binop( Iop_Or32,
13361 mkexpr( flags2 ),
13362 mkexpr( flags3 ) ) ) ),
13363 crfD );
13364
13365 break;
13366 }
13367 case 0x174: // xvtdivsp (VSX Vector Test for software Divide Single-Precision)
13368 {
13369 IRTemp flags0 = newTemp(Ity_I32);
13370 IRTemp flags1 = newTemp(Ity_I32);
13371 IRTemp flags2 = newTemp(Ity_I32);
13372 IRTemp flags3 = newTemp(Ity_I32);
13373 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
13374 IRTemp fe_flag0, fg_flag0, fe_flag1, fg_flag1;
13375 IRTemp fe_flag2, fg_flag2, fe_flag3, fg_flag3;
13376 fe_flag0 = fg_flag0 = fe_flag1 = fg_flag1 = IRTemp_INVALID;
13377 fe_flag2 = fg_flag2 = fe_flag3 = fg_flag3 = IRTemp_INVALID;
13378 DIP("xvtdivsp cr%d,v%d,v%d\n", (UInt)crfD, (UInt)XA, (UInt)XB);
13379
13380 breakV128to4x32( getVSReg( XA ), &a3, &a2, &a1, &a0 );
13381 breakV128to4x32( getVSReg( XB ), &b3, &b2, &b1, &b0 );
13382 _do_fp_tdiv(a0, b0, True /* single precision*/, &fe_flag0, &fg_flag0);
13383 _do_fp_tdiv(a1, b1, True /* single precision*/, &fe_flag1, &fg_flag1);
13384 _do_fp_tdiv(a2, b2, True /* single precision*/, &fe_flag2, &fg_flag2);
13385 _do_fp_tdiv(a3, b3, True /* single precision*/, &fe_flag3, &fg_flag3);
13386
13387 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
13388 * where fl_flag == 1 on ppc64.
13389 */
13390 assign( flags0,
13391 binop( Iop_Or32,
13392 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13393 binop( Iop_Shl32, mkexpr(fg_flag0), mkU8( 2 ) ) ),
13394 binop( Iop_Shl32, mkexpr(fe_flag0), mkU8( 1 ) ) ) );
13395 assign( flags1,
13396 binop( Iop_Or32,
13397 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13398 binop( Iop_Shl32, mkexpr(fg_flag1), mkU8( 2 ) ) ),
13399 binop( Iop_Shl32, mkexpr(fe_flag1), mkU8( 1 ) ) ) );
13400 assign( flags2,
13401 binop( Iop_Or32,
13402 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13403 binop( Iop_Shl32, mkexpr(fg_flag2), mkU8( 2 ) ) ),
13404 binop( Iop_Shl32, mkexpr(fe_flag2), mkU8( 1 ) ) ) );
13405 assign( flags3,
13406 binop( Iop_Or32,
13407 binop( Iop_Or32, mkU32( 8 ), // fl_flag
13408 binop( Iop_Shl32, mkexpr(fg_flag3), mkU8( 2 ) ) ),
13409 binop( Iop_Shl32, mkexpr(fe_flag3), mkU8( 1 ) ) ) );
13410 putGST_field( PPC_GST_CR,
13411 binop( Iop_Or32,
13412 mkexpr( flags0 ),
13413 binop( Iop_Or32,
13414 mkexpr( flags1 ),
13415 binop( Iop_Or32,
13416 mkexpr( flags2 ),
13417 mkexpr( flags3 ) ) ) ),
13418 crfD );
13419
13420 break;
13421 }
sewardj4aa412a2011-07-24 14:13:21 +000013422
13423 default:
13424 vex_printf( "dis_vxv_sp_arith(ppc)(opc2)\n" );
13425 return False;
13426 }
13427 return True;
13428}
13429
carll7deaf952013-10-15 18:11:20 +000013430/*
carll60c6bac2013-10-18 01:19:06 +000013431 * Vector Population Count/bit matrix transpose
carll7deaf952013-10-15 18:11:20 +000013432 */
13433static Bool
carll60c6bac2013-10-18 01:19:06 +000013434dis_av_count_bitTranspose ( UInt theInstr, UInt opc2 )
carll7deaf952013-10-15 18:11:20 +000013435{
13436 UChar vRB_addr = ifieldRegB(theInstr);
13437 UChar vRT_addr = ifieldRegDS(theInstr);
13438 UChar opc1 = ifieldOPC( theInstr );
13439 IRTemp vB = newTemp(Ity_V128);
13440 assign( vB, getVReg(vRB_addr));
13441
13442 if (opc1 != 0x4) {
carll60c6bac2013-10-18 01:19:06 +000013443 vex_printf( "dis_av_count_bitTranspose(ppc)(instr)\n" );
carll7deaf952013-10-15 18:11:20 +000013444 return False;
13445 }
13446
13447 switch (opc2) {
13448 case 0x702: // vclzb
13449 DIP("vclzb v%d,v%d\n", vRT_addr, vRB_addr);
sewardja8c7b0f2014-06-26 08:18:08 +000013450 putVReg( vRT_addr, unop(Iop_Clz8x16, mkexpr( vB ) ) );
carll7deaf952013-10-15 18:11:20 +000013451 break;
13452
13453 case 0x742: // vclzh
13454 DIP("vclzh v%d,v%d\n", vRT_addr, vRB_addr);
sewardja8c7b0f2014-06-26 08:18:08 +000013455 putVReg( vRT_addr, unop(Iop_Clz16x8, mkexpr( vB ) ) );
carll7deaf952013-10-15 18:11:20 +000013456 break;
13457
13458 case 0x782: // vclzw
13459 DIP("vclzw v%d,v%d\n", vRT_addr, vRB_addr);
sewardja8c7b0f2014-06-26 08:18:08 +000013460 putVReg( vRT_addr, unop(Iop_Clz32x4, mkexpr( vB ) ) );
carll7deaf952013-10-15 18:11:20 +000013461 break;
13462
13463 case 0x7C2: // vclzd
13464 DIP("vclzd v%d,v%d\n", vRT_addr, vRB_addr);
13465 putVReg( vRT_addr, unop(Iop_Clz64x2, mkexpr( vB ) ) );
13466 break;
13467
13468 case 0x703: // vpopcntb
13469 {
13470 /* Break vector into 32-bit words and do the population count
13471 * on byte in the words
13472 */
13473 IRType ty = Ity_I32;
13474 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13475 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13476 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
13477 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
13478
13479 DIP("vpopcntb v%d,v%d\n", vRT_addr, vRB_addr);
13480 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13481 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, BYTE);
13482 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, BYTE);
13483 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, BYTE);
13484 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, BYTE);
13485
13486 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
13487 cnt_bits32_63, cnt_bits0_31) );
13488 break;
13489 }
13490
13491 case 0x743: // vpopcnth
13492 {
13493 /* Break vector into 32-bit words and do the population count
13494 * for each half word
13495 */
13496 IRType ty = Ity_I32;
13497 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13498 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13499 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
13500 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
13501
13502 DIP("vpopcnth v%d,v%d\n", vRT_addr, vRB_addr);
13503 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13504
13505 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, HWORD);
13506 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, HWORD);
13507 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, HWORD);
13508 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, HWORD);
13509
13510 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
13511 cnt_bits32_63, cnt_bits0_31) );
13512 break;
13513 }
13514
13515 case 0x783: // vpopcntw
13516 {
13517 /* Break vector into 32-bit words and do the population count
13518 * on each word.
13519 */
13520 IRType ty = Ity_I32;
13521 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13522 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13523 IRTemp cnt_bits0_31, cnt_bits32_63, cnt_bits64_95, cnt_bits96_127;
13524 cnt_bits0_31 = cnt_bits32_63 = cnt_bits64_95 = cnt_bits96_127 = IRTemp_INVALID;
13525
13526 DIP("vpopcntw v%d,v%d\n", vRT_addr, vRB_addr);
13527 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13528
13529 cnt_bits0_31 = gen_POPCOUNT(ty, bits0_31, WORD);
13530 cnt_bits32_63 = gen_POPCOUNT(ty, bits32_63, WORD);
13531 cnt_bits64_95 = gen_POPCOUNT(ty, bits64_95, WORD);
13532 cnt_bits96_127 = gen_POPCOUNT(ty, bits96_127, WORD);
13533
13534 putVReg( vRT_addr, mkV128from32(cnt_bits96_127, cnt_bits64_95,
13535 cnt_bits32_63, cnt_bits0_31) );
13536 break;
13537 }
13538
13539 case 0x7C3: // vpopcntd
13540 {
13541 if (mode64) {
13542 /* Break vector into 64-bit double words and do the population count
13543 * on each double word.
13544 */
13545 IRType ty = Ity_I64;
13546 IRTemp bits0_63 = newTemp(Ity_I64);
13547 IRTemp bits64_127 = newTemp(Ity_I64);
13548 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
13549 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
13550
13551 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
13552
13553 assign(bits0_63, unop( Iop_V128to64, mkexpr( vB ) ) );
13554 assign(bits64_127, unop( Iop_V128HIto64, mkexpr( vB ) ) );
13555 cnt_bits0_63 = gen_POPCOUNT(ty, bits0_63, DWORD);
13556 cnt_bits64_127 = gen_POPCOUNT(ty, bits64_127, DWORD);
13557
13558 putVReg( vRT_addr, binop( Iop_64HLtoV128,
13559 mkexpr( cnt_bits64_127 ),
13560 mkexpr( cnt_bits0_63 ) ) );
13561 } else {
13562 /* Break vector into 32-bit words and do the population count
13563 * on each doubleword.
13564 */
13565 IRTemp bits0_31, bits32_63, bits64_95, bits96_127;
13566 bits0_31 = bits32_63 = bits64_95 = bits96_127 = IRTemp_INVALID;
13567 IRTemp cnt_bits0_63 = newTemp(Ity_I64);
13568 IRTemp cnt_bits64_127 = newTemp(Ity_I64);
13569
13570 DIP("vpopcntd v%d,v%d\n", vRT_addr, vRB_addr);
13571 breakV128to4x32(mkexpr( vB), &bits96_127, &bits64_95, &bits32_63, &bits0_31 );
13572
13573 cnt_bits0_63 = gen_vpopcntd_mode32(bits0_31, bits32_63);
13574 cnt_bits64_127 = gen_vpopcntd_mode32(bits64_95, bits96_127);
13575
13576 putVReg( vRT_addr, binop( Iop_64HLtoV128,
13577 mkexpr( cnt_bits64_127 ),
13578 mkexpr( cnt_bits0_63 ) ) );
13579 }
13580 break;
13581 }
13582
carll60c6bac2013-10-18 01:19:06 +000013583 case 0x50C: // vgbbd Vector Gather Bits by Bytes by Doubleword
13584 DIP("vgbbd v%d,v%d\n", vRT_addr, vRB_addr);
13585 putVReg( vRT_addr, unop( Iop_PwBitMtxXpose64x2, mkexpr( vB ) ) );
13586 break;
13587
carll7deaf952013-10-15 18:11:20 +000013588 default:
carll60c6bac2013-10-18 01:19:06 +000013589 vex_printf("dis_av_count_bitTranspose(ppc)(opc2)\n");
carll7deaf952013-10-15 18:11:20 +000013590 return False;
13591 break;
13592 }
13593 return True;
13594}
13595
sewardj4aa412a2011-07-24 14:13:21 +000013596typedef enum {
13597 PPC_CMP_EQ = 2,
13598 PPC_CMP_GT = 4,
13599 PPC_CMP_GE = 6,
13600 PPC_CMP_LT = 8
13601} ppc_cmp_t;
13602
13603
13604/*
13605 This helper function takes as input the IRExpr returned
13606 from a binop( Iop_CmpF64, fpA, fpB), whose result is returned
13607 in IR form. This helper function converts it to PPC form.
13608
13609 Map compare result from IR to PPC
13610
13611 FP cmp result | PPC | IR
13612 --------------------------
13613 UN | 0x1 | 0x45
13614 EQ | 0x2 | 0x40
13615 GT | 0x4 | 0x00
13616 LT | 0x8 | 0x01
13617
13618 condcode = Shl(1, (~(ccIR>>5) & 2)
13619 | ((ccIR ^ (ccIR>>6)) & 1)
13620*/
13621static IRTemp
13622get_fp_cmp_CR_val (IRExpr * ccIR_expr)
13623{
13624 IRTemp condcode = newTemp( Ity_I32 );
13625 IRTemp ccIR = newTemp( Ity_I32 );
13626
13627 assign(ccIR, ccIR_expr);
13628 assign( condcode,
13629 binop( Iop_Shl32,
13630 mkU32( 1 ),
13631 unop( Iop_32to8,
13632 binop( Iop_Or32,
13633 binop( Iop_And32,
13634 unop( Iop_Not32,
13635 binop( Iop_Shr32,
13636 mkexpr( ccIR ),
13637 mkU8( 5 ) ) ),
13638 mkU32( 2 ) ),
13639 binop( Iop_And32,
13640 binop( Iop_Xor32,
13641 mkexpr( ccIR ),
13642 binop( Iop_Shr32,
13643 mkexpr( ccIR ),
13644 mkU8( 6 ) ) ),
13645 mkU32( 1 ) ) ) ) ) );
13646 return condcode;
13647}
13648
13649/*
13650 * Helper function for get_max_min_fp for ascertaining the max or min between two doubles
13651 * following these special rules:
13652 * - The max/min of a QNaN and any value is that value
13653 * (When two QNaNs are being compared, the frA QNaN is the return value.)
13654 * - The max/min of any value and an SNaN is that SNaN converted to a QNaN
13655 * (When two SNaNs are being compared, the frA SNaN is converted to a QNaN.)
13656 */
13657static IRExpr * _get_maxmin_fp_NaN(IRTemp frA_I64, IRTemp frB_I64)
13658{
13659 IRTemp frA_isNaN = newTemp(Ity_I1);
13660 IRTemp frB_isNaN = newTemp(Ity_I1);
13661 IRTemp frA_isSNaN = newTemp(Ity_I1);
13662 IRTemp frB_isSNaN = newTemp(Ity_I1);
13663 IRTemp frA_isQNaN = newTemp(Ity_I1);
13664 IRTemp frB_isQNaN = newTemp(Ity_I1);
13665
13666 assign( frA_isNaN, is_NaN( frA_I64 ) );
13667 assign( frB_isNaN, is_NaN( frB_I64 ) );
13668 // If operand is a NAN and bit 12 is '0', then it's an SNaN
13669 assign( frA_isSNaN,
13670 mkAND1( mkexpr(frA_isNaN),
13671 binop( Iop_CmpEQ32,
13672 binop( Iop_And32,
13673 unop( Iop_64HIto32, mkexpr( frA_I64 ) ),
13674 mkU32( 0x00080000 ) ),
13675 mkU32( 0 ) ) ) );
13676 assign( frB_isSNaN,
13677 mkAND1( mkexpr(frB_isNaN),
13678 binop( Iop_CmpEQ32,
13679 binop( Iop_And32,
13680 unop( Iop_64HIto32, mkexpr( frB_I64 ) ),
13681 mkU32( 0x00080000 ) ),
13682 mkU32( 0 ) ) ) );
13683 assign( frA_isQNaN,
13684 mkAND1( mkexpr( frA_isNaN ), unop( Iop_Not1, mkexpr( frA_isSNaN ) ) ) );
13685 assign( frB_isQNaN,
13686 mkAND1( mkexpr( frB_isNaN ), unop( Iop_Not1, mkexpr( frB_isSNaN ) ) ) );
13687
13688 /* Based on the rules specified in the function prologue, the algorithm is as follows:
13689 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
13690 * if frA is a SNaN
13691 * result = frA converted to QNaN
13692 * else if frB is a SNaN
13693 * result = frB converted to QNaN
13694 * else if frB is a QNaN
13695 * result = frA
13696 * // One of frA or frB was a NaN in order for this function to be called, so
13697 * // if we get to this point, we KNOW that frA must be a QNaN.
13698 * else // frA is a QNaN
13699 * result = frB
13700 * <<<<<<<<<>>>>>>>>>>>>>>>>>>
13701 */
13702
13703#define SNAN_MASK 0x0008000000000000ULL
13704 return
florian99dd03e2013-01-29 03:56:06 +000013705 IRExpr_ITE(mkexpr(frA_isSNaN),
13706 /* then: result = frA converted to QNaN */
13707 binop(Iop_Or64, mkexpr(frA_I64), mkU64(SNAN_MASK)),
13708 /* else: if frB is a SNaN */
13709 IRExpr_ITE(mkexpr(frB_isSNaN),
13710 /* then: result = frB converted to QNaN */
13711 binop(Iop_Or64, mkexpr(frB_I64), mkU64(SNAN_MASK)),
13712 /* else: if frB is a QNaN */
13713 IRExpr_ITE(mkexpr(frB_isQNaN),
13714 /* then: result = frA */
13715 mkexpr(frA_I64),
13716 /* else: frA is a QNaN, so result = frB */
13717 mkexpr(frB_I64))));
sewardj4aa412a2011-07-24 14:13:21 +000013718}
13719
13720/*
13721 * Helper function for get_max_min_fp.
13722 */
13723static IRExpr * _get_maxmin_fp_cmp(IRTemp src1, IRTemp src2, Bool isMin)
13724{
13725 IRTemp src1cmpsrc2 = get_fp_cmp_CR_val( binop( Iop_CmpF64,
13726 unop( Iop_ReinterpI64asF64,
13727 mkexpr( src1 ) ),
13728 unop( Iop_ReinterpI64asF64,
13729 mkexpr( src2 ) ) ) );
13730
florian99dd03e2013-01-29 03:56:06 +000013731 return IRExpr_ITE( binop( Iop_CmpEQ32,
sewardj009230b2013-01-26 11:47:55 +000013732 mkexpr( src1cmpsrc2 ),
13733 mkU32( isMin ? PPC_CMP_LT : PPC_CMP_GT ) ),
florian99dd03e2013-01-29 03:56:06 +000013734 /* then: use src1 */
13735 mkexpr( src1 ),
13736 /* else: use src2 */
13737 mkexpr( src2 ) );
sewardj4aa412a2011-07-24 14:13:21 +000013738}
13739
13740/*
13741 * Helper function for "Maximum/Minimum Double Precision" operations.
13742 * Arguments: frA and frb are Ity_I64
13743 * Returns Ity_I64 IRExpr that answers the "which is Maxiumum/Minimum" question
13744 */
13745static IRExpr * get_max_min_fp(IRTemp frA_I64, IRTemp frB_I64, Bool isMin)
13746{
13747 /* There are three special cases where get_fp_cmp_CR_val is not helpful
13748 * for ascertaining the maximum between two doubles:
13749 * 1. The max/min of +0 and -0 is +0.
13750 * 2. The max/min of a QNaN and any value is that value.
13751 * 3. The max/min of any value and an SNaN is that SNaN converted to a QNaN.
13752 * We perform the check for [+/-]0 here in this function and use the
13753 * _get_maxmin_fp_NaN helper for the two NaN cases; otherwise we call _get_maxmin_fp_cmp
13754 * to do the standard comparison function.
13755 */
13756 IRTemp anyNaN = newTemp(Ity_I1);
13757 IRTemp frA_isZero = newTemp(Ity_I1);
13758 IRTemp frB_isZero = newTemp(Ity_I1);
sewardje71e56a2011-09-05 12:11:06 +000013759 assign(frA_isZero, is_Zero(frA_I64, False /*not single precision*/ ));
13760 assign(frB_isZero, is_Zero(frB_I64, False /*not single precision*/ ));
sewardj4aa412a2011-07-24 14:13:21 +000013761 assign(anyNaN, mkOR1(is_NaN(frA_I64), is_NaN(frB_I64)));
13762#define MINUS_ZERO 0x8000000000000000ULL
13763
florian99dd03e2013-01-29 03:56:06 +000013764 return IRExpr_ITE( /* If both arguments are zero . . . */
13765 mkAND1( mkexpr( frA_isZero ), mkexpr( frB_isZero ) ),
13766 /* then: if frA is -0 and isMin==True, return -0;
13767 * else if frA is +0 and isMin==False; return +0;
13768 * otherwise, simply return frB. */
13769 IRExpr_ITE( binop( Iop_CmpEQ32,
13770 unop( Iop_64HIto32,
13771 mkexpr( frA_I64 ) ),
13772 mkU32( isMin ? 0x80000000 : 0 ) ),
13773 mkU64( isMin ? MINUS_ZERO : 0ULL ),
13774 mkexpr( frB_I64 ) ),
13775 /* else: check if either input is a NaN*/
13776 IRExpr_ITE( mkexpr( anyNaN ),
13777 /* then: use "NaN helper" */
13778 _get_maxmin_fp_NaN( frA_I64, frB_I64 ),
13779 /* else: use "comparison helper" */
13780 _get_maxmin_fp_cmp( frB_I64, frA_I64, isMin ) ));
sewardj4aa412a2011-07-24 14:13:21 +000013781}
sewardje71e56a2011-09-05 12:11:06 +000013782
carll9884af02013-01-30 18:39:57 +000013783static const HChar * _get_vsx_rdpi_suffix(UInt opc2)
13784{
13785 switch (opc2 & 0x7F) {
13786 case 0x72:
13787 return "m";
13788 case 0x52:
13789 return "p";
13790 case 0x56:
13791 return "c";
13792 case 0x32:
13793 return "z";
13794 case 0x12:
13795 return "";
13796
13797 default: // Impossible to get here
13798 vex_printf("Unrecognized opcode %x\n", opc2);
13799 vpanic("_get_vsx_rdpi_suffix(ppc)(opc2)");
13800 }
13801}
13802
sewardje71e56a2011-09-05 12:11:06 +000013803/*
13804 * Helper function for vector/scalar double precision fp round to integer instructions.
13805 */
carll9884af02013-01-30 18:39:57 +000013806static IRExpr * _do_vsx_fp_roundToInt(IRTemp frB_I64, UInt opc2)
sewardje71e56a2011-09-05 12:11:06 +000013807{
13808
13809 /* The same rules apply for x{s|v}rdpi{m|p|c|z} as for floating point round operations (fri{m|n|p|z}). */
13810 IRTemp frB = newTemp(Ity_F64);
13811 IRTemp frD = newTemp(Ity_F64);
13812 IRTemp intermediateResult = newTemp(Ity_I64);
13813 IRTemp is_SNAN = newTemp(Ity_I1);
13814 IRExpr * hi32;
13815 IRExpr * rxpi_rm;
13816 switch (opc2 & 0x7F) {
13817 case 0x72:
sewardje71e56a2011-09-05 12:11:06 +000013818 rxpi_rm = mkU32(Irrm_NegINF);
13819 break;
13820 case 0x52:
sewardje71e56a2011-09-05 12:11:06 +000013821 rxpi_rm = mkU32(Irrm_PosINF);
13822 break;
13823 case 0x56:
sewardje71e56a2011-09-05 12:11:06 +000013824 rxpi_rm = get_IR_roundingmode();
13825 break;
13826 case 0x32:
sewardje71e56a2011-09-05 12:11:06 +000013827 rxpi_rm = mkU32(Irrm_ZERO);
13828 break;
13829 case 0x12:
sewardje71e56a2011-09-05 12:11:06 +000013830 rxpi_rm = mkU32(Irrm_NEAREST);
13831 break;
13832
13833 default: // Impossible to get here
carll9884af02013-01-30 18:39:57 +000013834 vex_printf("Unrecognized opcode %x\n", opc2);
13835 vpanic("_do_vsx_fp_roundToInt(ppc)(opc2)");
sewardje71e56a2011-09-05 12:11:06 +000013836 }
13837 assign(frB, unop(Iop_ReinterpI64asF64, mkexpr(frB_I64)));
13838 assign( intermediateResult,
13839 binop( Iop_F64toI64S, rxpi_rm,
13840 mkexpr( frB ) ) );
13841
13842 /* don't use the rounded integer if frB is outside -9e18..9e18 */
13843 /* F64 has only log10(2**52) significant digits anyway */
13844 /* need to preserve sign of zero */
13845 /* frD = (fabs(frB) > 9e18) ? frB :
13846 (sign(frB)) ? -fabs((double)intermediateResult) : (double)intermediateResult */
13847 assign( frD,
florian99dd03e2013-01-29 03:56:06 +000013848 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +000013849 binop( Iop_CmpNE8,
13850 unop( Iop_32to8,
13851 binop( Iop_CmpF64,
13852 IRExpr_Const( IRConst_F64( 9e18 ) ),
13853 unop( Iop_AbsF64, mkexpr( frB ) ) ) ),
13854 mkU8(0) ),
florian99dd03e2013-01-29 03:56:06 +000013855 mkexpr( frB ),
13856 IRExpr_ITE(
sewardj009230b2013-01-26 11:47:55 +000013857 binop( Iop_CmpNE32,
13858 binop( Iop_Shr32,
13859 unop( Iop_64HIto32,
13860 mkexpr( frB_I64 ) ),
13861 mkU8( 31 ) ),
13862 mkU32(0) ),
sewardj009230b2013-01-26 11:47:55 +000013863 unop( Iop_NegF64,
13864 unop( Iop_AbsF64,
13865 binop( Iop_I64StoF64,
13866 mkU32( 0 ),
florian99dd03e2013-01-29 03:56:06 +000013867 mkexpr( intermediateResult ) ) ) ),
13868 binop( Iop_I64StoF64,
13869 mkU32( 0 ),
13870 mkexpr( intermediateResult ) )
13871 )
sewardj009230b2013-01-26 11:47:55 +000013872 )
13873 );
sewardje71e56a2011-09-05 12:11:06 +000013874
13875 /* See Appendix "Floating-Point Round to Integer Model" in ISA doc.
13876 * If frB is a SNAN, then frD <- frB, with bit 12 set to '1'.
13877 */
13878#define SNAN_MASK 0x0008000000000000ULL
13879 hi32 = unop( Iop_64HIto32, mkexpr(frB_I64) );
13880 assign( is_SNAN,
13881 mkAND1( is_NaN( frB_I64 ),
13882 binop( Iop_CmpEQ32,
13883 binop( Iop_And32, hi32, mkU32( 0x00080000 ) ),
13884 mkU32( 0 ) ) ) );
13885
florian99dd03e2013-01-29 03:56:06 +000013886 return IRExpr_ITE( mkexpr( is_SNAN ),
sewardje71e56a2011-09-05 12:11:06 +000013887 unop( Iop_ReinterpI64asF64,
13888 binop( Iop_Xor64,
13889 mkU64( SNAN_MASK ),
florian99dd03e2013-01-29 03:56:06 +000013890 mkexpr( frB_I64 ) ) ),
13891 mkexpr( frD ));
sewardje71e56a2011-09-05 12:11:06 +000013892}
13893
sewardj4aa412a2011-07-24 14:13:21 +000013894/*
13895 * Miscellaneous VSX vector instructions
13896 */
13897static Bool
13898dis_vxv_misc ( UInt theInstr, UInt opc2 )
13899{
13900 /* XX3-Form */
13901 UChar opc1 = ifieldOPC( theInstr );
13902 UChar XT = ifieldRegXT( theInstr );
13903 UChar XB = ifieldRegXB( theInstr );
13904
13905 if (opc1 != 0x3C) {
13906 vex_printf( "dis_vxv_misc(ppc)(instr)\n" );
13907 return False;
13908 }
13909
13910 switch (opc2) {
sewardje71e56a2011-09-05 12:11:06 +000013911 case 0x1B4: // xvredp (VSX Vector Reciprocal Estimate Double-Precision)
13912 case 0x194: // xvrsqrtedp (VSX Vector Reciprocal Square Root Estimate
13913 // Double-Precision)
13914 {
13915 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
13916 IRExpr* rm = get_IR_roundingmode();
13917 IRTemp frB = newTemp(Ity_I64);
13918 IRTemp frB2 = newTemp(Ity_I64);
13919 Bool redp = opc2 == 0x1B4;
13920 IRTemp sqrtHi = newTemp(Ity_F64);
13921 IRTemp sqrtLo = newTemp(Ity_F64);
13922 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
13923 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
13924
13925 DIP("%s v%d,v%d\n", redp ? "xvredp" : "xvrsqrtedp", (UInt)XT, (UInt)XB);
13926 if (!redp) {
13927 assign( sqrtHi,
13928 binop( Iop_SqrtF64,
13929 rm,
13930 unop( Iop_ReinterpI64asF64, mkexpr( frB ) ) ) );
13931 assign( sqrtLo,
13932 binop( Iop_SqrtF64,
13933 rm,
13934 unop( Iop_ReinterpI64asF64, mkexpr( frB2 ) ) ) );
13935 }
13936 putVSReg( XT,
13937 binop( Iop_64HLtoV128,
13938 unop( Iop_ReinterpF64asI64,
13939 triop( Iop_DivF64,
13940 rm,
13941 ieee_one,
13942 redp ? unop( Iop_ReinterpI64asF64,
13943 mkexpr( frB ) )
13944 : mkexpr( sqrtHi ) ) ),
13945 unop( Iop_ReinterpF64asI64,
13946 triop( Iop_DivF64,
13947 rm,
13948 ieee_one,
13949 redp ? unop( Iop_ReinterpI64asF64,
13950 mkexpr( frB2 ) )
13951 : mkexpr( sqrtLo ) ) ) ) );
13952 break;
13953
13954 }
sewardj4aa412a2011-07-24 14:13:21 +000013955 case 0x134: // xvresp (VSX Vector Reciprocal Estimate Single-Precision)
sewardje71e56a2011-09-05 12:11:06 +000013956 case 0x114: // xvrsqrtesp (VSX Vector Reciprocal Square Root Estimate Single-Precision)
sewardj4aa412a2011-07-24 14:13:21 +000013957 {
13958 IRTemp b3, b2, b1, b0;
13959 IRTemp res0 = newTemp(Ity_I32);
13960 IRTemp res1 = newTemp(Ity_I32);
13961 IRTemp res2 = newTemp(Ity_I32);
13962 IRTemp res3 = newTemp(Ity_I32);
sewardje71e56a2011-09-05 12:11:06 +000013963 IRTemp sqrt3 = newTemp(Ity_F64);
13964 IRTemp sqrt2 = newTemp(Ity_F64);
13965 IRTemp sqrt1 = newTemp(Ity_F64);
13966 IRTemp sqrt0 = newTemp(Ity_F64);
sewardj4aa412a2011-07-24 14:13:21 +000013967 IRExpr* rm = get_IR_roundingmode();
sewardje71e56a2011-09-05 12:11:06 +000013968 Bool resp = opc2 == 0x134;
13969
sewardj4aa412a2011-07-24 14:13:21 +000013970 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
13971
13972 b3 = b2 = b1 = b0 = IRTemp_INVALID;
sewardje71e56a2011-09-05 12:11:06 +000013973 DIP("%s v%d,v%d\n", resp ? "xvresp" : "xvrsqrtesp", (UInt)XT, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000013974 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
sewardje71e56a2011-09-05 12:11:06 +000013975
13976 if (!resp) {
13977 assign( sqrt3, binop( Iop_SqrtF64, rm, mkexpr( b3 ) ) );
13978 assign( sqrt2, binop( Iop_SqrtF64, rm, mkexpr( b2 ) ) );
13979 assign( sqrt1, binop( Iop_SqrtF64, rm, mkexpr( b1 ) ) );
13980 assign( sqrt0, binop( Iop_SqrtF64, rm, mkexpr( b0 ) ) );
13981 }
13982
sewardj4aa412a2011-07-24 14:13:21 +000013983 assign( res0,
13984 unop( Iop_ReinterpF32asI32,
13985 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000013986 triop( Iop_DivF64r32,
13987 rm,
13988 ieee_one,
13989 resp ? mkexpr( b0 ) : mkexpr( sqrt0 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000013990 assign( res1,
13991 unop( Iop_ReinterpF32asI32,
13992 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000013993 triop( Iop_DivF64r32,
13994 rm,
13995 ieee_one,
13996 resp ? mkexpr( b1 ) : mkexpr( sqrt1 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000013997 assign( res2,
13998 unop( Iop_ReinterpF32asI32,
13999 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000014000 triop( Iop_DivF64r32,
14001 rm,
14002 ieee_one,
14003 resp ? mkexpr( b2 ) : mkexpr( sqrt2 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000014004 assign( res3,
14005 unop( Iop_ReinterpF32asI32,
14006 unop( Iop_TruncF64asF32,
sewardje71e56a2011-09-05 12:11:06 +000014007 triop( Iop_DivF64r32,
14008 rm,
14009 ieee_one,
14010 resp ? mkexpr( b3 ) : mkexpr( sqrt3 ) ) ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000014011 putVSReg( XT,
14012 binop( Iop_64HLtoV128,
14013 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
14014 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
14015 break;
14016 }
14017 case 0x300: // xvmaxsp (VSX Vector Maximum Single-Precision)
14018 case 0x320: // xvminsp (VSX Vector Minimum Single-Precision)
14019 {
14020 UChar XA = ifieldRegXA( theInstr );
14021 IRTemp a3, a2, a1, a0;
14022 IRTemp b3, b2, b1, b0;
14023 IRTemp res0 = newTemp( Ity_I32 );
14024 IRTemp res1 = newTemp( Ity_I32 );
14025 IRTemp res2 = newTemp( Ity_I32 );
14026 IRTemp res3 = newTemp( Ity_I32 );
14027 IRTemp a0_I64 = newTemp( Ity_I64 );
14028 IRTemp a1_I64 = newTemp( Ity_I64 );
14029 IRTemp a2_I64 = newTemp( Ity_I64 );
14030 IRTemp a3_I64 = newTemp( Ity_I64 );
14031 IRTemp b0_I64 = newTemp( Ity_I64 );
14032 IRTemp b1_I64 = newTemp( Ity_I64 );
14033 IRTemp b2_I64 = newTemp( Ity_I64 );
14034 IRTemp b3_I64 = newTemp( Ity_I64 );
14035
14036 Bool isMin = opc2 == 0x320 ? True : False;
14037
14038 a3 = a2 = a1 = a0 = IRTemp_INVALID;
14039 b3 = b2 = b1 = b0 = IRTemp_INVALID;
14040 DIP("%s v%d,v%d v%d\n", isMin ? "xvminsp" : "xvmaxsp", (UInt)XT, (UInt)XA, (UInt)XB);
14041 breakV128to4xF64( getVSReg( XA ), &a3, &a2, &a1, &a0 );
14042 breakV128to4xF64( getVSReg( XB ), &b3, &b2, &b1, &b0 );
14043 assign( a0_I64, unop( Iop_ReinterpF64asI64, mkexpr( a0 ) ) );
14044 assign( b0_I64, unop( Iop_ReinterpF64asI64, mkexpr( b0 ) ) );
14045 assign( a1_I64, unop( Iop_ReinterpF64asI64, mkexpr( a1 ) ) );
14046 assign( b1_I64, unop( Iop_ReinterpF64asI64, mkexpr( b1 ) ) );
14047 assign( a2_I64, unop( Iop_ReinterpF64asI64, mkexpr( a2 ) ) );
14048 assign( b2_I64, unop( Iop_ReinterpF64asI64, mkexpr( b2 ) ) );
14049 assign( a3_I64, unop( Iop_ReinterpF64asI64, mkexpr( a3 ) ) );
14050 assign( b3_I64, unop( Iop_ReinterpF64asI64, mkexpr( b3 ) ) );
14051 assign( res0,
14052 unop( Iop_ReinterpF32asI32,
14053 unop( Iop_TruncF64asF32,
14054 unop( Iop_ReinterpI64asF64,
14055 get_max_min_fp( a0_I64, b0_I64, isMin ) ) ) ) );
14056 assign( res1,
14057 unop( Iop_ReinterpF32asI32,
14058 unop( Iop_TruncF64asF32,
14059 unop( Iop_ReinterpI64asF64,
14060 get_max_min_fp( a1_I64, b1_I64, isMin ) ) ) ) );
14061 assign( res2,
14062 unop( Iop_ReinterpF32asI32,
14063 unop( Iop_TruncF64asF32,
14064 unop( Iop_ReinterpI64asF64,
14065 get_max_min_fp( a2_I64, b2_I64, isMin ) ) ) ) );
14066 assign( res3,
14067 unop( Iop_ReinterpF32asI32,
14068 unop( Iop_TruncF64asF32,
14069 unop( Iop_ReinterpI64asF64,
14070 get_max_min_fp( a3_I64, b3_I64, isMin ) ) ) ) );
14071 putVSReg( XT,
14072 binop( Iop_64HLtoV128,
14073 binop( Iop_32HLto64, mkexpr( res3 ), mkexpr( res2 ) ),
14074 binop( Iop_32HLto64, mkexpr( res1 ), mkexpr( res0 ) ) ) );
14075 break;
14076 }
14077 case 0x380: // xvmaxdp (VSX Vector Maximum Double-Precision)
14078 case 0x3A0: // xvmindp (VSX Vector Minimum Double-Precision)
14079 {
14080 UChar XA = ifieldRegXA( theInstr );
14081 IRTemp frA = newTemp(Ity_I64);
14082 IRTemp frB = newTemp(Ity_I64);
14083 IRTemp frA2 = newTemp(Ity_I64);
14084 IRTemp frB2 = newTemp(Ity_I64);
14085 Bool isMin = opc2 == 0x3A0 ? True : False;
14086
14087 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
14088 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
14089 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
14090 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
14091 DIP("%s v%d,v%d v%d\n", isMin ? "xvmindp" : "xvmaxdp", (UInt)XT, (UInt)XA, (UInt)XB);
14092 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), get_max_min_fp(frA2, frB2, isMin) ) );
14093
14094 break;
14095 }
14096 case 0x3c0: // xvcpsgndp (VSX Vector Copy Sign Double-Precision)
14097 {
14098 UChar XA = ifieldRegXA( theInstr );
14099 IRTemp frA = newTemp(Ity_I64);
14100 IRTemp frB = newTemp(Ity_I64);
14101 IRTemp frA2 = newTemp(Ity_I64);
14102 IRTemp frB2 = newTemp(Ity_I64);
14103 assign(frA, unop(Iop_V128HIto64, getVSReg( XA )));
14104 assign(frB, unop(Iop_V128HIto64, getVSReg( XB )));
14105 assign(frA2, unop(Iop_V128to64, getVSReg( XA )));
14106 assign(frB2, unop(Iop_V128to64, getVSReg( XB )));
14107
14108 DIP("xvcpsgndp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14109 putVSReg( XT,
14110 binop( Iop_64HLtoV128,
14111 binop( Iop_Or64,
14112 binop( Iop_And64,
14113 mkexpr( frA ),
14114 mkU64( SIGN_BIT ) ),
14115 binop( Iop_And64,
14116 mkexpr( frB ),
14117 mkU64( SIGN_MASK ) ) ),
14118 binop( Iop_Or64,
14119 binop( Iop_And64,
14120 mkexpr( frA2 ),
14121 mkU64( SIGN_BIT ) ),
14122 binop( Iop_And64,
14123 mkexpr( frB2 ),
14124 mkU64( SIGN_MASK ) ) ) ) );
14125 break;
14126 }
14127 case 0x340: // xvcpsgnsp
14128 {
14129 UChar XA = ifieldRegXA( theInstr );
14130 IRTemp a3_I64, a2_I64, a1_I64, a0_I64;
14131 IRTemp b3_I64, b2_I64, b1_I64, b0_I64;
14132 IRTemp resHi = newTemp(Ity_I64);
14133 IRTemp resLo = newTemp(Ity_I64);
14134
14135 a3_I64 = a2_I64 = a1_I64 = a0_I64 = IRTemp_INVALID;
14136 b3_I64 = b2_I64 = b1_I64 = b0_I64 = IRTemp_INVALID;
14137 DIP("xvcpsgnsp v%d,v%d v%d\n",(UInt)XT, (UInt)XA, (UInt)XB);
14138 breakV128to4x64U( getVSReg( XA ), &a3_I64, &a2_I64, &a1_I64, &a0_I64 );
14139 breakV128to4x64U( getVSReg( XB ), &b3_I64, &b2_I64, &b1_I64, &b0_I64 );
14140
14141 assign( resHi,
14142 binop( Iop_32HLto64,
14143 binop( Iop_Or32,
14144 binop( Iop_And32,
14145 unop(Iop_64to32, mkexpr( a3_I64 ) ),
14146 mkU32( SIGN_BIT32 ) ),
14147 binop( Iop_And32,
14148 unop(Iop_64to32, mkexpr( b3_I64 ) ),
14149 mkU32( SIGN_MASK32) ) ),
14150
14151 binop( Iop_Or32,
14152 binop( Iop_And32,
14153 unop(Iop_64to32, mkexpr( a2_I64 ) ),
14154 mkU32( SIGN_BIT32 ) ),
14155 binop( Iop_And32,
14156 unop(Iop_64to32, mkexpr( b2_I64 ) ),
14157 mkU32( SIGN_MASK32 ) ) ) ) );
14158 assign( resLo,
14159 binop( Iop_32HLto64,
14160 binop( Iop_Or32,
14161 binop( Iop_And32,
14162 unop(Iop_64to32, mkexpr( a1_I64 ) ),
14163 mkU32( SIGN_BIT32 ) ),
14164 binop( Iop_And32,
14165 unop(Iop_64to32, mkexpr( b1_I64 ) ),
14166 mkU32( SIGN_MASK32 ) ) ),
14167
14168 binop( Iop_Or32,
14169 binop( Iop_And32,
14170 unop(Iop_64to32, mkexpr( a0_I64 ) ),
14171 mkU32( SIGN_BIT32 ) ),
14172 binop( Iop_And32,
14173 unop(Iop_64to32, mkexpr( b0_I64 ) ),
14174 mkU32( SIGN_MASK32 ) ) ) ) );
14175 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( resHi ), mkexpr( resLo ) ) );
14176 break;
14177 }
sewardje71e56a2011-09-05 12:11:06 +000014178 case 0x3B2: // xvabsdp (VSX Vector Absolute Value Double-Precision)
14179 case 0x3D2: // xvnabsdp VSX Vector Negative Absolute Value Double-Precision)
14180 {
14181 IRTemp frB = newTemp(Ity_F64);
14182 IRTemp frB2 = newTemp(Ity_F64);
14183 IRTemp abs_resultHi = newTemp(Ity_F64);
14184 IRTemp abs_resultLo = newTemp(Ity_F64);
14185 Bool make_negative = (opc2 == 0x3D2) ? True : False;
14186 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14187 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
14188
14189 DIP("xv%sabsdp v%d,v%d\n", make_negative ? "n" : "", (UInt)XT, (UInt)XB);
14190 if (make_negative) {
14191 assign(abs_resultHi, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB ) ) ) );
14192 assign(abs_resultLo, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr( frB2 ) ) ) );
14193
14194 } else {
14195 assign(abs_resultHi, unop( Iop_AbsF64, mkexpr( frB ) ) );
14196 assign(abs_resultLo, unop( Iop_AbsF64, mkexpr( frB2 ) ) );
14197 }
14198 putVSReg( XT, binop( Iop_64HLtoV128,
14199 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultHi ) ),
14200 unop( Iop_ReinterpF64asI64, mkexpr( abs_resultLo ) ) ) );
14201 break;
14202 }
14203 case 0x332: // xvabssp (VSX Vector Absolute Value Single-Precision)
14204 case 0x352: // xvnabssp (VSX Vector Negative Absolute Value Single-Precision)
14205 {
14206 /*
14207 * The Iop_AbsF32 IRop is not implemented for ppc64 since, up until introduction
14208 * of xvabssp, there has not been an abs(sp) type of instruction. But since emulation
14209 * of this function is so easy using shifts, I choose to emulate this instruction that
14210 * way versus a native instruction method of implementation.
14211 */
14212 Bool make_negative = (opc2 == 0x352) ? True : False;
14213 IRTemp shiftVector = newTemp(Ity_V128);
14214 IRTemp absVal_vector = newTemp(Ity_V128);
14215 assign( shiftVector,
14216 binop( Iop_64HLtoV128,
14217 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ),
14218 binop( Iop_32HLto64, mkU32( 1 ), mkU32( 1 ) ) ) );
14219 assign( absVal_vector,
14220 binop( Iop_Shr32x4,
14221 binop( Iop_Shl32x4,
14222 getVSReg( XB ),
14223 mkexpr( shiftVector ) ),
14224 mkexpr( shiftVector ) ) );
14225 if (make_negative) {
14226 IRTemp signBit_vector = newTemp(Ity_V128);
14227 assign( signBit_vector,
14228 binop( Iop_64HLtoV128,
14229 binop( Iop_32HLto64,
14230 mkU32( 0x80000000 ),
14231 mkU32( 0x80000000 ) ),
14232 binop( Iop_32HLto64,
14233 mkU32( 0x80000000 ),
14234 mkU32( 0x80000000 ) ) ) );
14235 putVSReg( XT,
14236 binop( Iop_OrV128,
14237 mkexpr( absVal_vector ),
14238 mkexpr( signBit_vector ) ) );
14239 } else {
14240 putVSReg( XT, mkexpr( absVal_vector ) );
14241 }
14242 break;
14243 }
14244 case 0x3F2: // xvnegdp (VSX Vector Negate Double-Precision)
14245 {
14246 IRTemp frB = newTemp(Ity_F64);
14247 IRTemp frB2 = newTemp(Ity_F64);
14248 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14249 assign(frB2, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, getVSReg(XB))));
14250 DIP("xvnegdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14251 putVSReg( XT,
14252 binop( Iop_64HLtoV128,
14253 unop( Iop_ReinterpF64asI64,
14254 unop( Iop_NegF64, mkexpr( frB ) ) ),
14255 unop( Iop_ReinterpF64asI64,
14256 unop( Iop_NegF64, mkexpr( frB2 ) ) ) ) );
14257 break;
14258 }
14259 case 0x192: // xvrdpi (VSX Vector Round to Double-Precision Integer using round toward Nearest Away)
14260 case 0x1D6: // xvrdpic (VSX Vector Round to Double-Precision Integer using Current rounding mode)
14261 case 0x1F2: // xvrdpim (VSX Vector Round to Double-Precision Integer using round toward -Infinity)
14262 case 0x1D2: // xvrdpip (VSX Vector Round to Double-Precision Integer using round toward +Infinity)
14263 case 0x1B2: // xvrdpiz (VSX Vector Round to Double-Precision Integer using round toward Zero)
14264 {
14265 IRTemp frBHi_I64 = newTemp(Ity_I64);
14266 IRTemp frBLo_I64 = newTemp(Ity_I64);
14267 IRExpr * frD_fp_roundHi = NULL;
14268 IRExpr * frD_fp_roundLo = NULL;
sewardje71e56a2011-09-05 12:11:06 +000014269
14270 assign( frBHi_I64, unop( Iop_V128HIto64, getVSReg( XB ) ) );
carll9884af02013-01-30 18:39:57 +000014271 frD_fp_roundHi = _do_vsx_fp_roundToInt(frBHi_I64, opc2);
sewardje71e56a2011-09-05 12:11:06 +000014272 assign( frBLo_I64, unop( Iop_V128to64, getVSReg( XB ) ) );
carll9884af02013-01-30 18:39:57 +000014273 frD_fp_roundLo = _do_vsx_fp_roundToInt(frBLo_I64, opc2);
sewardje71e56a2011-09-05 12:11:06 +000014274
carll9884af02013-01-30 18:39:57 +000014275 DIP("xvrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), (UInt)XT, (UInt)XB);
sewardje71e56a2011-09-05 12:11:06 +000014276 putVSReg( XT,
14277 binop( Iop_64HLtoV128,
14278 unop( Iop_ReinterpF64asI64, frD_fp_roundHi ),
14279 unop( Iop_ReinterpF64asI64, frD_fp_roundLo ) ) );
14280 break;
14281 }
14282 case 0x112: // xvrspi (VSX Vector Round to Single-Precision Integer using round toward Nearest Away)
14283 case 0x156: // xvrspic (VSX Vector Round to SinglePrecision Integer using Current rounding mode)
14284 case 0x172: // xvrspim (VSX Vector Round to SinglePrecision Integer using round toward -Infinity)
14285 case 0x152: // xvrspip (VSX Vector Round to SinglePrecision Integer using round toward +Infinity)
14286 case 0x132: // xvrspiz (VSX Vector Round to SinglePrecision Integer using round toward Zero)
14287 {
florian55085f82012-11-21 00:36:55 +000014288 const HChar * insn_suffix = NULL;
sewardje71e56a2011-09-05 12:11:06 +000014289 IROp op;
14290 if (opc2 != 0x156) {
14291 // Use pre-defined IRop's for vrfi{m|n|p|z}
14292 switch (opc2) {
14293 case 0x112:
14294 insn_suffix = "";
14295 op = Iop_RoundF32x4_RN;
14296 break;
14297 case 0x172:
14298 insn_suffix = "m";
14299 op = Iop_RoundF32x4_RM;
14300 break;
14301 case 0x152:
14302 insn_suffix = "p";
14303 op = Iop_RoundF32x4_RP;
14304 break;
14305 case 0x132:
14306 insn_suffix = "z";
14307 op = Iop_RoundF32x4_RZ;
14308 break;
14309
14310 default:
carll9884af02013-01-30 18:39:57 +000014311 vex_printf("Unrecognized opcode %x\n", opc2);
14312 vpanic("dis_vxv_misc(ppc)(vrspi<x>)(opc2)\n");
sewardje71e56a2011-09-05 12:11:06 +000014313 }
14314 DIP("xvrspi%s v%d,v%d\n", insn_suffix, (UInt)XT, (UInt)XB);
14315 putVSReg( XT, unop( op, getVSReg(XB) ) );
14316 } else {
14317 // Handle xvrspic. Unfortunately there is no corresponding "vfric" instruction.
14318 IRExpr * frD_fp_roundb3, * frD_fp_roundb2, * frD_fp_roundb1, * frD_fp_roundb0;
14319 IRTemp b3_F64, b2_F64, b1_F64, b0_F64;
14320 IRTemp b3_I64 = newTemp(Ity_I64);
14321 IRTemp b2_I64 = newTemp(Ity_I64);
14322 IRTemp b1_I64 = newTemp(Ity_I64);
14323 IRTemp b0_I64 = newTemp(Ity_I64);
14324
14325 b3_F64 = b2_F64 = b1_F64 = b0_F64 = IRTemp_INVALID;
14326 frD_fp_roundb3 = frD_fp_roundb2 = frD_fp_roundb1 = frD_fp_roundb0 = NULL;
14327 breakV128to4xF64( getVSReg(XB), &b3_F64, &b2_F64, &b1_F64, &b0_F64);
14328 assign(b3_I64, unop(Iop_ReinterpF64asI64, mkexpr(b3_F64)));
14329 assign(b2_I64, unop(Iop_ReinterpF64asI64, mkexpr(b2_F64)));
14330 assign(b1_I64, unop(Iop_ReinterpF64asI64, mkexpr(b1_F64)));
14331 assign(b0_I64, unop(Iop_ReinterpF64asI64, mkexpr(b0_F64)));
14332 frD_fp_roundb3 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014333 _do_vsx_fp_roundToInt(b3_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014334 frD_fp_roundb2 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014335 _do_vsx_fp_roundToInt(b2_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014336 frD_fp_roundb1 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014337 _do_vsx_fp_roundToInt(b1_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014338 frD_fp_roundb0 = unop(Iop_TruncF64asF32,
carll9884af02013-01-30 18:39:57 +000014339 _do_vsx_fp_roundToInt(b0_I64, opc2));
sewardje71e56a2011-09-05 12:11:06 +000014340 DIP("xvrspic v%d,v%d\n", (UInt)XT, (UInt)XB);
14341 putVSReg( XT,
14342 binop( Iop_64HLtoV128,
14343 binop( Iop_32HLto64,
14344 unop( Iop_ReinterpF32asI32, frD_fp_roundb3 ),
14345 unop( Iop_ReinterpF32asI32, frD_fp_roundb2 ) ),
14346 binop( Iop_32HLto64,
14347 unop( Iop_ReinterpF32asI32, frD_fp_roundb1 ),
14348 unop( Iop_ReinterpF32asI32, frD_fp_roundb0 ) ) ) );
14349 }
14350 break;
14351 }
sewardj4aa412a2011-07-24 14:13:21 +000014352
14353 default:
14354 vex_printf( "dis_vxv_misc(ppc)(opc2)\n" );
14355 return False;
14356 }
14357 return True;
14358}
14359
14360
14361/*
sewardj66d5ef22011-04-15 11:55:00 +000014362 * VSX Scalar Floating Point Arithmetic Instructions
14363 */
14364static Bool
sewardj4aa412a2011-07-24 14:13:21 +000014365dis_vxs_arith ( UInt theInstr, UInt opc2 )
sewardj66d5ef22011-04-15 11:55:00 +000014366{
14367 /* XX3-Form */
14368 UChar opc1 = ifieldOPC( theInstr );
14369 UChar XT = ifieldRegXT( theInstr );
14370 UChar XA = ifieldRegXA( theInstr );
14371 UChar XB = ifieldRegXB( theInstr );
14372 IRExpr* rm = get_IR_roundingmode();
14373 IRTemp frA = newTemp(Ity_F64);
14374 IRTemp frB = newTemp(Ity_F64);
14375
14376 if (opc1 != 0x3C) {
sewardj4aa412a2011-07-24 14:13:21 +000014377 vex_printf( "dis_vxs_arith(ppc)(instr)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000014378 return False;
14379 }
14380
14381 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
14382 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14383
14384 /* For all the VSX sclar arithmetic instructions, the contents of doubleword element 1
14385 * of VSX[XT] are undefined after the operation; therefore, we can simply set
14386 * element to zero where it makes sense to do so.
14387 */
14388 switch (opc2) {
carll6c758b62013-10-03 21:38:45 +000014389 case 0x000: // xsaddsp (VSX Scalar Add Single-Precision)
14390 DIP("xsaddsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14391 putVSReg( XT, binop( Iop_64HLtoV128,
14392 unop( Iop_ReinterpF64asI64,
14393 binop( Iop_RoundF64toF32, rm,
14394 triop( Iop_AddF64, rm,
14395 mkexpr( frA ),
14396 mkexpr( frB ) ) ) ),
14397 mkU64( 0 ) ) );
14398 break;
14399 case 0x020: // xssubsp (VSX Scalar Subtract Single-Precision)
14400 DIP("xssubsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14401 putVSReg( XT, binop( Iop_64HLtoV128,
14402 unop( Iop_ReinterpF64asI64,
14403 binop( Iop_RoundF64toF32, rm,
14404 triop( Iop_SubF64, rm,
14405 mkexpr( frA ),
14406 mkexpr( frB ) ) ) ),
14407 mkU64( 0 ) ) );
14408 break;
sewardj66d5ef22011-04-15 11:55:00 +000014409 case 0x080: // xsadddp (VSX scalar add double-precision)
14410 DIP("xsadddp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14411 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14412 triop( Iop_AddF64, rm,
14413 mkexpr( frA ),
14414 mkexpr( frB ) ) ),
14415 mkU64( 0 ) ) );
14416 break;
carll6c758b62013-10-03 21:38:45 +000014417 case 0x060: // xsdivsp (VSX scalar divide single-precision)
14418 DIP("xsdivsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14419 putVSReg( XT, binop( Iop_64HLtoV128,
14420 unop( Iop_ReinterpF64asI64,
14421 binop( Iop_RoundF64toF32, rm,
14422 triop( Iop_DivF64, rm,
14423 mkexpr( frA ),
14424 mkexpr( frB ) ) ) ),
14425 mkU64( 0 ) ) );
14426 break;
sewardj66d5ef22011-04-15 11:55:00 +000014427 case 0x0E0: // xsdivdp (VSX scalar divide double-precision)
14428 DIP("xsdivdp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14429 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14430 triop( Iop_DivF64, rm,
14431 mkexpr( frA ),
14432 mkexpr( frB ) ) ),
14433 mkU64( 0 ) ) );
14434 break;
carll6c758b62013-10-03 21:38:45 +000014435 case 0x004: case 0x024: /* xsmaddasp, xsmaddmsp (VSX scalar multiply-add
14436 * single-precision)
14437 */
14438 {
14439 IRTemp frT = newTemp(Ity_F64);
14440 Bool mdp = opc2 == 0x024;
14441 DIP("xsmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14442 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14443 getVSReg( XT ) ) ) );
14444 putVSReg( XT,
14445 binop( Iop_64HLtoV128,
14446 unop( Iop_ReinterpF64asI64,
14447 binop( Iop_RoundF64toF32, rm,
14448 qop( Iop_MAddF64, rm,
14449 mkexpr( frA ),
14450 mkexpr( mdp ? frT : frB ),
14451 mkexpr( mdp ? frB : frT ) ) ) ),
14452 mkU64( 0 ) ) );
14453 break;
14454 }
sewardj66d5ef22011-04-15 11:55:00 +000014455 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp (VSX scalar multiply-add double-precision)
14456 {
14457 IRTemp frT = newTemp(Ity_F64);
14458 Bool mdp = opc2 == 0x0A4;
14459 DIP("xsmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14460 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14461 getVSReg( XT ) ) ) );
14462 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14463 qop( Iop_MAddF64, rm,
14464 mkexpr( frA ),
14465 mkexpr( mdp ? frT : frB ),
14466 mkexpr( mdp ? frB : frT ) ) ),
14467 mkU64( 0 ) ) );
14468 break;
14469 }
carll6c758b62013-10-03 21:38:45 +000014470 case 0x044: case 0x064: /* xsmsubasp, xsmsubmsp (VSX scalar
14471 * multiply-subtract single-precision)
14472 */
14473 {
14474 IRTemp frT = newTemp(Ity_F64);
14475 Bool mdp = opc2 == 0x064;
14476 DIP("xsmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14477 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14478 getVSReg( XT ) ) ) );
14479 putVSReg( XT,
14480 binop( Iop_64HLtoV128,
14481 unop( Iop_ReinterpF64asI64,
14482 binop( Iop_RoundF64toF32, rm,
14483 qop( Iop_MSubF64, rm,
14484 mkexpr( frA ),
14485 mkexpr( mdp ? frT : frB ),
14486 mkexpr( mdp ? frB : frT ) ) ) ),
14487 mkU64( 0 ) ) );
14488 break;
14489 }
sewardj66d5ef22011-04-15 11:55:00 +000014490 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp (VSX scalar multiply-subtract double-precision)
14491 {
14492 IRTemp frT = newTemp(Ity_F64);
14493 Bool mdp = opc2 == 0x0E4;
14494 DIP("xsmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14495 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14496 getVSReg( XT ) ) ) );
14497 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14498 qop( Iop_MSubF64, rm,
14499 mkexpr( frA ),
14500 mkexpr( mdp ? frT : frB ),
14501 mkexpr( mdp ? frB : frT ) ) ),
14502 mkU64( 0 ) ) );
14503 break;
14504 }
14505 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp (VSX scalar multiply-add double-precision)
14506 {
14507 /* TODO: mpj -- Naturally, I expected to be able to leverage the implementation
14508 * of fnmadd and use pretty much the same code. However, that code has a bug in the
14509 * way it blindly negates the signbit, even if the floating point result is a NaN.
14510 * So, the TODO is to fix fnmadd (which I'll do in a different patch).
sewardj2bcdd652012-07-14 08:22:13 +000014511 * FIXED 7/1/2012: carll fnmadd and fnmsubs fixed to not negate sign
14512 * bit for NaN result.
sewardj66d5ef22011-04-15 11:55:00 +000014513 */
sewardj66d5ef22011-04-15 11:55:00 +000014514 Bool mdp = opc2 == 0x2A4;
14515 IRTemp frT = newTemp(Ity_F64);
14516 IRTemp maddResult = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +000014517
14518 DIP("xsnmadd%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14519 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14520 getVSReg( XT ) ) ) );
14521 assign( maddResult, unop( Iop_ReinterpF64asI64, qop( Iop_MAddF64, rm,
14522 mkexpr( frA ),
14523 mkexpr( mdp ? frT : frB ),
14524 mkexpr( mdp ? frB : frT ) ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000014525
sewardj4aa412a2011-07-24 14:13:21 +000014526 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(maddResult) ),
sewardj66d5ef22011-04-15 11:55:00 +000014527 mkU64( 0 ) ) );
14528 break;
14529 }
carll6c758b62013-10-03 21:38:45 +000014530 case 0x204: case 0x224: /* xsnmaddasp, xsnmaddmsp (VSX scalar
14531 * multiply-add single-precision)
14532 */
14533 {
14534 Bool mdp = opc2 == 0x224;
14535 IRTemp frT = newTemp(Ity_F64);
14536 IRTemp maddResult = newTemp(Ity_I64);
14537
14538 DIP("xsnmadd%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14539 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14540 getVSReg( XT ) ) ) );
14541 assign( maddResult,
14542 unop( Iop_ReinterpF64asI64,
14543 binop( Iop_RoundF64toF32, rm,
14544 qop( Iop_MAddF64, rm,
14545 mkexpr( frA ),
14546 mkexpr( mdp ? frT : frB ),
14547 mkexpr( mdp ? frB : frT ) ) ) ) );
14548
14549 putVSReg( XT, binop( Iop_64HLtoV128,
14550 mkexpr( getNegatedResult(maddResult) ),
14551 mkU64( 0 ) ) );
14552 break;
14553 }
14554 case 0x244: case 0x264: /* xsnmsubasp, xsnmsubmsp (VSX Scalar Negative
14555 * Multiply-Subtract Single-Precision)
14556 */
14557 {
14558 IRTemp frT = newTemp(Ity_F64);
14559 Bool mdp = opc2 == 0x264;
14560 IRTemp msubResult = newTemp(Ity_I64);
14561
14562 DIP("xsnmsub%ssp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14563 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14564 getVSReg( XT ) ) ) );
14565 assign( msubResult,
14566 unop( Iop_ReinterpF64asI64,
14567 binop( Iop_RoundF64toF32, rm,
14568 qop( Iop_MSubF64, rm,
14569 mkexpr( frA ),
14570 mkexpr( mdp ? frT : frB ),
14571 mkexpr( mdp ? frB : frT ) ) ) ) );
14572
14573 putVSReg( XT, binop( Iop_64HLtoV128,
14574 mkexpr( getNegatedResult(msubResult) ),
14575 mkU64( 0 ) ) );
14576
14577 break;
14578 }
14579
sewardj4aa412a2011-07-24 14:13:21 +000014580 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp (VSX Scalar Negative Multiply-Subtract Double-Precision)
14581 {
14582 IRTemp frT = newTemp(Ity_F64);
14583 Bool mdp = opc2 == 0x2E4;
14584 IRTemp msubResult = newTemp(Ity_I64);
14585
14586 DIP("xsnmsub%sdp v%d,v%d,v%d\n", mdp ? "m" : "a", (UInt)XT, (UInt)XA, (UInt)XB);
14587 assign( frT, unop( Iop_ReinterpI64asF64, unop( Iop_V128HIto64,
14588 getVSReg( XT ) ) ) );
14589 assign(msubResult, unop( Iop_ReinterpF64asI64,
14590 qop( Iop_MSubF64,
14591 rm,
14592 mkexpr( frA ),
14593 mkexpr( mdp ? frT : frB ),
14594 mkexpr( mdp ? frB : frT ) ) ));
14595
14596 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( getNegatedResult(msubResult) ), mkU64( 0 ) ) );
14597
14598 break;
14599 }
14600
carll6c758b62013-10-03 21:38:45 +000014601 case 0x040: // xsmulsp (VSX Scalar Multiply Single-Precision)
14602 DIP("xsmulsp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14603 putVSReg( XT, binop( Iop_64HLtoV128,
14604 unop( Iop_ReinterpF64asI64,
14605 binop( Iop_RoundF64toF32, rm,
14606 triop( Iop_MulF64, rm,
14607 mkexpr( frA ),
14608 mkexpr( frB ) ) ) ),
14609 mkU64( 0 ) ) );
14610 break;
14611
sewardj66d5ef22011-04-15 11:55:00 +000014612 case 0x0C0: // xsmuldp (VSX Scalar Multiply Double-Precision)
14613 DIP("xsmuldp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14614 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14615 triop( Iop_MulF64, rm,
14616 mkexpr( frA ),
14617 mkexpr( frB ) ) ),
14618 mkU64( 0 ) ) );
14619 break;
14620 case 0x0A0: // xssubdp (VSX Scalar Subtract Double-Precision)
14621 DIP("xssubdp v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
14622 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14623 triop( Iop_SubF64, rm,
14624 mkexpr( frA ),
14625 mkexpr( frB ) ) ),
14626 mkU64( 0 ) ) );
14627 break;
14628
carll6c758b62013-10-03 21:38:45 +000014629 case 0x016: // xssqrtsp (VSX Scalar Square Root Single-Precision)
14630 DIP("xssqrtsp v%d,v%d\n", (UInt)XT, (UInt)XB);
14631 putVSReg( XT,
14632 binop( Iop_64HLtoV128,
14633 unop( Iop_ReinterpF64asI64,
14634 binop( Iop_RoundF64toF32, rm,
14635 binop( Iop_SqrtF64, rm,
14636 mkexpr( frB ) ) ) ),
14637 mkU64( 0 ) ) );
14638 break;
14639
sewardj4aa412a2011-07-24 14:13:21 +000014640 case 0x096: // xssqrtdp (VSX Scalar Square Root Double-Precision)
14641 DIP("xssqrtdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14642 putVSReg( XT, binop( Iop_64HLtoV128, unop( Iop_ReinterpF64asI64,
14643 binop( Iop_SqrtF64, rm,
14644 mkexpr( frB ) ) ),
14645 mkU64( 0 ) ) );
14646 break;
14647
14648 case 0x0F4: // xstdivdp (VSX Scalar Test for software Divide Double-Precision)
14649 {
14650 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
14651 IRTemp frA_I64 = newTemp(Ity_I64);
14652 IRTemp frB_I64 = newTemp(Ity_I64);
14653 DIP("xstdivdp crf%d,v%d,v%d\n", crfD, (UInt)XA, (UInt)XB);
14654 assign( frA_I64, unop( Iop_ReinterpF64asI64, mkexpr( frA ) ) );
14655 assign( frB_I64, unop( Iop_ReinterpF64asI64, mkexpr( frB ) ) );
14656 putGST_field( PPC_GST_CR, do_fp_tdiv(frA_I64, frB_I64), crfD );
14657 break;
14658 }
sewardje71e56a2011-09-05 12:11:06 +000014659 case 0x0D4: // xstsqrtdp (VSX Vector Test for software Square Root Double-Precision)
14660 {
14661 IRTemp frB_I64 = newTemp(Ity_I64);
14662 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
14663 IRTemp flags = newTemp(Ity_I32);
14664 IRTemp fe_flag, fg_flag;
14665 fe_flag = fg_flag = IRTemp_INVALID;
14666 DIP("xstsqrtdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14667 assign( frB_I64, unop(Iop_V128HIto64, getVSReg( XB )) );
14668 do_fp_tsqrt(frB_I64, False /*not single precision*/, &fe_flag, &fg_flag);
14669 /* The CR field consists of fl_flag || fg_flag || fe_flag || 0b0
14670 * where fl_flag == 1 on ppc64.
14671 */
14672 assign( flags,
14673 binop( Iop_Or32,
14674 binop( Iop_Or32, mkU32( 8 ), // fl_flag
14675 binop( Iop_Shl32, mkexpr(fg_flag), mkU8( 2 ) ) ),
14676 binop( Iop_Shl32, mkexpr(fe_flag), mkU8( 1 ) ) ) );
14677 putGST_field( PPC_GST_CR, mkexpr(flags), crfD );
14678 break;
14679 }
sewardj4aa412a2011-07-24 14:13:21 +000014680
sewardj66d5ef22011-04-15 11:55:00 +000014681 default:
sewardj4aa412a2011-07-24 14:13:21 +000014682 vex_printf( "dis_vxs_arith(ppc)(opc2)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000014683 return False;
14684 }
sewardj4aa412a2011-07-24 14:13:21 +000014685
sewardj66d5ef22011-04-15 11:55:00 +000014686 return True;
14687}
14688
sewardj4aa412a2011-07-24 14:13:21 +000014689
sewardj66d5ef22011-04-15 11:55:00 +000014690/*
14691 * VSX Floating Point Compare Instructions
14692 */
14693static Bool
14694dis_vx_cmp( UInt theInstr, UInt opc2 )
14695{
14696 /* XX3-Form and XX2-Form */
14697 UChar opc1 = ifieldOPC( theInstr );
14698 UChar crfD = toUChar( IFIELD( theInstr, 23, 3 ) );
sewardj4aa412a2011-07-24 14:13:21 +000014699 IRTemp ccPPC32;
sewardj66d5ef22011-04-15 11:55:00 +000014700 UChar XA = ifieldRegXA ( theInstr );
14701 UChar XB = ifieldRegXB ( theInstr );
14702 IRTemp frA = newTemp(Ity_F64);
14703 IRTemp frB = newTemp(Ity_F64);
14704
14705 if (opc1 != 0x3C) {
14706 vex_printf( "dis_vx_cmp(ppc)(instr)\n" );
14707 return False;
14708 }
14709
14710 assign(frA, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XA ))));
14711 assign(frB, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, getVSReg( XB ))));
14712 switch (opc2) {
14713 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
14714 /* Note: Differences between xscmpudp and xscmpodp are only in
14715 * exception flag settings, which aren't supported anyway. */
14716 DIP("xscmp%sdp crf%d,fr%u,fr%u\n", opc2 == 0x08c ? "u" : "o",
14717 crfD, (UInt)XA, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000014718 ccPPC32 = get_fp_cmp_CR_val( binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)));
sewardj66d5ef22011-04-15 11:55:00 +000014719 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), crfD );
sewardj66d5ef22011-04-15 11:55:00 +000014720 break;
sewardj4aa412a2011-07-24 14:13:21 +000014721
sewardj66d5ef22011-04-15 11:55:00 +000014722 default:
14723 vex_printf( "dis_vx_cmp(ppc)(opc2)\n" );
14724 return False;
14725 }
14726 return True;
14727}
sewardj4aa412a2011-07-24 14:13:21 +000014728
14729static void
14730do_vvec_fp_cmp ( IRTemp vA, IRTemp vB, UChar XT, UChar flag_rC,
14731 ppc_cmp_t cmp_type )
14732{
14733 IRTemp frA_hi = newTemp(Ity_F64);
14734 IRTemp frB_hi = newTemp(Ity_F64);
14735 IRTemp frA_lo = newTemp(Ity_F64);
14736 IRTemp frB_lo = newTemp(Ity_F64);
14737 IRTemp ccPPC32 = newTemp(Ity_I32);
14738 IRTemp ccIR_hi;
14739 IRTemp ccIR_lo;
14740
14741 IRTemp hiResult = newTemp(Ity_I64);
14742 IRTemp loResult = newTemp(Ity_I64);
14743 IRTemp hiEQlo = newTemp(Ity_I1);
14744 IRTemp all_elem_true = newTemp(Ity_I32);
14745 IRTemp all_elem_false = newTemp(Ity_I32);
14746
14747 assign(frA_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vA ))));
14748 assign(frB_hi, unop(Iop_ReinterpI64asF64, unop(Iop_V128HIto64, mkexpr( vB ))));
14749 assign(frA_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vA ))));
14750 assign(frB_lo, unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, mkexpr( vB ))));
14751
14752 ccIR_hi = get_fp_cmp_CR_val( binop( Iop_CmpF64,
14753 mkexpr( frA_hi ),
14754 mkexpr( frB_hi ) ) );
14755 ccIR_lo = get_fp_cmp_CR_val( binop( Iop_CmpF64,
14756 mkexpr( frA_lo ),
14757 mkexpr( frB_lo ) ) );
14758
14759 if (cmp_type != PPC_CMP_GE) {
14760 assign( hiResult,
14761 unop( Iop_1Sto64,
14762 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( cmp_type ) ) ) );
14763 assign( loResult,
14764 unop( Iop_1Sto64,
14765 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( cmp_type ) ) ) );
14766 } else {
14767 // For PPC_CMP_GE, one element compare may return "4" (for "greater than") and
14768 // the other element compare may return "2" (for "equal to").
14769 IRTemp lo_GE = newTemp(Ity_I1);
14770 IRTemp hi_GE = newTemp(Ity_I1);
14771
14772 assign(hi_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 2 ) ),
14773 binop( Iop_CmpEQ32, mkexpr( ccIR_hi ), mkU32( 4 ) ) ) );
14774 assign( hiResult,unop( Iop_1Sto64, mkexpr( hi_GE ) ) );
14775
14776 assign(lo_GE, mkOR1( binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 2 ) ),
14777 binop( Iop_CmpEQ32, mkexpr( ccIR_lo ), mkU32( 4 ) ) ) );
14778 assign( loResult, unop( Iop_1Sto64, mkexpr( lo_GE ) ) );
14779 }
14780
14781 // The [hi/lo]Result will be all 1's or all 0's. We just look at the lower word.
14782 assign( hiEQlo,
14783 binop( Iop_CmpEQ32,
14784 unop( Iop_64to32, mkexpr( hiResult ) ),
14785 unop( Iop_64to32, mkexpr( loResult ) ) ) );
14786 putVSReg( XT,
14787 binop( Iop_64HLtoV128, mkexpr( hiResult ), mkexpr( loResult ) ) );
14788
14789 assign( all_elem_true,
14790 unop( Iop_1Uto32,
14791 mkAND1( mkexpr( hiEQlo ),
14792 binop( Iop_CmpEQ32,
14793 mkU32( 0xffffffff ),
14794 unop( Iop_64to32,
14795 mkexpr( hiResult ) ) ) ) ) );
14796
14797 assign( all_elem_false,
14798 unop( Iop_1Uto32,
14799 mkAND1( mkexpr( hiEQlo ),
14800 binop( Iop_CmpEQ32,
14801 mkU32( 0 ),
14802 unop( Iop_64to32,
14803 mkexpr( hiResult ) ) ) ) ) );
14804 assign( ccPPC32,
14805 binop( Iop_Or32,
14806 binop( Iop_Shl32, mkexpr( all_elem_false ), mkU8( 1 ) ),
14807 binop( Iop_Shl32, mkexpr( all_elem_true ), mkU8( 3 ) ) ) );
14808
14809 if (flag_rC) {
14810 putGST_field( PPC_GST_CR, mkexpr(ccPPC32), 6 );
14811 }
14812}
14813
sewardj66d5ef22011-04-15 11:55:00 +000014814/*
sewardj4aa412a2011-07-24 14:13:21 +000014815 * VSX Vector Compare Instructions
sewardj66d5ef22011-04-15 11:55:00 +000014816 */
14817static Bool
sewardj4aa412a2011-07-24 14:13:21 +000014818dis_vvec_cmp( UInt theInstr, UInt opc2 )
14819{
14820 /* XX3-Form */
14821 UChar opc1 = ifieldOPC( theInstr );
14822 UChar XT = ifieldRegXT ( theInstr );
14823 UChar XA = ifieldRegXA ( theInstr );
14824 UChar XB = ifieldRegXB ( theInstr );
14825 UChar flag_rC = ifieldBIT10(theInstr);
14826 IRTemp vA = newTemp( Ity_V128 );
14827 IRTemp vB = newTemp( Ity_V128 );
14828
14829 if (opc1 != 0x3C) {
14830 vex_printf( "dis_vvec_cmp(ppc)(instr)\n" );
14831 return False;
14832 }
14833
14834 assign( vA, getVSReg( XA ) );
14835 assign( vB, getVSReg( XB ) );
14836
14837 switch (opc2) {
14838 case 0x18C: case 0x38C: // xvcmpeqdp[.] (VSX Vector Compare Equal To Double-Precision [ & Record ])
14839 {
14840 DIP("xvcmpeqdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14841 (UInt)XT, (UInt)XA, (UInt)XB);
14842 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_EQ);
14843 break;
14844 }
14845
14846 case 0x1CC: case 0x3CC: // xvcmpgedp[.] (VSX Vector Compare Greater Than or Equal To Double-Precision [ & Record ])
14847 {
14848 DIP("xvcmpgedp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14849 (UInt)XT, (UInt)XA, (UInt)XB);
14850 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GE);
14851 break;
14852 }
14853
14854 case 0x1AC: case 0x3AC: // xvcmpgtdp[.] (VSX Vector Compare Greater Than Double-Precision [ & Record ])
14855 {
14856 DIP("xvcmpgtdp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14857 (UInt)XT, (UInt)XA, (UInt)XB);
14858 do_vvec_fp_cmp(vA, vB, XT, flag_rC, PPC_CMP_GT);
14859 break;
14860 }
14861
14862 case 0x10C: case 0x30C: // xvcmpeqsp[.] (VSX Vector Compare Equal To Single-Precision [ & Record ])
14863 {
14864 IRTemp vD = newTemp(Ity_V128);
14865
14866 DIP("xvcmpeqsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14867 (UInt)XT, (UInt)XA, (UInt)XB);
14868 assign( vD, binop(Iop_CmpEQ32Fx4, mkexpr(vA), mkexpr(vB)) );
14869 putVSReg( XT, mkexpr(vD) );
14870 if (flag_rC) {
14871 set_AV_CR6( mkexpr(vD), True );
14872 }
14873 break;
14874 }
14875
14876 case 0x14C: case 0x34C: // xvcmpgesp[.] (VSX Vector Compare Greater Than or Equal To Single-Precision [ & Record ])
14877 {
14878 IRTemp vD = newTemp(Ity_V128);
14879
14880 DIP("xvcmpgesp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14881 (UInt)XT, (UInt)XA, (UInt)XB);
14882 assign( vD, binop(Iop_CmpGE32Fx4, mkexpr(vA), mkexpr(vB)) );
14883 putVSReg( XT, mkexpr(vD) );
14884 if (flag_rC) {
14885 set_AV_CR6( mkexpr(vD), True );
14886 }
14887 break;
14888 }
14889
14890 case 0x12C: case 0x32C: //xvcmpgtsp[.] (VSX Vector Compare Greater Than Single-Precision [ & Record ])
14891 {
14892 IRTemp vD = newTemp(Ity_V128);
14893
14894 DIP("xvcmpgtsp%s crf%d,fr%u,fr%u\n", (flag_rC ? ".":""),
14895 (UInt)XT, (UInt)XA, (UInt)XB);
14896 assign( vD, binop(Iop_CmpGT32Fx4, mkexpr(vA), mkexpr(vB)) );
14897 putVSReg( XT, mkexpr(vD) );
14898 if (flag_rC) {
14899 set_AV_CR6( mkexpr(vD), True );
14900 }
14901 break;
14902 }
14903
14904 default:
14905 vex_printf( "dis_vvec_cmp(ppc)(opc2)\n" );
14906 return False;
14907 }
14908 return True;
14909}
14910/*
14911 * Miscellaneous VSX Scalar Instructions
14912 */
14913static Bool
14914dis_vxs_misc( UInt theInstr, UInt opc2 )
sewardj66d5ef22011-04-15 11:55:00 +000014915{
carll1f5fe1f2014-08-07 23:25:23 +000014916#define VG_PPC_SIGN_MASK 0x7fffffffffffffffULL
sewardj66d5ef22011-04-15 11:55:00 +000014917 /* XX3-Form and XX2-Form */
14918 UChar opc1 = ifieldOPC( theInstr );
14919 UChar XT = ifieldRegXT ( theInstr );
14920 UChar XA = ifieldRegXA ( theInstr );
14921 UChar XB = ifieldRegXB ( theInstr );
14922 IRTemp vA = newTemp( Ity_V128 );
14923 IRTemp vB = newTemp( Ity_V128 );
14924
14925 if (opc1 != 0x3C) {
sewardj4aa412a2011-07-24 14:13:21 +000014926 vex_printf( "dis_vxs_misc(ppc)(instr)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000014927 return False;
14928 }
14929
14930 assign( vA, getVSReg( XA ) );
14931 assign( vB, getVSReg( XB ) );
14932
14933 /* For all the VSX move instructions, the contents of doubleword element 1
14934 * of VSX[XT] are undefined after the operation; therefore, we can simply
14935 * move the entire array element where it makes sense to do so.
14936 */
14937
14938 switch (opc2) {
14939 case 0x2B2: // xsabsdp (VSX scalar absolute value double-precision
14940 {
14941 /* Move abs val of dw 0 of VSX[XB] to dw 0 of VSX[XT]. */
14942 IRTemp absVal = newTemp(Ity_V128);
carll1f5fe1f2014-08-07 23:25:23 +000014943 if (host_endness == VexEndnessLE) {
14944 IRTemp hi64 = newTemp(Ity_I64);
14945 IRTemp lo64 = newTemp(Ity_I64);
14946 assign( hi64, unop( Iop_V128HIto64, mkexpr(vB) ) );
14947 assign( lo64, unop( Iop_V128to64, mkexpr(vB) ) );
14948 assign( absVal, binop( Iop_64HLtoV128,
14949 binop( Iop_And64, mkexpr(hi64),
14950 mkU64(VG_PPC_SIGN_MASK) ),
14951 mkexpr(lo64) ) );
14952 } else {
14953 assign(absVal, binop(Iop_ShrV128,
14954 binop(Iop_ShlV128, mkexpr(vB),
14955 mkU8(1)), mkU8(1)));
14956 }
sewardj66d5ef22011-04-15 11:55:00 +000014957 DIP("xsabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
14958 putVSReg(XT, mkexpr(absVal));
14959 break;
14960 }
14961 case 0x2C0: // xscpsgndp
14962 {
14963 /* Scalar copy sign double-precision */
carll1f5fe1f2014-08-07 23:25:23 +000014964 IRTemp vecA_signed = newTemp(Ity_I64);
14965 IRTemp vecB_unsigned = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +000014966 IRTemp vec_result = newTemp(Ity_V128);
14967 DIP("xscpsgndp v%d,v%d v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
carll1f5fe1f2014-08-07 23:25:23 +000014968 assign( vecA_signed, binop( Iop_And64,
14969 unop( Iop_V128HIto64,
14970 mkexpr(vA)),
14971 mkU64(~VG_PPC_SIGN_MASK) ) );
14972 assign( vecB_unsigned, binop( Iop_And64,
14973 unop( Iop_V128HIto64,
14974 mkexpr(vB) ),
14975 mkU64(VG_PPC_SIGN_MASK) ) );
14976 assign( vec_result, binop( Iop_64HLtoV128,
14977 binop( Iop_Or64,
14978 mkexpr(vecA_signed),
14979 mkexpr(vecB_unsigned) ),
14980 mkU64(0x0ULL)));
sewardj66d5ef22011-04-15 11:55:00 +000014981 putVSReg(XT, mkexpr(vec_result));
14982 break;
14983 }
14984 case 0x2D2: // xsnabsdp
14985 {
14986 /* Scalar negative absolute value double-precision */
carll1f5fe1f2014-08-07 23:25:23 +000014987 IRTemp BHi_signed = newTemp(Ity_I64);
sewardj66d5ef22011-04-15 11:55:00 +000014988 DIP("xsnabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
carll1f5fe1f2014-08-07 23:25:23 +000014989 assign( BHi_signed, binop( Iop_Or64,
14990 unop( Iop_V128HIto64,
14991 mkexpr(vB) ),
14992 mkU64(~VG_PPC_SIGN_MASK) ) );
14993 putVSReg(XT, binop( Iop_64HLtoV128,
14994 mkexpr(BHi_signed), mkU64(0x0ULL) ) );
sewardj66d5ef22011-04-15 11:55:00 +000014995 break;
14996 }
14997 case 0x2F2: // xsnegdp
14998 {
14999 /* Scalar negate double-precision */
carll1f5fe1f2014-08-07 23:25:23 +000015000 IRTemp BHi_signed = newTemp(Ity_I64);
15001 IRTemp BHi_unsigned = newTemp(Ity_I64);
15002 IRTemp BHi_negated = newTemp(Ity_I64);
15003 IRTemp BHi_negated_signbit = newTemp(Ity_I1);
15004 IRTemp vec_result = newTemp(Ity_V128);
sewardj66d5ef22011-04-15 11:55:00 +000015005 DIP("xsnabsdp v%d,v%d\n", (UInt)XT, (UInt)XB);
carll1f5fe1f2014-08-07 23:25:23 +000015006 assign( BHi_signed, unop( Iop_V128HIto64, mkexpr(vB) ) );
15007 assign( BHi_unsigned, binop( Iop_And64, mkexpr(BHi_signed),
15008 mkU64(VG_PPC_SIGN_MASK) ) );
15009 assign( BHi_negated_signbit,
15010 unop( Iop_Not1,
15011 unop( Iop_32to1,
15012 binop( Iop_Shr32,
15013 unop( Iop_64HIto32,
15014 binop( Iop_And64,
15015 mkexpr(BHi_signed),
15016 mkU64(~VG_PPC_SIGN_MASK) )
15017 ),
15018 mkU8(31) ) ) ) );
15019 assign( BHi_negated,
15020 binop( Iop_Or64,
15021 binop( Iop_32HLto64,
15022 binop( Iop_Shl32,
15023 unop( Iop_1Uto32,
15024 mkexpr(BHi_negated_signbit) ),
15025 mkU8(31) ),
15026 mkU32(0) ),
15027 mkexpr(BHi_unsigned) ) );
15028 assign( vec_result, binop( Iop_64HLtoV128, mkexpr(BHi_negated),
15029 mkU64(0x0ULL)));
15030 putVSReg( XT, mkexpr(vec_result));
sewardj66d5ef22011-04-15 11:55:00 +000015031 break;
15032 }
sewardj4aa412a2011-07-24 14:13:21 +000015033 case 0x280: // xsmaxdp (VSX Scalar Maximum Double-Precision)
15034 case 0x2A0: // xsmindp (VSX Scalar Minimum Double-Precision)
15035 {
15036 IRTemp frA = newTemp(Ity_I64);
15037 IRTemp frB = newTemp(Ity_I64);
15038 Bool isMin = opc2 == 0x2A0 ? True : False;
15039 DIP("%s v%d,v%d v%d\n", isMin ? "xsmaxdp" : "xsmindp", (UInt)XT, (UInt)XA, (UInt)XB);
15040
15041 assign(frA, unop(Iop_V128HIto64, mkexpr( vA )));
15042 assign(frB, unop(Iop_V128HIto64, mkexpr( vB )));
15043 putVSReg( XT, binop( Iop_64HLtoV128, get_max_min_fp(frA, frB, isMin), mkU64( 0 ) ) );
15044
15045 break;
15046 }
15047 case 0x0F2: // xsrdpim (VSX Scalar Round to Double-Precision Integer using round toward -Infinity)
sewardje71e56a2011-09-05 12:11:06 +000015048 case 0x0D2: // xsrdpip (VSX Scalar Round to Double-Precision Integer using round toward +Infinity)
15049 case 0x0D6: // xsrdpic (VSX Scalar Round to Double-Precision Integer using Current rounding mode)
15050 case 0x0B2: // xsrdpiz (VSX Scalar Round to Double-Precision Integer using round toward Zero)
15051 case 0x092: // xsrdpi (VSX Scalar Round to Double-Precision Integer using round toward Nearest Away)
sewardj4aa412a2011-07-24 14:13:21 +000015052 {
sewardj4aa412a2011-07-24 14:13:21 +000015053 IRTemp frB_I64 = newTemp(Ity_I64);
sewardje71e56a2011-09-05 12:11:06 +000015054 IRExpr * frD_fp_round = NULL;
sewardje71e56a2011-09-05 12:11:06 +000015055
sewardj4aa412a2011-07-24 14:13:21 +000015056 assign(frB_I64, unop(Iop_V128HIto64, mkexpr( vB )));
carll9884af02013-01-30 18:39:57 +000015057 frD_fp_round = _do_vsx_fp_roundToInt(frB_I64, opc2);
sewardj4aa412a2011-07-24 14:13:21 +000015058
carll9884af02013-01-30 18:39:57 +000015059 DIP("xsrdpi%s v%d,v%d\n", _get_vsx_rdpi_suffix(opc2), (UInt)XT, (UInt)XB);
sewardj4aa412a2011-07-24 14:13:21 +000015060 putVSReg( XT,
15061 binop( Iop_64HLtoV128,
sewardje71e56a2011-09-05 12:11:06 +000015062 unop( Iop_ReinterpF64asI64, frD_fp_round),
sewardj4aa412a2011-07-24 14:13:21 +000015063 mkU64( 0 ) ) );
sewardje71e56a2011-09-05 12:11:06 +000015064 break;
15065 }
carll6c758b62013-10-03 21:38:45 +000015066 case 0x034: // xsresp (VSX Scalar Reciprocal Estimate single-Precision)
15067 case 0x014: /* xsrsqrtesp (VSX Scalar Reciprocal Square Root Estimate
15068 * single-Precision)
15069 */
15070 {
15071 IRTemp frB = newTemp(Ity_F64);
15072 IRTemp sqrt = newTemp(Ity_F64);
15073 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
15074 IRExpr* rm = get_IR_roundingmode();
15075 Bool redp = opc2 == 0x034;
15076 DIP("%s v%d,v%d\n", redp ? "xsresp" : "xsrsqrtesp", (UInt)XT,
15077 (UInt)XB);
15078
15079 assign( frB,
15080 unop( Iop_ReinterpI64asF64,
15081 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
15082
15083 if (!redp)
15084 assign( sqrt,
15085 binop( Iop_SqrtF64,
15086 rm,
15087 mkexpr(frB) ) );
15088 putVSReg( XT,
15089 binop( Iop_64HLtoV128,
15090 unop( Iop_ReinterpF64asI64,
15091 binop( Iop_RoundF64toF32, rm,
15092 triop( Iop_DivF64,
15093 rm,
15094 ieee_one,
15095 redp ? mkexpr( frB ) :
15096 mkexpr( sqrt ) ) ) ),
15097 mkU64( 0 ) ) );
15098 break;
15099 }
15100
sewardje71e56a2011-09-05 12:11:06 +000015101 case 0x0B4: // xsredp (VSX Scalar Reciprocal Estimate Double-Precision)
15102 case 0x094: // xsrsqrtedp (VSX Scalar Reciprocal Square Root Estimate Double-Precision)
sewardj4aa412a2011-07-24 14:13:21 +000015103
sewardje71e56a2011-09-05 12:11:06 +000015104 {
15105 IRTemp frB = newTemp(Ity_F64);
15106 IRTemp sqrt = newTemp(Ity_F64);
15107 IRExpr* ieee_one = IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL));
15108 IRExpr* rm = get_IR_roundingmode();
15109 Bool redp = opc2 == 0x0B4;
15110 DIP("%s v%d,v%d\n", redp ? "xsredp" : "xsrsqrtedp", (UInt)XT, (UInt)XB);
15111 assign( frB,
15112 unop( Iop_ReinterpI64asF64,
15113 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
15114
15115 if (!redp)
15116 assign( sqrt,
15117 binop( Iop_SqrtF64,
15118 rm,
15119 mkexpr(frB) ) );
15120 putVSReg( XT,
15121 binop( Iop_64HLtoV128,
15122 unop( Iop_ReinterpF64asI64,
15123 triop( Iop_DivF64,
15124 rm,
15125 ieee_one,
15126 redp ? mkexpr( frB ) : mkexpr( sqrt ) ) ),
15127 mkU64( 0 ) ) );
sewardj4aa412a2011-07-24 14:13:21 +000015128 break;
15129 }
sewardj66d5ef22011-04-15 11:55:00 +000015130
carll6c758b62013-10-03 21:38:45 +000015131 case 0x232: // xsrsp (VSX Scalar Round to Single-Precision)
15132 {
15133 IRTemp frB = newTemp(Ity_F64);
15134 IRExpr* rm = get_IR_roundingmode();
15135 DIP("xsrsp v%d, v%d\n", (UInt)XT, (UInt)XB);
15136 assign( frB,
15137 unop( Iop_ReinterpI64asF64,
15138 unop( Iop_V128HIto64, mkexpr( vB ) ) ) );
15139
15140 putVSReg( XT, binop( Iop_64HLtoV128,
15141 unop( Iop_ReinterpF64asI64,
15142 binop( Iop_RoundF64toF32,
15143 rm,
15144 mkexpr( frB ) ) ),
15145 mkU64( 0 ) ) );
15146 break;
15147 }
15148
sewardj66d5ef22011-04-15 11:55:00 +000015149 default:
sewardj4aa412a2011-07-24 14:13:21 +000015150 vex_printf( "dis_vxs_misc(ppc)(opc2)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000015151 return False;
15152 }
15153 return True;
15154}
15155
15156/*
15157 * VSX Logical Instructions
15158 */
15159static Bool
15160dis_vx_logic ( UInt theInstr, UInt opc2 )
15161{
15162 /* XX3-Form */
15163 UChar opc1 = ifieldOPC( theInstr );
15164 UChar XT = ifieldRegXT ( theInstr );
15165 UChar XA = ifieldRegXA ( theInstr );
15166 UChar XB = ifieldRegXB ( theInstr );
15167 IRTemp vA = newTemp( Ity_V128 );
15168 IRTemp vB = newTemp( Ity_V128 );
15169
15170 if (opc1 != 0x3C) {
15171 vex_printf( "dis_vx_logic(ppc)(instr)\n" );
15172 return False;
15173 }
15174
15175 assign( vA, getVSReg( XA ) );
15176 assign( vB, getVSReg( XB ) );
15177
15178 switch (opc2) {
15179 case 0x268: // xxlxor
15180 DIP("xxlxor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15181 putVSReg( XT, binop( Iop_XorV128, mkexpr( vA ), mkexpr( vB ) ) );
15182 break;
15183 case 0x248: // xxlor
15184 DIP("xxlor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15185 putVSReg( XT, binop( Iop_OrV128, mkexpr( vA ), mkexpr( vB ) ) );
15186 break;
15187 case 0x288: // xxlnor
15188 DIP("xxlnor v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15189 putVSReg( XT, unop( Iop_NotV128, binop( Iop_OrV128, mkexpr( vA ),
15190 mkexpr( vB ) ) ) );
15191 break;
15192 case 0x208: // xxland
15193 DIP("xxland v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15194 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), mkexpr( vB ) ) );
15195 break;
15196 case 0x228: //xxlandc
15197 DIP("xxlandc v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15198 putVSReg( XT, binop( Iop_AndV128, mkexpr( vA ), unop( Iop_NotV128,
15199 mkexpr( vB ) ) ) );
15200 break;
carll6c758b62013-10-03 21:38:45 +000015201 case 0x2A8: // xxlorc (VSX Logical OR with complement)
15202 DIP("xxlorc v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15203 putVSReg( XT, binop( Iop_OrV128,
15204 mkexpr( vA ),
15205 unop( Iop_NotV128, mkexpr( vB ) ) ) );
15206 break;
15207 case 0x2C8: // xxlnand (VSX Logical NAND)
15208 DIP("xxlnand v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15209 putVSReg( XT, unop( Iop_NotV128,
15210 binop( Iop_AndV128, mkexpr( vA ),
15211 mkexpr( vB ) ) ) );
15212 break;
15213 case 0x2E8: // xxleqv (VSX Logical Equivalence)
15214 DIP("xxleqv v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB);
15215 putVSReg( XT, unop( Iop_NotV128,
15216 binop( Iop_XorV128,
15217 mkexpr( vA ), mkexpr( vB ) ) ) );
15218 break;
sewardj66d5ef22011-04-15 11:55:00 +000015219 default:
15220 vex_printf( "dis_vx_logic(ppc)(opc2)\n" );
15221 return False;
15222 }
15223 return True;
15224}
15225
15226/*
15227 * VSX Load Instructions
15228 * NOTE: VSX supports word-aligned storage access.
15229 */
15230static Bool
15231dis_vx_load ( UInt theInstr )
15232{
15233 /* XX1-Form */
15234 UChar opc1 = ifieldOPC( theInstr );
15235 UChar XT = ifieldRegXT ( theInstr );
15236 UChar rA_addr = ifieldRegA( theInstr );
15237 UChar rB_addr = ifieldRegB( theInstr );
15238 UInt opc2 = ifieldOPClo10( theInstr );
15239
15240 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15241 IRTemp EA = newTemp( ty );
15242
15243 if (opc1 != 0x1F) {
15244 vex_printf( "dis_vx_load(ppc)(instr)\n" );
15245 return False;
15246 }
15247
15248 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
15249
15250 switch (opc2) {
carll6c758b62013-10-03 21:38:45 +000015251 case 0x00C: // lxsiwzx (Load VSX Scalar as Integer Word and Zero Indexed)
15252 {
15253 IRExpr * exp;
15254 DIP("lxsiwzx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015255 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
carll6c758b62013-10-03 21:38:45 +000015256 putVSReg( XT, binop( Iop_64HLtoV128,
15257 unop( Iop_32Uto64, exp),
15258 mkU64(0) ) );
15259 break;
15260 }
15261 case 0x04C: // lxsiwax (Load VSX Scalar as Integer Word Algebraic Indexed)
15262 {
15263 IRExpr * exp;
15264 DIP("lxsiwax %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015265 exp = unop( Iop_64HIto32, load( Ity_I64, mkexpr( EA ) ) );
carll6c758b62013-10-03 21:38:45 +000015266 putVSReg( XT, binop( Iop_64HLtoV128,
15267 unop( Iop_32Sto64, exp),
15268 mkU64(0) ) );
15269 break;
15270 }
15271 case 0x20C: // lxsspx (Load VSX Scalar Single-Precision Indexed)
15272 {
15273 IRExpr * exp;
15274 DIP("lxsspx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
15275 /* Take 32-bit floating point value in the upper half of the fetched
15276 * 64-bit value, convert to 64-bit floating point value and load into
15277 * top word of V128.
15278 */
15279 exp = unop( Iop_ReinterpF64asI64,
15280 unop( Iop_F32toF64,
15281 unop( Iop_ReinterpI32asF32,
carll1f5fe1f2014-08-07 23:25:23 +000015282 load( Ity_I32, mkexpr( EA ) ) ) ) );
carll6c758b62013-10-03 21:38:45 +000015283
15284 putVSReg( XT, binop( Iop_64HLtoV128, exp, mkU64( 0 ) ) );
15285 break;
15286 }
sewardj66d5ef22011-04-15 11:55:00 +000015287 case 0x24C: // lxsdx
15288 {
15289 IRExpr * exp;
15290 DIP("lxsdx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015291 exp = load( Ity_I64, mkexpr( EA ) );
sewardj66d5ef22011-04-15 11:55:00 +000015292 // We need to pass an expression of type Ity_V128 with putVSReg, but the load
15293 // we just performed is only a DW. But since the contents of VSR[XT] element 1
15294 // are undefined after this operation, we can just do a splat op.
15295 putVSReg( XT, binop( Iop_64HLtoV128, exp, exp ) );
15296 break;
15297 }
15298 case 0x34C: // lxvd2x
15299 {
15300 IROp addOp = ty == Ity_I64 ? Iop_Add64 : Iop_Add32;
15301 IRExpr * high, *low;
15302 ULong ea_off = 8;
15303 IRExpr* high_addr;
15304 DIP("lxvd2x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015305 high = load( Ity_I64, mkexpr( EA ) );
sewardj66d5ef22011-04-15 11:55:00 +000015306 high_addr = binop( addOp, mkexpr( EA ), ty == Ity_I64 ? mkU64( ea_off )
15307 : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015308 low = load( Ity_I64, high_addr );
sewardj66d5ef22011-04-15 11:55:00 +000015309 putVSReg( XT, binop( Iop_64HLtoV128, high, low ) );
15310 break;
15311 }
15312 case 0x14C: // lxvdsx
15313 {
15314 IRTemp data = newTemp(Ity_I64);
15315 DIP("lxvdsx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015316 assign( data, load( Ity_I64, mkexpr( EA ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015317 putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( data ), mkexpr( data ) ) );
15318 break;
15319 }
15320 case 0x30C:
15321 {
carll4e303f22014-09-29 19:33:00 +000015322 IRExpr *t0;
sewardj66d5ef22011-04-15 11:55:00 +000015323
15324 DIP("lxvw4x %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
carll4e303f22014-09-29 19:33:00 +000015325
carll85175a72014-10-09 21:08:25 +000015326 /* The load will result in the data being in BE order. */
15327 if (host_endness == VexEndnessLE) {
15328 IRExpr *t0_BE;
15329 IRTemp perm_LE = newTemp(Ity_V128);
15330
15331 t0_BE = load( Ity_V128, mkexpr( EA ) );
15332
15333 /* Permute the data to LE format */
15334 assign( perm_LE, binop( Iop_64HLtoV128, mkU64(0x0c0d0e0f08090a0b),
15335 mkU64(0x0405060700010203)));
15336
15337 t0 = binop( Iop_Perm8x16, t0_BE, mkexpr(perm_LE) );
15338 } else {
15339 t0 = load( Ity_V128, mkexpr( EA ) );
15340 }
15341
carll4e303f22014-09-29 19:33:00 +000015342 putVSReg( XT, t0 );
sewardj66d5ef22011-04-15 11:55:00 +000015343 break;
15344 }
15345 default:
15346 vex_printf( "dis_vx_load(ppc)(opc2)\n" );
15347 return False;
15348 }
15349 return True;
15350}
15351
15352/*
15353 * VSX Store Instructions
15354 * NOTE: VSX supports word-aligned storage access.
15355 */
15356static Bool
15357dis_vx_store ( UInt theInstr )
15358{
15359 /* XX1-Form */
15360 UChar opc1 = ifieldOPC( theInstr );
15361 UChar XS = ifieldRegXS( theInstr );
15362 UChar rA_addr = ifieldRegA( theInstr );
15363 UChar rB_addr = ifieldRegB( theInstr );
15364 IRTemp vS = newTemp( Ity_V128 );
15365 UInt opc2 = ifieldOPClo10( theInstr );
15366
15367 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15368 IRTemp EA = newTemp( ty );
15369
15370 if (opc1 != 0x1F) {
15371 vex_printf( "dis_vx_store(ppc)(instr)\n" );
15372 return False;
15373 }
15374
15375 assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
15376 assign( vS, getVSReg( XS ) );
15377
15378 switch (opc2) {
carll6c758b62013-10-03 21:38:45 +000015379 case 0x08C:
15380 {
15381 /* Need the next to the most significant 32-bit word from
15382 * the 128-bit vector.
15383 */
15384 IRExpr * high64, * low32;
15385 DIP("stxsiwx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15386 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
15387 low32 = unop( Iop_64to32, high64 );
carll1f5fe1f2014-08-07 23:25:23 +000015388 store( mkexpr( EA ), low32 );
carll6c758b62013-10-03 21:38:45 +000015389 break;
15390 }
15391 case 0x28C:
15392 {
15393 IRTemp high64 = newTemp(Ity_F64);
15394 IRTemp val32 = newTemp(Ity_I32);
15395 DIP("stxsspx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15396 assign(high64, unop( Iop_ReinterpI64asF64,
15397 unop( Iop_V128HIto64, mkexpr( vS ) ) ) );
15398 assign(val32, unop( Iop_ReinterpF32asI32,
15399 unop( Iop_TruncF64asF32,
15400 mkexpr(high64) ) ) );
carll1f5fe1f2014-08-07 23:25:23 +000015401 store( mkexpr( EA ), mkexpr( val32 ) );
carll6c758b62013-10-03 21:38:45 +000015402 break;
15403 }
sewardj66d5ef22011-04-15 11:55:00 +000015404 case 0x2CC:
15405 {
15406 IRExpr * high64;
15407 DIP("stxsdx %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15408 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
carll1f5fe1f2014-08-07 23:25:23 +000015409 store( mkexpr( EA ), high64 );
sewardj66d5ef22011-04-15 11:55:00 +000015410 break;
15411 }
15412 case 0x3CC:
15413 {
15414 IRExpr * high64, *low64;
15415 DIP("stxvd2x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15416 high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
15417 low64 = unop( Iop_V128to64, mkexpr( vS ) );
carll1f5fe1f2014-08-07 23:25:23 +000015418 store( mkexpr( EA ), high64 );
15419 store( binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15420 ty == Ity_I64 ? mkU64( 8 ) : mkU32( 8 ) ), low64 );
sewardj66d5ef22011-04-15 11:55:00 +000015421 break;
15422 }
15423 case 0x38C:
15424 {
15425 UInt ea_off = 0;
15426 IRExpr* irx_addr;
15427 IRTemp hi64 = newTemp( Ity_I64 );
15428 IRTemp lo64 = newTemp( Ity_I64 );
15429
15430 DIP("stxvw4x %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
15431
15432 // This instruction supports word-aligned stores, so EA may not be
15433 // quad-word aligned. Therefore, do 4 individual word-size stores.
15434 assign( hi64, unop( Iop_V128HIto64, mkexpr( vS ) ) );
15435 assign( lo64, unop( Iop_V128to64, mkexpr( vS ) ) );
carll1f5fe1f2014-08-07 23:25:23 +000015436 store( mkexpr( EA ), unop( Iop_64HIto32, mkexpr( hi64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015437 ea_off += 4;
15438 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15439 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015440 store( irx_addr, unop( Iop_64to32, mkexpr( hi64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015441 ea_off += 4;
15442 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15443 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015444 store( irx_addr, unop( Iop_64HIto32, mkexpr( lo64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015445 ea_off += 4;
15446 irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( EA ),
15447 ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
carll1f5fe1f2014-08-07 23:25:23 +000015448 store( irx_addr, unop( Iop_64to32, mkexpr( lo64 ) ) );
sewardj66d5ef22011-04-15 11:55:00 +000015449
15450 break;
15451 }
15452 default:
15453 vex_printf( "dis_vx_store(ppc)(opc2)\n" );
15454 return False;
15455 }
15456 return True;
15457}
15458
15459/*
sewardj4aa412a2011-07-24 14:13:21 +000015460 * VSX permute and other miscealleous instructions
sewardj66d5ef22011-04-15 11:55:00 +000015461 */
15462static Bool
sewardj4aa412a2011-07-24 14:13:21 +000015463dis_vx_permute_misc( UInt theInstr, UInt opc2 )
sewardj66d5ef22011-04-15 11:55:00 +000015464{
15465 /* XX3-Form */
15466 UChar opc1 = ifieldOPC( theInstr );
15467 UChar XT = ifieldRegXT ( theInstr );
15468 UChar XA = ifieldRegXA ( theInstr );
15469 UChar XB = ifieldRegXB ( theInstr );
15470 IRTemp vT = newTemp( Ity_V128 );
15471 IRTemp vA = newTemp( Ity_V128 );
15472 IRTemp vB = newTemp( Ity_V128 );
15473
15474 if (opc1 != 0x3C) {
sewardj4aa412a2011-07-24 14:13:21 +000015475 vex_printf( "dis_vx_permute_misc(ppc)(instr)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000015476 return False;
15477 }
15478
15479 assign( vA, getVSReg( XA ) );
15480 assign( vB, getVSReg( XB ) );
15481
15482 switch (opc2) {
15483 case 0x8: // xxsldwi (VSX Shift Left Double by Word Immediate)
15484 {
15485 UChar SHW = ifieldSHW ( theInstr );
15486 IRTemp result = newTemp(Ity_V128);
15487 if ( SHW != 0 ) {
15488 IRTemp hi = newTemp(Ity_V128);
15489 IRTemp lo = newTemp(Ity_V128);
15490 assign( hi, binop(Iop_ShlV128, mkexpr(vA), mkU8(SHW*32)) );
15491 assign( lo, binop(Iop_ShrV128, mkexpr(vB), mkU8(128-SHW*32)) );
15492 assign ( result, binop(Iop_OrV128, mkexpr(hi), mkexpr(lo)) );
15493 } else
15494 assign ( result, mkexpr(vA) );
15495 DIP("xxsldwi v%d,v%d,v%d,%d\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)SHW);
15496 putVSReg( XT, mkexpr(result) );
15497 break;
15498 }
15499 case 0x28: // xpermdi (VSX Permute Doubleword Immediate)
15500 {
15501 UChar DM = ifieldDM ( theInstr );
15502 IRTemp hi = newTemp(Ity_I64);
15503 IRTemp lo = newTemp(Ity_I64);
15504
15505 if (DM & 0x2)
15506 assign( hi, unop(Iop_V128to64, mkexpr(vA)) );
15507 else
15508 assign( hi, unop(Iop_V128HIto64, mkexpr(vA)) );
15509
15510 if (DM & 0x1)
15511 assign( lo, unop(Iop_V128to64, mkexpr(vB)) );
15512 else
15513 assign( lo, unop(Iop_V128HIto64, mkexpr(vB)) );
15514
15515 assign( vT, binop(Iop_64HLtoV128, mkexpr(hi), mkexpr(lo)) );
15516
15517 DIP("xxpermdi v%d,v%d,v%d,0x%x\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)DM);
15518 putVSReg( XT, mkexpr( vT ) );
15519 break;
15520 }
15521 case 0x48: // xxmrghw (VSX Merge High Word)
15522 case 0xc8: // xxmrglw (VSX Merge Low Word)
15523 {
florian55085f82012-11-21 00:36:55 +000015524 const HChar type = (opc2 == 0x48) ? 'h' : 'l';
sewardj66d5ef22011-04-15 11:55:00 +000015525 IROp word_op = (opc2 == 0x48) ? Iop_V128HIto64 : Iop_V128to64;
15526 IRTemp a64 = newTemp(Ity_I64);
15527 IRTemp ahi32 = newTemp(Ity_I32);
15528 IRTemp alo32 = newTemp(Ity_I32);
15529 IRTemp b64 = newTemp(Ity_I64);
15530 IRTemp bhi32 = newTemp(Ity_I32);
15531 IRTemp blo32 = newTemp(Ity_I32);
15532
15533 assign( a64, unop(word_op, mkexpr(vA)) );
15534 assign( ahi32, unop(Iop_64HIto32, mkexpr(a64)) );
15535 assign( alo32, unop(Iop_64to32, mkexpr(a64)) );
15536
15537 assign( b64, unop(word_op, mkexpr(vB)) );
15538 assign( bhi32, unop(Iop_64HIto32, mkexpr(b64)) );
15539 assign( blo32, unop(Iop_64to32, mkexpr(b64)) );
15540
15541 assign( vT, binop(Iop_64HLtoV128,
15542 binop(Iop_32HLto64, mkexpr(ahi32), mkexpr(bhi32)),
15543 binop(Iop_32HLto64, mkexpr(alo32), mkexpr(blo32))) );
15544
15545 DIP("xxmrg%cw v%d,v%d,v%d\n", type, (UInt)XT, (UInt)XA, (UInt)XB);
15546 putVSReg( XT, mkexpr( vT ) );
15547 break;
15548 }
sewardj4aa412a2011-07-24 14:13:21 +000015549 case 0x018: // xxsel (VSX Select)
15550 {
15551 UChar XC = ifieldRegXC(theInstr);
15552 IRTemp vC = newTemp( Ity_V128 );
15553 assign( vC, getVSReg( XC ) );
15554 DIP("xxsel v%d,v%d,v%d,v%d\n", (UInt)XT, (UInt)XA, (UInt)XB, (UInt)XC);
15555 /* vD = (vA & ~vC) | (vB & vC) */
15556 putVSReg( XT, binop(Iop_OrV128,
15557 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
15558 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
15559 break;
15560 }
15561 case 0x148: // xxspltw (VSX Splat Word)
15562 {
15563 UChar UIM = ifieldRegA(theInstr) & 3;
15564 UChar sh_uim = (3 - (UIM)) * 32;
15565 DIP("xxspltw v%d,v%d,%d\n", (UInt)XT, (UInt)XB, UIM);
15566 putVSReg( XT,
15567 unop( Iop_Dup32x4,
15568 unop( Iop_V128to32,
15569 binop( Iop_ShrV128, mkexpr( vB ), mkU8( sh_uim ) ) ) ) );
15570 break;
15571 }
sewardj66d5ef22011-04-15 11:55:00 +000015572
15573 default:
sewardj4aa412a2011-07-24 14:13:21 +000015574 vex_printf( "dis_vx_permute_misc(ppc)(opc2)\n" );
sewardj66d5ef22011-04-15 11:55:00 +000015575 return False;
15576 }
15577 return True;
15578}
15579
15580/*
ceriona982c052005-06-28 17:23:09 +000015581 AltiVec Load Instructions
15582*/
sewardjdd40fdf2006-12-24 02:20:24 +000015583static Bool dis_av_load ( VexAbiInfo* vbi, UInt theInstr )
ceriona982c052005-06-28 17:23:09 +000015584{
cerion76de5cf2005-11-18 18:25:12 +000015585 /* X-Form */
15586 UChar opc1 = ifieldOPC(theInstr);
15587 UChar vD_addr = ifieldRegDS(theInstr);
15588 UChar rA_addr = ifieldRegA(theInstr);
15589 UChar rB_addr = ifieldRegB(theInstr);
15590 UInt opc2 = ifieldOPClo10(theInstr);
15591 UChar b0 = ifieldBIT0(theInstr);
ceriona982c052005-06-28 17:23:09 +000015592
cerionfb197c42005-12-24 12:32:10 +000015593 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15594 IRTemp EA = newTemp(ty);
15595 IRTemp EA_align16 = newTemp(ty);
cerion2831b002005-11-30 19:55:22 +000015596
ceriona982c052005-06-28 17:23:09 +000015597 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000015598 vex_printf("dis_av_load(ppc)(instr)\n");
ceriona982c052005-06-28 17:23:09 +000015599 return False;
15600 }
15601
cerionfb197c42005-12-24 12:32:10 +000015602 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
15603 assign( EA_align16, addr_align( mkexpr(EA), 16 ) );
ceriona50fde52005-07-01 21:16:10 +000015604
ceriona982c052005-06-28 17:23:09 +000015605 switch (opc2) {
15606
cerion6f6c6a02005-09-13 18:41:09 +000015607 case 0x006: { // lvsl (Load Vector for Shift Left, AV p123)
cerionfb197c42005-12-24 12:32:10 +000015608 IRDirty* d;
sewardjd1470942005-10-22 02:01:16 +000015609 UInt vD_off = vectorGuestRegOffset(vD_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015610 IRExpr** args_be = mkIRExprVec_5(
florian90419562013-08-15 20:54:52 +000015611 IRExpr_BBPTR(),
carll1f5fe1f2014-08-07 23:25:23 +000015612 mkU32(vD_off),
sewardje9d8a262009-07-01 08:06:34 +000015613 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
cerionfb197c42005-12-24 12:32:10 +000015614 mkU32(0xF)),
carll1f5fe1f2014-08-07 23:25:23 +000015615 mkU32(0)/*left*/,
15616 mkU32(1)/*Big Endian*/);
15617 IRExpr** args_le = mkIRExprVec_5(
15618 IRExpr_BBPTR(),
15619 mkU32(vD_off),
15620 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
15621 mkU32(0xF)),
15622 mkU32(0)/*left*/,
15623 mkU32(0)/*Little Endian*/);
cerion5b2325f2005-12-23 00:55:09 +000015624 if (!mode64) {
cerion4c4f5ef2006-01-02 14:41:50 +000015625 d = unsafeIRDirty_0_N (
15626 0/*regparms*/,
15627 "ppc32g_dirtyhelper_LVS",
sewardjdd40fdf2006-12-24 02:20:24 +000015628 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
carll1f5fe1f2014-08-07 23:25:23 +000015629 args_be );
cerion5b2325f2005-12-23 00:55:09 +000015630 } else {
carll1f5fe1f2014-08-07 23:25:23 +000015631 if (host_endness == VexEndnessBE)
15632 d = unsafeIRDirty_0_N (
15633 0/*regparms*/,
15634 "ppc64g_dirtyhelper_LVS",
15635 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
15636 args_be );
15637 else
15638 d = unsafeIRDirty_0_N (
15639 0/*regparms*/,
15640 "ppc64g_dirtyhelper_LVS",
15641 &ppc64g_dirtyhelper_LVS,
15642 args_le );
cerion5b2325f2005-12-23 00:55:09 +000015643 }
ceriond953ebb2005-11-29 13:27:20 +000015644 DIP("lvsl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion6f6c6a02005-09-13 18:41:09 +000015645 /* declare guest state effects */
cerion6f6c6a02005-09-13 18:41:09 +000015646 d->nFxState = 1;
sewardjc9069f22012-06-01 16:09:50 +000015647 vex_bzero(&d->fxState, sizeof(d->fxState));
cerion6f6c6a02005-09-13 18:41:09 +000015648 d->fxState[0].fx = Ifx_Write;
sewardjd1470942005-10-22 02:01:16 +000015649 d->fxState[0].offset = vD_off;
cerion6f6c6a02005-09-13 18:41:09 +000015650 d->fxState[0].size = sizeof(U128);
cerion32aad402005-09-10 12:02:24 +000015651
cerion6f6c6a02005-09-13 18:41:09 +000015652 /* execute the dirty call, side-effecting guest state */
15653 stmt( IRStmt_Dirty(d) );
15654 break;
15655 }
15656 case 0x026: { // lvsr (Load Vector for Shift Right, AV p125)
cerionfb197c42005-12-24 12:32:10 +000015657 IRDirty* d;
sewardjd1470942005-10-22 02:01:16 +000015658 UInt vD_off = vectorGuestRegOffset(vD_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015659 IRExpr** args_be = mkIRExprVec_5(
15660 IRExpr_BBPTR(),
15661 mkU32(vD_off),
15662 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
15663 mkU32(0xF)),
15664 mkU32(1)/*right*/,
15665 mkU32(1)/*Big Endian*/);
15666 IRExpr** args_le = mkIRExprVec_5(
15667 IRExpr_BBPTR(),
15668 mkU32(vD_off),
15669 binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
15670 mkU32(0xF)),
15671 mkU32(1)/*right*/,
15672 mkU32(0)/*Little Endian*/);
15673
cerion5b2325f2005-12-23 00:55:09 +000015674 if (!mode64) {
cerion4c4f5ef2006-01-02 14:41:50 +000015675 d = unsafeIRDirty_0_N (
carll1f5fe1f2014-08-07 23:25:23 +000015676 0/*regparms*/,
cerion4c4f5ef2006-01-02 14:41:50 +000015677 "ppc32g_dirtyhelper_LVS",
sewardjdd40fdf2006-12-24 02:20:24 +000015678 fnptr_to_fnentry(vbi, &ppc32g_dirtyhelper_LVS),
carll1f5fe1f2014-08-07 23:25:23 +000015679 args_be );
cerion5b2325f2005-12-23 00:55:09 +000015680 } else {
carll1f5fe1f2014-08-07 23:25:23 +000015681 if (host_endness == VexEndnessBE)
15682 d = unsafeIRDirty_0_N (
15683 0/*regparms*/,
15684 "ppc64g_dirtyhelper_LVS",
15685 fnptr_to_fnentry(vbi, &ppc64g_dirtyhelper_LVS),
15686 args_be );
15687 else
15688 d = unsafeIRDirty_0_N (
15689 0/*regparms*/,
15690 "ppc64g_dirtyhelper_LVS",
15691 &ppc64g_dirtyhelper_LVS,
15692 args_le );
cerion5b2325f2005-12-23 00:55:09 +000015693 }
ceriond953ebb2005-11-29 13:27:20 +000015694 DIP("lvsr v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion6f6c6a02005-09-13 18:41:09 +000015695 /* declare guest state effects */
cerion6f6c6a02005-09-13 18:41:09 +000015696 d->nFxState = 1;
sewardjc9069f22012-06-01 16:09:50 +000015697 vex_bzero(&d->fxState, sizeof(d->fxState));
cerion6f6c6a02005-09-13 18:41:09 +000015698 d->fxState[0].fx = Ifx_Write;
sewardjd1470942005-10-22 02:01:16 +000015699 d->fxState[0].offset = vD_off;
cerion6f6c6a02005-09-13 18:41:09 +000015700 d->fxState[0].size = sizeof(U128);
cerion32aad402005-09-10 12:02:24 +000015701
cerion6f6c6a02005-09-13 18:41:09 +000015702 /* execute the dirty call, side-effecting guest state */
15703 stmt( IRStmt_Dirty(d) );
15704 break;
15705 }
cerion32aad402005-09-10 12:02:24 +000015706 case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119)
ceriond953ebb2005-11-29 13:27:20 +000015707 DIP("lvebx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015708 /* loads addressed byte into vector[EA[0:3]
15709 since all other destination bytes are undefined,
15710 can simply load entire vector from 16-aligned EA */
carll1f5fe1f2014-08-07 23:25:23 +000015711 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
cerion61c92742005-09-14 22:59:26 +000015712 break;
cerion32aad402005-09-10 12:02:24 +000015713
15714 case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121)
ceriond953ebb2005-11-29 13:27:20 +000015715 DIP("lvehx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015716 /* see note for lvebx */
carll1f5fe1f2014-08-07 23:25:23 +000015717 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
cerion61c92742005-09-14 22:59:26 +000015718 break;
cerion32aad402005-09-10 12:02:24 +000015719
15720 case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122)
ceriond953ebb2005-11-29 13:27:20 +000015721 DIP("lvewx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015722 /* see note for lvebx */
carll1f5fe1f2014-08-07 23:25:23 +000015723 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
cerion61c92742005-09-14 22:59:26 +000015724 break;
ceriona982c052005-06-28 17:23:09 +000015725
15726 case 0x067: // lvx (Load Vector Indexed, AV p127)
ceriond953ebb2005-11-29 13:27:20 +000015727 DIP("lvx v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015728 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
ceriona50fde52005-07-01 21:16:10 +000015729 break;
ceriona982c052005-06-28 17:23:09 +000015730
cerion32aad402005-09-10 12:02:24 +000015731 case 0x167: // lvxl (Load Vector Indexed LRU, AV p128)
ceriond953ebb2005-11-29 13:27:20 +000015732 DIP("lvxl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015733 putVReg( vD_addr, load(Ity_V128, mkexpr(EA_align16)) );
sewardjd2fd8642006-12-27 21:21:14 +000015734 break;
ceriona982c052005-06-28 17:23:09 +000015735
15736 default:
cerion5b2325f2005-12-23 00:55:09 +000015737 vex_printf("dis_av_load(ppc)(opc2)\n");
ceriona982c052005-06-28 17:23:09 +000015738 return False;
15739 }
15740 return True;
15741}
15742
15743/*
15744 AltiVec Store Instructions
15745*/
15746static Bool dis_av_store ( UInt theInstr )
15747{
cerion76de5cf2005-11-18 18:25:12 +000015748 /* X-Form */
15749 UChar opc1 = ifieldOPC(theInstr);
15750 UChar vS_addr = ifieldRegDS(theInstr);
15751 UChar rA_addr = ifieldRegA(theInstr);
15752 UChar rB_addr = ifieldRegB(theInstr);
15753 UInt opc2 = ifieldOPClo10(theInstr);
15754 UChar b0 = ifieldBIT0(theInstr);
ceriona982c052005-06-28 17:23:09 +000015755
cerion2831b002005-11-30 19:55:22 +000015756 IRType ty = mode64 ? Ity_I64 : Ity_I32;
15757 IRTemp EA = newTemp(ty);
ceriondba87e22006-01-02 15:15:45 +000015758 IRTemp addr_aligned = newTemp(ty);
cerion2831b002005-11-30 19:55:22 +000015759 IRTemp vS = newTemp(Ity_V128);
15760 IRTemp eb = newTemp(Ity_I8);
15761 IRTemp idx = newTemp(Ity_I8);
ceriona982c052005-06-28 17:23:09 +000015762
15763 if (opc1 != 0x1F || b0 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000015764 vex_printf("dis_av_store(ppc)(instr)\n");
ceriona982c052005-06-28 17:23:09 +000015765 return False;
15766 }
15767
ceriond953ebb2005-11-29 13:27:20 +000015768 assign( vS, getVReg(vS_addr));
cerion2831b002005-11-30 19:55:22 +000015769 assign( EA, ea_rAor0_idxd(rA_addr, rB_addr) );
ceriond953ebb2005-11-29 13:27:20 +000015770
ceriona982c052005-06-28 17:23:09 +000015771 switch (opc2) {
cerion61c92742005-09-14 22:59:26 +000015772 case 0x087: { // stvebx (Store Vector Byte Indexed, AV p131)
ceriond953ebb2005-11-29 13:27:20 +000015773 DIP("stvebx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +000015774 assign( eb, binop(Iop_And8, mkU8(0xF),
cerion2831b002005-11-30 19:55:22 +000015775 unop(Iop_32to8,
sewardje9d8a262009-07-01 08:06:34 +000015776 mkNarrowTo32(ty, mkexpr(EA)) )) );
carll1f5fe1f2014-08-07 23:25:23 +000015777 if (host_endness == VexEndnessLE) {
15778 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
15779 } else {
15780 assign( idx, binop(Iop_Shl8,
15781 binop(Iop_Sub8, mkU8(15), mkexpr(eb)),
15782 mkU8(3)) );
15783 }
15784 store( mkexpr(EA),
15785 unop( Iop_32to8, unop(Iop_V128to32,
15786 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
cerion61c92742005-09-14 22:59:26 +000015787 break;
15788 }
15789 case 0x0A7: { // stvehx (Store Vector Half Word Indexed, AV p132)
ceriond953ebb2005-11-29 13:27:20 +000015790 DIP("stvehx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
ceriondba87e22006-01-02 15:15:45 +000015791 assign( addr_aligned, addr_align(mkexpr(EA), 2) );
cerion61c92742005-09-14 22:59:26 +000015792 assign( eb, binop(Iop_And8, mkU8(0xF),
sewardje9d8a262009-07-01 08:06:34 +000015793 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
carll1f5fe1f2014-08-07 23:25:23 +000015794 if (host_endness == VexEndnessLE) {
15795 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
15796 } else {
15797 assign( idx, binop(Iop_Shl8,
15798 binop(Iop_Sub8, mkU8(14), mkexpr(eb)),
15799 mkU8(3)) );
15800 }
15801 store( mkexpr(addr_aligned),
15802 unop( Iop_32to16, unop(Iop_V128to32,
15803 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
cerion61c92742005-09-14 22:59:26 +000015804 break;
15805 }
15806 case 0x0C7: { // stvewx (Store Vector Word Indexed, AV p133)
ceriond953ebb2005-11-29 13:27:20 +000015807 DIP("stvewx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
ceriondba87e22006-01-02 15:15:45 +000015808 assign( addr_aligned, addr_align(mkexpr(EA), 4) );
cerion61c92742005-09-14 22:59:26 +000015809 assign( eb, binop(Iop_And8, mkU8(0xF),
sewardje9d8a262009-07-01 08:06:34 +000015810 mkNarrowTo8(ty, mkexpr(addr_aligned) )) );
carll1f5fe1f2014-08-07 23:25:23 +000015811 if (host_endness == VexEndnessLE) {
15812 assign( idx, binop(Iop_Shl8, mkexpr(eb), mkU8(3)) );
15813 } else {
15814 assign( idx, binop(Iop_Shl8,
15815 binop(Iop_Sub8, mkU8(12), mkexpr(eb)),
15816 mkU8(3)) );
15817 }
15818 store( mkexpr( addr_aligned),
15819 unop( Iop_V128to32,
15820 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx))) );
cerion61c92742005-09-14 22:59:26 +000015821 break;
15822 }
cerion32aad402005-09-10 12:02:24 +000015823
ceriona982c052005-06-28 17:23:09 +000015824 case 0x0E7: // stvx (Store Vector Indexed, AV p134)
ceriond953ebb2005-11-29 13:27:20 +000015825 DIP("stvx v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015826 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
ceriona982c052005-06-28 17:23:09 +000015827 break;
15828
cerion32aad402005-09-10 12:02:24 +000015829 case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135)
ceriond953ebb2005-11-29 13:27:20 +000015830 DIP("stvxl v%d,r%u,r%u\n", vS_addr, rA_addr, rB_addr);
carll1f5fe1f2014-08-07 23:25:23 +000015831 store( addr_align( mkexpr(EA), 16 ), mkexpr(vS) );
sewardjd2fd8642006-12-27 21:21:14 +000015832 break;
ceriona982c052005-06-28 17:23:09 +000015833
15834 default:
cerion5b2325f2005-12-23 00:55:09 +000015835 vex_printf("dis_av_store(ppc)(opc2)\n");
ceriona982c052005-06-28 17:23:09 +000015836 return False;
15837 }
15838 return True;
15839}
15840
cerion32aad402005-09-10 12:02:24 +000015841/*
15842 AltiVec Arithmetic Instructions
15843*/
15844static Bool dis_av_arith ( UInt theInstr )
15845{
cerion76de5cf2005-11-18 18:25:12 +000015846 /* VX-Form */
15847 UChar opc1 = ifieldOPC(theInstr);
15848 UChar vD_addr = ifieldRegDS(theInstr);
15849 UChar vA_addr = ifieldRegA(theInstr);
15850 UChar vB_addr = ifieldRegB(theInstr);
15851 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000015852
ceriond3e52412005-09-14 21:15:40 +000015853 IRTemp vA = newTemp(Ity_V128);
15854 IRTemp vB = newTemp(Ity_V128);
cerion4a49b032005-11-08 16:23:07 +000015855 IRTemp z3 = newTemp(Ity_I64);
15856 IRTemp z2 = newTemp(Ity_I64);
15857 IRTemp z1 = newTemp(Ity_I64);
15858 IRTemp z0 = newTemp(Ity_I64);
15859 IRTemp aEvn, aOdd;
15860 IRTemp a15, a14, a13, a12, a11, a10, a9, a8;
15861 IRTemp a7, a6, a5, a4, a3, a2, a1, a0;
15862 IRTemp b3, b2, b1, b0;
15863
15864 aEvn = aOdd = IRTemp_INVALID;
15865 a15 = a14 = a13 = a12 = a11 = a10 = a9 = a8 = IRTemp_INVALID;
15866 a7 = a6 = a5 = a4 = a3 = a2 = a1 = a0 = IRTemp_INVALID;
15867 b3 = b2 = b1 = b0 = IRTemp_INVALID;
15868
ceriond3e52412005-09-14 21:15:40 +000015869 assign( vA, getVReg(vA_addr));
15870 assign( vB, getVReg(vB_addr));
15871
cerion32aad402005-09-10 12:02:24 +000015872 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000015873 vex_printf("dis_av_arith(ppc)(opc1 != 0x4)\n");
cerion32aad402005-09-10 12:02:24 +000015874 return False;
15875 }
15876
15877 switch (opc2) {
15878 /* Add */
ceriond3e52412005-09-14 21:15:40 +000015879 case 0x180: { // vaddcuw (Add Carryout Unsigned Word, AV p136)
cerion32aad402005-09-10 12:02:24 +000015880 DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015881 /* unsigned_ov(x+y) = (y >u not(x)) */
ceriond3e52412005-09-14 21:15:40 +000015882 putVReg( vD_addr, binop(Iop_ShrN32x4,
cerion36991ef2005-09-15 12:42:16 +000015883 binop(Iop_CmpGT32Ux4, mkexpr(vB),
15884 unop(Iop_NotV128, mkexpr(vA))),
ceriond3e52412005-09-14 21:15:40 +000015885 mkU8(31)) );
15886 break;
15887 }
cerion32aad402005-09-10 12:02:24 +000015888 case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
15889 DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015890 putVReg( vD_addr, binop(Iop_Add8x16, mkexpr(vA), mkexpr(vB)) );
15891 break;
15892
cerion32aad402005-09-10 12:02:24 +000015893 case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143)
15894 DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015895 putVReg( vD_addr, binop(Iop_Add16x8, mkexpr(vA), mkexpr(vB)) );
15896 break;
15897
cerion32aad402005-09-10 12:02:24 +000015898 case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145)
15899 DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015900 putVReg( vD_addr, binop(Iop_Add32x4, mkexpr(vA), mkexpr(vB)) );
15901 break;
15902
carll0c74bb52013-08-12 18:01:40 +000015903 case 0x0C0: // vaddudm (Add Unsigned Double Word Modulo)
15904 DIP("vaddudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
15905 putVReg( vD_addr, binop(Iop_Add64x2, mkexpr(vA), mkexpr(vB)) );
15906 break;
15907
cerion32aad402005-09-10 12:02:24 +000015908 case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
15909 DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015910 putVReg( vD_addr, binop(Iop_QAdd8Ux16, mkexpr(vA), mkexpr(vB)) );
15911 // TODO: set VSCR[SAT], perhaps via new primop: Iop_SatOfQAdd8Ux16
15912 break;
15913
cerion32aad402005-09-10 12:02:24 +000015914 case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144)
15915 DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015916 putVReg( vD_addr, binop(Iop_QAdd16Ux8, mkexpr(vA), mkexpr(vB)) );
15917 // TODO: set VSCR[SAT]
15918 break;
15919
cerion32aad402005-09-10 12:02:24 +000015920 case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146)
15921 DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015922 putVReg( vD_addr, binop(Iop_QAdd32Ux4, mkexpr(vA), mkexpr(vB)) );
15923 // TODO: set VSCR[SAT]
15924 break;
15925
cerion32aad402005-09-10 12:02:24 +000015926 case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138)
15927 DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015928 putVReg( vD_addr, binop(Iop_QAdd8Sx16, mkexpr(vA), mkexpr(vB)) );
15929 // TODO: set VSCR[SAT]
15930 break;
15931
cerion32aad402005-09-10 12:02:24 +000015932 case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139)
15933 DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015934 putVReg( vD_addr, binop(Iop_QAdd16Sx8, mkexpr(vA), mkexpr(vB)) );
15935 // TODO: set VSCR[SAT]
15936 break;
15937
cerion32aad402005-09-10 12:02:24 +000015938 case 0x380: // vaddsws (Add Signed Word Saturate, AV p140)
15939 DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015940 putVReg( vD_addr, binop(Iop_QAdd32Sx4, mkexpr(vA), mkexpr(vB)) );
15941 // TODO: set VSCR[SAT]
15942 break;
15943
15944
cerion32aad402005-09-10 12:02:24 +000015945 /* Subtract */
cerion36991ef2005-09-15 12:42:16 +000015946 case 0x580: { // vsubcuw (Subtract Carryout Unsigned Word, AV p260)
cerion32aad402005-09-10 12:02:24 +000015947 DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015948 /* unsigned_ov(x-y) = (y >u x) */
15949 putVReg( vD_addr, binop(Iop_ShrN32x4,
15950 unop(Iop_NotV128,
15951 binop(Iop_CmpGT32Ux4, mkexpr(vB),
15952 mkexpr(vA))),
15953 mkU8(31)) );
15954 break;
15955 }
cerion32aad402005-09-10 12:02:24 +000015956 case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265)
15957 DIP("vsububm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015958 putVReg( vD_addr, binop(Iop_Sub8x16, mkexpr(vA), mkexpr(vB)) );
15959 break;
15960
cerion32aad402005-09-10 12:02:24 +000015961 case 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267)
15962 DIP("vsubuhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015963 putVReg( vD_addr, binop(Iop_Sub16x8, mkexpr(vA), mkexpr(vB)) );
15964 break;
15965
cerion32aad402005-09-10 12:02:24 +000015966 case 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269)
15967 DIP("vsubuwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015968 putVReg( vD_addr, binop(Iop_Sub32x4, mkexpr(vA), mkexpr(vB)) );
15969 break;
15970
carll48ae46b2013-10-01 15:45:54 +000015971 case 0x4C0: // vsubudm (Subtract Unsigned Double Word Modulo)
15972 DIP("vsubudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
15973 putVReg( vD_addr, binop(Iop_Sub64x2, mkexpr(vA), mkexpr(vB)) );
15974 break;
15975
cerion32aad402005-09-10 12:02:24 +000015976 case 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266)
15977 DIP("vsububs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015978 putVReg( vD_addr, binop(Iop_QSub8Ux16, mkexpr(vA), mkexpr(vB)) );
15979 // TODO: set VSCR[SAT]
15980 break;
15981
cerion5b2325f2005-12-23 00:55:09 +000015982 case 0x640: // vsubuhs (Subtract Unsigned HWord Saturate, AV p268)
cerion32aad402005-09-10 12:02:24 +000015983 DIP("vsubuhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015984 putVReg( vD_addr, binop(Iop_QSub16Ux8, mkexpr(vA), mkexpr(vB)) );
15985 // TODO: set VSCR[SAT]
15986 break;
15987
cerion32aad402005-09-10 12:02:24 +000015988 case 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270)
15989 DIP("vsubuws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015990 putVReg( vD_addr, binop(Iop_QSub32Ux4, mkexpr(vA), mkexpr(vB)) );
15991 // TODO: set VSCR[SAT]
15992 break;
15993
cerion32aad402005-09-10 12:02:24 +000015994 case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262)
15995 DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000015996 putVReg( vD_addr, binop(Iop_QSub8Sx16, mkexpr(vA), mkexpr(vB)) );
15997 // TODO: set VSCR[SAT]
15998 break;
15999
cerion32aad402005-09-10 12:02:24 +000016000 case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263)
16001 DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016002 putVReg( vD_addr, binop(Iop_QSub16Sx8, mkexpr(vA), mkexpr(vB)) );
16003 // TODO: set VSCR[SAT]
16004 break;
16005
cerion32aad402005-09-10 12:02:24 +000016006 case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264)
16007 DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016008 putVReg( vD_addr, binop(Iop_QSub32Sx4, mkexpr(vA), mkexpr(vB)) );
16009 // TODO: set VSCR[SAT]
16010 break;
cerion32aad402005-09-10 12:02:24 +000016011
16012
16013 /* Maximum */
16014 case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182)
16015 DIP("vmaxub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016016 putVReg( vD_addr, binop(Iop_Max8Ux16, mkexpr(vA), mkexpr(vB)) );
16017 break;
cerion32aad402005-09-10 12:02:24 +000016018
16019 case 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183)
16020 DIP("vmaxuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016021 putVReg( vD_addr, binop(Iop_Max16Ux8, mkexpr(vA), mkexpr(vB)) );
16022 break;
cerion32aad402005-09-10 12:02:24 +000016023
16024 case 0x082: // vmaxuw (Maximum Unsigned Word, AV p184)
16025 DIP("vmaxuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016026 putVReg( vD_addr, binop(Iop_Max32Ux4, mkexpr(vA), mkexpr(vB)) );
16027 break;
cerion32aad402005-09-10 12:02:24 +000016028
carll48ae46b2013-10-01 15:45:54 +000016029 case 0x0C2: // vmaxud (Maximum Unsigned Double word)
16030 DIP("vmaxud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16031 putVReg( vD_addr, binop(Iop_Max64Ux2, mkexpr(vA), mkexpr(vB)) );
16032 break;
16033
cerion32aad402005-09-10 12:02:24 +000016034 case 0x102: // vmaxsb (Maximum Signed Byte, AV p179)
16035 DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016036 putVReg( vD_addr, binop(Iop_Max8Sx16, mkexpr(vA), mkexpr(vB)) );
16037 break;
cerion32aad402005-09-10 12:02:24 +000016038
16039 case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180)
16040 DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016041 putVReg( vD_addr, binop(Iop_Max16Sx8, mkexpr(vA), mkexpr(vB)) );
16042 break;
cerion32aad402005-09-10 12:02:24 +000016043
16044 case 0x182: // vmaxsw (Maximum Signed Word, AV p181)
16045 DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016046 putVReg( vD_addr, binop(Iop_Max32Sx4, mkexpr(vA), mkexpr(vB)) );
16047 break;
cerion32aad402005-09-10 12:02:24 +000016048
carll48ae46b2013-10-01 15:45:54 +000016049 case 0x1C2: // vmaxsd (Maximum Signed Double word)
16050 DIP("vmaxsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16051 putVReg( vD_addr, binop(Iop_Max64Sx2, mkexpr(vA), mkexpr(vB)) );
16052 break;
cerion32aad402005-09-10 12:02:24 +000016053
16054 /* Minimum */
16055 case 0x202: // vminub (Minimum Unsigned Byte, AV p191)
16056 DIP("vminub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016057 putVReg( vD_addr, binop(Iop_Min8Ux16, mkexpr(vA), mkexpr(vB)) );
16058 break;
cerion32aad402005-09-10 12:02:24 +000016059
16060 case 0x242: // vminuh (Minimum Unsigned Half Word, AV p192)
16061 DIP("vminuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016062 putVReg( vD_addr, binop(Iop_Min16Ux8, mkexpr(vA), mkexpr(vB)) );
16063 break;
cerion32aad402005-09-10 12:02:24 +000016064
16065 case 0x282: // vminuw (Minimum Unsigned Word, AV p193)
16066 DIP("vminuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016067 putVReg( vD_addr, binop(Iop_Min32Ux4, mkexpr(vA), mkexpr(vB)) );
16068 break;
cerion32aad402005-09-10 12:02:24 +000016069
carll48ae46b2013-10-01 15:45:54 +000016070 case 0x2C2: // vminud (Minimum Unsigned Double Word)
16071 DIP("vminud v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16072 putVReg( vD_addr, binop(Iop_Min64Ux2, mkexpr(vA), mkexpr(vB)) );
16073 break;
16074
cerion32aad402005-09-10 12:02:24 +000016075 case 0x302: // vminsb (Minimum Signed Byte, AV p188)
16076 DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016077 putVReg( vD_addr, binop(Iop_Min8Sx16, mkexpr(vA), mkexpr(vB)) );
16078 break;
cerion32aad402005-09-10 12:02:24 +000016079
16080 case 0x342: // vminsh (Minimum Signed Half Word, AV p189)
16081 DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016082 putVReg( vD_addr, binop(Iop_Min16Sx8, mkexpr(vA), mkexpr(vB)) );
16083 break;
cerion32aad402005-09-10 12:02:24 +000016084
16085 case 0x382: // vminsw (Minimum Signed Word, AV p190)
16086 DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016087 putVReg( vD_addr, binop(Iop_Min32Sx4, mkexpr(vA), mkexpr(vB)) );
16088 break;
16089
carll48ae46b2013-10-01 15:45:54 +000016090 case 0x3C2: // vminsd (Minimum Signed Double Word)
16091 DIP("vminsd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16092 putVReg( vD_addr, binop(Iop_Min64Sx2, mkexpr(vA), mkexpr(vB)) );
16093 break;
16094
cerion32aad402005-09-10 12:02:24 +000016095
16096 /* Average */
16097 case 0x402: // vavgub (Average Unsigned Byte, AV p152)
16098 DIP("vavgub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016099 putVReg( vD_addr, binop(Iop_Avg8Ux16, mkexpr(vA), mkexpr(vB)) );
16100 break;
cerion32aad402005-09-10 12:02:24 +000016101
16102 case 0x442: // vavguh (Average Unsigned Half Word, AV p153)
16103 DIP("vavguh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016104 putVReg( vD_addr, binop(Iop_Avg16Ux8, mkexpr(vA), mkexpr(vB)) );
16105 break;
cerion32aad402005-09-10 12:02:24 +000016106
16107 case 0x482: // vavguw (Average Unsigned Word, AV p154)
16108 DIP("vavguw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016109 putVReg( vD_addr, binop(Iop_Avg32Ux4, mkexpr(vA), mkexpr(vB)) );
16110 break;
cerion32aad402005-09-10 12:02:24 +000016111
16112 case 0x502: // vavgsb (Average Signed Byte, AV p149)
16113 DIP("vavgsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016114 putVReg( vD_addr, binop(Iop_Avg8Sx16, mkexpr(vA), mkexpr(vB)) );
16115 break;
cerion32aad402005-09-10 12:02:24 +000016116
16117 case 0x542: // vavgsh (Average Signed Half Word, AV p150)
16118 DIP("vavgsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016119 putVReg( vD_addr, binop(Iop_Avg16Sx8, mkexpr(vA), mkexpr(vB)) );
16120 break;
cerion32aad402005-09-10 12:02:24 +000016121
16122 case 0x582: // vavgsw (Average Signed Word, AV p151)
16123 DIP("vavgsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +000016124 putVReg( vD_addr, binop(Iop_Avg32Sx4, mkexpr(vA), mkexpr(vB)) );
16125 break;
cerion32aad402005-09-10 12:02:24 +000016126
16127
16128 /* Multiply */
16129 case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213)
16130 DIP("vmuloub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016131 putVReg( vD_addr,
16132 binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016133 break;
cerion32aad402005-09-10 12:02:24 +000016134
16135 case 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214)
16136 DIP("vmulouh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016137 putVReg( vD_addr,
16138 binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016139 break;
cerion32aad402005-09-10 12:02:24 +000016140
carll48ae46b2013-10-01 15:45:54 +000016141 case 0x088: // vmulouw (Multiply Odd Unsigned Word)
16142 DIP("vmulouw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16143 putVReg( vD_addr, binop( Iop_MullEven32Ux4, mkexpr(vA), mkexpr(vB) ) );
16144 break;
16145
16146 case 0x089: // vmuluwm (Multiply Unsigned Word Modulo)
16147 DIP("vmuluwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16148 putVReg( vD_addr, binop( Iop_Mul32x4, mkexpr(vA), mkexpr(vB) ) );
16149 break;
16150
cerion32aad402005-09-10 12:02:24 +000016151 case 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211)
16152 DIP("vmulosb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016153 putVReg( vD_addr,
16154 binop(Iop_MullEven8Sx16, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016155 break;
cerion32aad402005-09-10 12:02:24 +000016156
16157 case 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212)
16158 DIP("vmulosh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000016159 putVReg( vD_addr,
16160 binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)));
cerion36991ef2005-09-15 12:42:16 +000016161 break;
cerion32aad402005-09-10 12:02:24 +000016162
carll48ae46b2013-10-01 15:45:54 +000016163 case 0x188: // vmulosw (Multiply Odd Signed Word)
16164 DIP("vmulosw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16165 putVReg( vD_addr, binop( Iop_MullEven32Sx4, mkexpr(vA), mkexpr(vB) ) );
16166 break;
16167
cerion32aad402005-09-10 12:02:24 +000016168 case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209)
16169 DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016170 putVReg( vD_addr, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
cerion36991ef2005-09-15 12:42:16 +000016171 break;
cerion32aad402005-09-10 12:02:24 +000016172
16173 case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210)
16174 DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016175 putVReg( vD_addr, MK_Iop_MullOdd16Ux8( mkexpr(vA), mkexpr(vB) ));
cerion36991ef2005-09-15 12:42:16 +000016176 break;
cerion32aad402005-09-10 12:02:24 +000016177
carll48ae46b2013-10-01 15:45:54 +000016178 case 0x288: // vmuleuw (Multiply Even Unsigned Word)
16179 DIP("vmuleuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16180 putVReg( vD_addr, MK_Iop_MullOdd32Ux4( mkexpr(vA), mkexpr(vB) ) );
16181 break;
16182
cerion32aad402005-09-10 12:02:24 +000016183 case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207)
16184 DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016185 putVReg( vD_addr, MK_Iop_MullOdd8Sx16( mkexpr(vA), mkexpr(vB) ));
cerion36991ef2005-09-15 12:42:16 +000016186 break;
cerion32aad402005-09-10 12:02:24 +000016187
16188 case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208)
16189 DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion24d06f12005-11-09 21:34:20 +000016190 putVReg( vD_addr, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
cerion36991ef2005-09-15 12:42:16 +000016191 break;
cerion32aad402005-09-10 12:02:24 +000016192
carll48ae46b2013-10-01 15:45:54 +000016193 case 0x388: // vmulesw (Multiply Even Signed Word)
16194 DIP("vmulesw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16195 putVReg( vD_addr, MK_Iop_MullOdd32Sx4( mkexpr(vA), mkexpr(vB) ) );
16196 break;
cerion32aad402005-09-10 12:02:24 +000016197
16198 /* Sum Across Partial */
cerion4a49b032005-11-08 16:23:07 +000016199 case 0x608: { // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275)
16200 IRTemp aEE, aEO, aOE, aOO;
16201 aEE = aEO = aOE = aOO = IRTemp_INVALID;
cerion32aad402005-09-10 12:02:24 +000016202 DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016203
cerion4a49b032005-11-08 16:23:07 +000016204 /* vA: V128_8Ux16 -> 4 x V128_32Ux4, sign-extended */
16205 expand8Ux16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
16206 expand16Ux8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
16207 expand16Ux8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
16208
16209 /* break V128 to 4xI32's, zero-extending to I64's */
16210 breakV128to4x64U( mkexpr(aEE), &a15, &a11, &a7, &a3 );
16211 breakV128to4x64U( mkexpr(aOE), &a14, &a10, &a6, &a2 );
16212 breakV128to4x64U( mkexpr(aEO), &a13, &a9, &a5, &a1 );
16213 breakV128to4x64U( mkexpr(aOO), &a12, &a8, &a4, &a0 );
16214 breakV128to4x64U( mkexpr(vB), &b3, &b2, &b1, &b0 );
16215
16216 /* add lanes */
16217 assign( z3, binop(Iop_Add64, mkexpr(b3),
cerion5b2325f2005-12-23 00:55:09 +000016218 binop(Iop_Add64,
16219 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
16220 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
cerion4a49b032005-11-08 16:23:07 +000016221 assign( z2, binop(Iop_Add64, mkexpr(b2),
cerion5b2325f2005-12-23 00:55:09 +000016222 binop(Iop_Add64,
16223 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
16224 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
cerion4a49b032005-11-08 16:23:07 +000016225 assign( z1, binop(Iop_Add64, mkexpr(b1),
cerion5b2325f2005-12-23 00:55:09 +000016226 binop(Iop_Add64,
16227 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
16228 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
cerion4a49b032005-11-08 16:23:07 +000016229 assign( z0, binop(Iop_Add64, mkexpr(b0),
cerion5b2325f2005-12-23 00:55:09 +000016230 binop(Iop_Add64,
16231 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
16232 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
cerion4a49b032005-11-08 16:23:07 +000016233
16234 /* saturate-narrow to 32bit, and combine to V128 */
16235 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
16236 mkexpr(z1), mkexpr(z0)) );
16237 break;
16238 }
16239 case 0x708: { // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273)
16240 IRTemp aEE, aEO, aOE, aOO;
16241 aEE = aEO = aOE = aOO = IRTemp_INVALID;
cerion32aad402005-09-10 12:02:24 +000016242 DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016243
cerion4a49b032005-11-08 16:23:07 +000016244 /* vA: V128_8Sx16 -> 4 x V128_32Sx4, sign-extended */
16245 expand8Sx16( mkexpr(vA), &aEvn, &aOdd ); // (15,13...),(14,12...)
16246 expand16Sx8( mkexpr(aEvn), &aEE, &aEO ); // (15,11...),(13, 9...)
16247 expand16Sx8( mkexpr(aOdd), &aOE, &aOO ); // (14,10...),(12, 8...)
16248
16249 /* break V128 to 4xI32's, sign-extending to I64's */
16250 breakV128to4x64S( mkexpr(aEE), &a15, &a11, &a7, &a3 );
16251 breakV128to4x64S( mkexpr(aOE), &a14, &a10, &a6, &a2 );
16252 breakV128to4x64S( mkexpr(aEO), &a13, &a9, &a5, &a1 );
16253 breakV128to4x64S( mkexpr(aOO), &a12, &a8, &a4, &a0 );
16254 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16255
16256 /* add lanes */
16257 assign( z3, binop(Iop_Add64, mkexpr(b3),
cerion5b2325f2005-12-23 00:55:09 +000016258 binop(Iop_Add64,
16259 binop(Iop_Add64, mkexpr(a15), mkexpr(a14)),
16260 binop(Iop_Add64, mkexpr(a13), mkexpr(a12)))) );
cerion4a49b032005-11-08 16:23:07 +000016261 assign( z2, binop(Iop_Add64, mkexpr(b2),
cerion5b2325f2005-12-23 00:55:09 +000016262 binop(Iop_Add64,
16263 binop(Iop_Add64, mkexpr(a11), mkexpr(a10)),
16264 binop(Iop_Add64, mkexpr(a9), mkexpr(a8)))) );
cerion4a49b032005-11-08 16:23:07 +000016265 assign( z1, binop(Iop_Add64, mkexpr(b1),
cerion5b2325f2005-12-23 00:55:09 +000016266 binop(Iop_Add64,
16267 binop(Iop_Add64, mkexpr(a7), mkexpr(a6)),
16268 binop(Iop_Add64, mkexpr(a5), mkexpr(a4)))) );
cerion4a49b032005-11-08 16:23:07 +000016269 assign( z0, binop(Iop_Add64, mkexpr(b0),
cerion5b2325f2005-12-23 00:55:09 +000016270 binop(Iop_Add64,
16271 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
16272 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
cerion4a49b032005-11-08 16:23:07 +000016273
16274 /* saturate-narrow to 32bit, and combine to V128 */
16275 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
16276 mkexpr(z1), mkexpr(z0)) );
16277 break;
16278 }
16279 case 0x648: { // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274)
cerion32aad402005-09-10 12:02:24 +000016280 DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016281
cerion4a49b032005-11-08 16:23:07 +000016282 /* vA: V128_16Sx8 -> 2 x V128_32Sx4, sign-extended */
16283 expand16Sx8( mkexpr(vA), &aEvn, &aOdd ); // (7,5...),(6,4...)
16284
16285 /* break V128 to 4xI32's, sign-extending to I64's */
16286 breakV128to4x64S( mkexpr(aEvn), &a7, &a5, &a3, &a1 );
16287 breakV128to4x64S( mkexpr(aOdd), &a6, &a4, &a2, &a0 );
16288 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16289
16290 /* add lanes */
16291 assign( z3, binop(Iop_Add64, mkexpr(b3),
16292 binop(Iop_Add64, mkexpr(a7), mkexpr(a6))));
16293 assign( z2, binop(Iop_Add64, mkexpr(b2),
16294 binop(Iop_Add64, mkexpr(a5), mkexpr(a4))));
16295 assign( z1, binop(Iop_Add64, mkexpr(b1),
16296 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))));
16297 assign( z0, binop(Iop_Add64, mkexpr(b0),
16298 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))));
16299
16300 /* saturate-narrow to 32bit, and combine to V128 */
16301 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
16302 mkexpr(z1), mkexpr(z0)) );
16303 break;
16304 }
16305 case 0x688: { // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272)
cerion32aad402005-09-10 12:02:24 +000016306 DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016307
cerion4a49b032005-11-08 16:23:07 +000016308 /* break V128 to 4xI32's, sign-extending to I64's */
16309 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
16310 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16311
16312 /* add lanes */
16313 assign( z2, binop(Iop_Add64, mkexpr(b2),
16314 binop(Iop_Add64, mkexpr(a3), mkexpr(a2))) );
16315 assign( z0, binop(Iop_Add64, mkexpr(b0),
16316 binop(Iop_Add64, mkexpr(a1), mkexpr(a0))) );
16317
16318 /* saturate-narrow to 32bit, and combine to V128 */
16319 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkexpr(z2),
16320 mkU64(0), mkexpr(z0)) );
16321 break;
16322 }
16323 case 0x788: { // vsumsws (Sum SW Saturate, AV p271)
cerion32aad402005-09-10 12:02:24 +000016324 DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion32aad402005-09-10 12:02:24 +000016325
cerion4a49b032005-11-08 16:23:07 +000016326 /* break V128 to 4xI32's, sign-extending to I64's */
16327 breakV128to4x64S( mkexpr(vA), &a3, &a2, &a1, &a0 );
16328 breakV128to4x64S( mkexpr(vB), &b3, &b2, &b1, &b0 );
16329
16330 /* add lanes */
16331 assign( z0, binop(Iop_Add64, mkexpr(b0),
cerion5b2325f2005-12-23 00:55:09 +000016332 binop(Iop_Add64,
16333 binop(Iop_Add64, mkexpr(a3), mkexpr(a2)),
16334 binop(Iop_Add64, mkexpr(a1), mkexpr(a0)))) );
cerion4a49b032005-11-08 16:23:07 +000016335
16336 /* saturate-narrow to 32bit, and combine to V128 */
16337 putVReg( vD_addr, mkV128from4x64S( mkU64(0), mkU64(0),
16338 mkU64(0), mkexpr(z0)) );
16339 break;
16340 }
cerion32aad402005-09-10 12:02:24 +000016341 default:
cerion5b2325f2005-12-23 00:55:09 +000016342 vex_printf("dis_av_arith(ppc)(opc2=0x%x)\n", opc2);
cerion32aad402005-09-10 12:02:24 +000016343 return False;
16344 }
16345 return True;
16346}
16347
16348/*
16349 AltiVec Logic Instructions
16350*/
16351static Bool dis_av_logic ( UInt theInstr )
16352{
cerion76de5cf2005-11-18 18:25:12 +000016353 /* VX-Form */
16354 UChar opc1 = ifieldOPC(theInstr);
16355 UChar vD_addr = ifieldRegDS(theInstr);
16356 UChar vA_addr = ifieldRegA(theInstr);
16357 UChar vB_addr = ifieldRegB(theInstr);
16358 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000016359
cerion225a0342005-09-12 20:49:09 +000016360 IRTemp vA = newTemp(Ity_V128);
16361 IRTemp vB = newTemp(Ity_V128);
16362 assign( vA, getVReg(vA_addr));
16363 assign( vB, getVReg(vB_addr));
16364
cerion32aad402005-09-10 12:02:24 +000016365 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000016366 vex_printf("dis_av_logic(ppc)(opc1 != 0x4)\n");
cerion32aad402005-09-10 12:02:24 +000016367 return False;
16368 }
16369
16370 switch (opc2) {
16371 case 0x404: // vand (And, AV p147)
16372 DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +000016373 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA), mkexpr(vB)) );
16374 break;
cerion32aad402005-09-10 12:02:24 +000016375
16376 case 0x444: // vandc (And, AV p148)
16377 DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion6e7a0ea2005-09-13 13:34:09 +000016378 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA),
cerion76de5cf2005-11-18 18:25:12 +000016379 unop(Iop_NotV128, mkexpr(vB))) );
cerion6e7a0ea2005-09-13 13:34:09 +000016380 break;
cerion32aad402005-09-10 12:02:24 +000016381
16382 case 0x484: // vor (Or, AV p217)
16383 DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +000016384 putVReg( vD_addr, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB)) );
16385 break;
cerion32aad402005-09-10 12:02:24 +000016386
16387 case 0x4C4: // vxor (Xor, AV p282)
16388 DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +000016389 putVReg( vD_addr, binop(Iop_XorV128, mkexpr(vA), mkexpr(vB)) );
16390 break;
cerion32aad402005-09-10 12:02:24 +000016391
16392 case 0x504: // vnor (Nor, AV p216)
16393 DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion6e7a0ea2005-09-13 13:34:09 +000016394 putVReg( vD_addr,
16395 unop(Iop_NotV128, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB))) );
16396 break;
cerion32aad402005-09-10 12:02:24 +000016397
carll7deaf952013-10-15 18:11:20 +000016398 case 0x544: // vorc (vA Or'd with complement of vb)
16399 DIP("vorc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16400 putVReg( vD_addr, binop( Iop_OrV128,
16401 mkexpr( vA ),
16402 unop( Iop_NotV128, mkexpr( vB ) ) ) );
16403 break;
16404
16405 case 0x584: // vnand (Nand)
16406 DIP("vnand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16407 putVReg( vD_addr, unop( Iop_NotV128,
16408 binop(Iop_AndV128, mkexpr( vA ),
16409 mkexpr( vB ) ) ) );
16410 break;
16411
16412 case 0x684: // veqv (complemented XOr)
16413 DIP("veqv v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16414 putVReg( vD_addr, unop( Iop_NotV128,
16415 binop( Iop_XorV128, mkexpr( vA ),
16416 mkexpr( vB ) ) ) );
16417 break;
16418
cerion32aad402005-09-10 12:02:24 +000016419 default:
cerion5b2325f2005-12-23 00:55:09 +000016420 vex_printf("dis_av_logic(ppc)(opc2=0x%x)\n", opc2);
cerion32aad402005-09-10 12:02:24 +000016421 return False;
16422 }
16423 return True;
16424}
16425
16426/*
16427 AltiVec Compare Instructions
16428*/
16429static Bool dis_av_cmp ( UInt theInstr )
16430{
cerion76de5cf2005-11-18 18:25:12 +000016431 /* VXR-Form */
16432 UChar opc1 = ifieldOPC(theInstr);
16433 UChar vD_addr = ifieldRegDS(theInstr);
16434 UChar vA_addr = ifieldRegA(theInstr);
16435 UChar vB_addr = ifieldRegB(theInstr);
16436 UChar flag_rC = ifieldBIT10(theInstr);
16437 UInt opc2 = IFIELD( theInstr, 0, 10 );
cerion32aad402005-09-10 12:02:24 +000016438
cerion0c439222005-09-15 14:22:58 +000016439 IRTemp vA = newTemp(Ity_V128);
16440 IRTemp vB = newTemp(Ity_V128);
16441 IRTemp vD = newTemp(Ity_V128);
16442 assign( vA, getVReg(vA_addr));
16443 assign( vB, getVReg(vB_addr));
16444
cerion32aad402005-09-10 12:02:24 +000016445 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000016446 vex_printf("dis_av_cmp(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000016447 return False;
16448 }
16449
16450 switch (opc2) {
16451 case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160)
cerion5b2325f2005-12-23 00:55:09 +000016452 DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16453 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016454 assign( vD, binop(Iop_CmpEQ8x16, mkexpr(vA), mkexpr(vB)) );
16455 break;
cerion32aad402005-09-10 12:02:24 +000016456
16457 case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161)
cerion5b2325f2005-12-23 00:55:09 +000016458 DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16459 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016460 assign( vD, binop(Iop_CmpEQ16x8, mkexpr(vA), mkexpr(vB)) );
16461 break;
cerion32aad402005-09-10 12:02:24 +000016462
16463 case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162)
cerion5b2325f2005-12-23 00:55:09 +000016464 DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16465 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016466 assign( vD, binop(Iop_CmpEQ32x4, mkexpr(vA), mkexpr(vB)) );
16467 break;
cerion32aad402005-09-10 12:02:24 +000016468
carll48ae46b2013-10-01 15:45:54 +000016469 case 0x0C7: // vcmpequd (Compare Equal-to Unsigned Doubleword)
16470 DIP("vcmpequd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16471 vD_addr, vA_addr, vB_addr);
16472 assign( vD, binop(Iop_CmpEQ64x2, mkexpr(vA), mkexpr(vB)) );
16473 break;
16474
cerion32aad402005-09-10 12:02:24 +000016475 case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168)
cerion5b2325f2005-12-23 00:55:09 +000016476 DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16477 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016478 assign( vD, binop(Iop_CmpGT8Ux16, mkexpr(vA), mkexpr(vB)) );
16479 break;
cerion32aad402005-09-10 12:02:24 +000016480
16481 case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169)
cerion5b2325f2005-12-23 00:55:09 +000016482 DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16483 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016484 assign( vD, binop(Iop_CmpGT16Ux8, mkexpr(vA), mkexpr(vB)) );
16485 break;
cerion32aad402005-09-10 12:02:24 +000016486
16487 case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170)
cerion5b2325f2005-12-23 00:55:09 +000016488 DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16489 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016490 assign( vD, binop(Iop_CmpGT32Ux4, mkexpr(vA), mkexpr(vB)) );
16491 break;
cerion32aad402005-09-10 12:02:24 +000016492
carll48ae46b2013-10-01 15:45:54 +000016493 case 0x2C7: // vcmpgtud (Compare Greater-than Unsigned double)
16494 DIP("vcmpgtud%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16495 vD_addr, vA_addr, vB_addr);
16496 assign( vD, binop(Iop_CmpGT64Ux2, mkexpr(vA), mkexpr(vB)) );
16497 break;
16498
cerion32aad402005-09-10 12:02:24 +000016499 case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165)
cerion5b2325f2005-12-23 00:55:09 +000016500 DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16501 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016502 assign( vD, binop(Iop_CmpGT8Sx16, mkexpr(vA), mkexpr(vB)) );
16503 break;
cerion32aad402005-09-10 12:02:24 +000016504
16505 case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166)
cerion5b2325f2005-12-23 00:55:09 +000016506 DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16507 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016508 assign( vD, binop(Iop_CmpGT16Sx8, mkexpr(vA), mkexpr(vB)) );
16509 break;
cerion32aad402005-09-10 12:02:24 +000016510
16511 case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167)
cerion5b2325f2005-12-23 00:55:09 +000016512 DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16513 vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +000016514 assign( vD, binop(Iop_CmpGT32Sx4, mkexpr(vA), mkexpr(vB)) );
16515 break;
cerion32aad402005-09-10 12:02:24 +000016516
carll48ae46b2013-10-01 15:45:54 +000016517 case 0x3C7: // vcmpgtsd (Compare Greater-than Signed double)
16518 DIP("vcmpgtsd%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
16519 vD_addr, vA_addr, vB_addr);
16520 assign( vD, binop(Iop_CmpGT64Sx2, mkexpr(vA), mkexpr(vB)) );
16521 break;
16522
cerion32aad402005-09-10 12:02:24 +000016523 default:
cerion5b2325f2005-12-23 00:55:09 +000016524 vex_printf("dis_av_cmp(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000016525 return False;
16526 }
cerion0c439222005-09-15 14:22:58 +000016527
16528 putVReg( vD_addr, mkexpr(vD) );
16529
cerion76de5cf2005-11-18 18:25:12 +000016530 if (flag_rC) {
cerion8ea0d3e2005-11-14 00:44:47 +000016531 set_AV_CR6( mkexpr(vD), True );
cerion0c439222005-09-15 14:22:58 +000016532 }
cerion32aad402005-09-10 12:02:24 +000016533 return True;
16534}
16535
16536/*
16537 AltiVec Multiply-Sum Instructions
16538*/
16539static Bool dis_av_multarith ( UInt theInstr )
16540{
cerion76de5cf2005-11-18 18:25:12 +000016541 /* VA-Form */
16542 UChar opc1 = ifieldOPC(theInstr);
16543 UChar vD_addr = ifieldRegDS(theInstr);
16544 UChar vA_addr = ifieldRegA(theInstr);
16545 UChar vB_addr = ifieldRegB(theInstr);
16546 UChar vC_addr = ifieldRegC(theInstr);
16547 UChar opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
cerion32aad402005-09-10 12:02:24 +000016548
cerion4a49b032005-11-08 16:23:07 +000016549 IRTemp vA = newTemp(Ity_V128);
16550 IRTemp vB = newTemp(Ity_V128);
16551 IRTemp vC = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000016552 IRTemp zeros = newTemp(Ity_V128);
cerion4a49b032005-11-08 16:23:07 +000016553 IRTemp aLo = newTemp(Ity_V128);
16554 IRTemp bLo = newTemp(Ity_V128);
16555 IRTemp cLo = newTemp(Ity_V128);
16556 IRTemp zLo = newTemp(Ity_V128);
16557 IRTemp aHi = newTemp(Ity_V128);
16558 IRTemp bHi = newTemp(Ity_V128);
16559 IRTemp cHi = newTemp(Ity_V128);
16560 IRTemp zHi = newTemp(Ity_V128);
16561 IRTemp abEvn = newTemp(Ity_V128);
16562 IRTemp abOdd = newTemp(Ity_V128);
16563 IRTemp z3 = newTemp(Ity_I64);
16564 IRTemp z2 = newTemp(Ity_I64);
16565 IRTemp z1 = newTemp(Ity_I64);
16566 IRTemp z0 = newTemp(Ity_I64);
16567 IRTemp ab7, ab6, ab5, ab4, ab3, ab2, ab1, ab0;
16568 IRTemp c3, c2, c1, c0;
16569
16570 ab7 = ab6 = ab5 = ab4 = ab3 = ab2 = ab1 = ab0 = IRTemp_INVALID;
16571 c3 = c2 = c1 = c0 = IRTemp_INVALID;
16572
cerion6f1cc0f2005-09-16 16:02:11 +000016573 assign( vA, getVReg(vA_addr));
16574 assign( vB, getVReg(vB_addr));
16575 assign( vC, getVReg(vC_addr));
cerion4a49b032005-11-08 16:23:07 +000016576 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016577
cerion32aad402005-09-10 12:02:24 +000016578 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000016579 vex_printf("dis_av_multarith(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000016580 return False;
16581 }
16582
16583 switch (opc2) {
cerion32aad402005-09-10 12:02:24 +000016584 /* Multiply-Add */
cerion5b2325f2005-12-23 00:55:09 +000016585 case 0x20: { // vmhaddshs (Mult Hi, Add Signed HW Saturate, AV p185)
cerion6f1cc0f2005-09-16 16:02:11 +000016586 IRTemp cSigns = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000016587 DIP("vmhaddshs v%d,v%d,v%d,v%d\n",
16588 vD_addr, vA_addr, vB_addr, vC_addr);
16589 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)));
16590 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
16591 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
16592 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
16593 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
16594 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
16595 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
cerion32aad402005-09-10 12:02:24 +000016596
cerion24d06f12005-11-09 21:34:20 +000016597 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
cerion6f1cc0f2005-09-16 16:02:11 +000016598 binop(Iop_SarN32x4,
cerion1ac656a2005-11-04 19:44:48 +000016599 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016600 mkexpr(aLo), mkexpr(bLo)),
16601 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016602
cerion24d06f12005-11-09 21:34:20 +000016603 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
cerion6f1cc0f2005-09-16 16:02:11 +000016604 binop(Iop_SarN32x4,
cerion1ac656a2005-11-04 19:44:48 +000016605 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016606 mkexpr(aHi), mkexpr(bHi)),
16607 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016608
cerion5b2325f2005-12-23 00:55:09 +000016609 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000016610 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016611 break;
16612 }
cerion5b2325f2005-12-23 00:55:09 +000016613 case 0x21: { // vmhraddshs (Mult High Round, Add Signed HW Saturate, AV p186)
cerion6f1cc0f2005-09-16 16:02:11 +000016614 IRTemp zKonst = newTemp(Ity_V128);
cerion6f1cc0f2005-09-16 16:02:11 +000016615 IRTemp cSigns = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000016616 DIP("vmhraddshs v%d,v%d,v%d,v%d\n",
16617 vD_addr, vA_addr, vB_addr, vC_addr);
16618 assign(cSigns, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vC)) );
16619 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
16620 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
16621 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(cSigns),mkexpr(vC)));
16622 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
16623 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
16624 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(cSigns),mkexpr(vC)));
cerion32aad402005-09-10 12:02:24 +000016625
cerion6f1cc0f2005-09-16 16:02:11 +000016626 /* shifting our const avoids store/load version of Dup */
cerion4a49b032005-11-08 16:23:07 +000016627 assign( zKonst, binop(Iop_ShlN32x4, unop(Iop_Dup32x4, mkU32(0x1)),
16628 mkU8(14)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016629
cerion24d06f12005-11-09 21:34:20 +000016630 assign( zLo, binop(Iop_Add32x4, mkexpr(cLo),
cerion6f1cc0f2005-09-16 16:02:11 +000016631 binop(Iop_SarN32x4,
16632 binop(Iop_Add32x4, mkexpr(zKonst),
cerion1ac656a2005-11-04 19:44:48 +000016633 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016634 mkexpr(aLo), mkexpr(bLo))),
16635 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016636
cerion24d06f12005-11-09 21:34:20 +000016637 assign( zHi, binop(Iop_Add32x4, mkexpr(cHi),
cerion6f1cc0f2005-09-16 16:02:11 +000016638 binop(Iop_SarN32x4,
16639 binop(Iop_Add32x4, mkexpr(zKonst),
cerion1ac656a2005-11-04 19:44:48 +000016640 binop(Iop_MullEven16Sx8,
cerion24d06f12005-11-09 21:34:20 +000016641 mkexpr(aHi), mkexpr(bHi))),
16642 mkU8(15))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016643
sewardjc9bff7d2011-06-15 15:09:37 +000016644 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000016645 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(zHi), mkexpr(zLo)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016646 break;
16647 }
cerion5b2325f2005-12-23 00:55:09 +000016648 case 0x22: { // vmladduhm (Mult Low, Add Unsigned HW Modulo, AV p194)
16649 DIP("vmladduhm v%d,v%d,v%d,v%d\n",
16650 vD_addr, vA_addr, vB_addr, vC_addr);
16651 assign(aLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vA)));
16652 assign(bLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vB)));
16653 assign(cLo, binop(Iop_InterleaveLO16x8, mkexpr(zeros), mkexpr(vC)));
16654 assign(aHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vA)));
16655 assign(bHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vB)));
16656 assign(cHi, binop(Iop_InterleaveHI16x8, mkexpr(zeros), mkexpr(vC)));
16657 assign(zLo, binop(Iop_Add32x4,
16658 binop(Iop_MullEven16Ux8, mkexpr(aLo), mkexpr(bLo)),
16659 mkexpr(cLo)) );
16660 assign(zHi, binop(Iop_Add32x4,
16661 binop(Iop_MullEven16Ux8, mkexpr(aHi), mkexpr(bHi)),
16662 mkexpr(cHi)));
sewardj5f438dd2011-06-16 11:36:23 +000016663 putVReg( vD_addr,
16664 binop(Iop_NarrowBin32to16x8, mkexpr(zHi), mkexpr(zLo)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016665 break;
16666 }
cerion32aad402005-09-10 12:02:24 +000016667
16668
16669 /* Multiply-Sum */
cerion6f1cc0f2005-09-16 16:02:11 +000016670 case 0x24: { // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204)
cerion4a49b032005-11-08 16:23:07 +000016671 IRTemp abEE, abEO, abOE, abOO;
16672 abEE = abEO = abOE = abOO = IRTemp_INVALID;
cerion5b2325f2005-12-23 00:55:09 +000016673 DIP("vmsumubm v%d,v%d,v%d,v%d\n",
16674 vD_addr, vA_addr, vB_addr, vC_addr);
cerion32aad402005-09-10 12:02:24 +000016675
cerion4a49b032005-11-08 16:23:07 +000016676 /* multiply vA,vB (unsigned, widening) */
cerion24d06f12005-11-09 21:34:20 +000016677 assign( abEvn, MK_Iop_MullOdd8Ux16( mkexpr(vA), mkexpr(vB) ));
16678 assign( abOdd, binop(Iop_MullEven8Ux16, mkexpr(vA), mkexpr(vB)) );
cerion4a49b032005-11-08 16:23:07 +000016679
16680 /* evn,odd: V128_16Ux8 -> 2 x V128_32Ux4, zero-extended */
16681 expand16Ux8( mkexpr(abEvn), &abEE, &abEO );
16682 expand16Ux8( mkexpr(abOdd), &abOE, &abOO );
16683
cerion6f1cc0f2005-09-16 16:02:11 +000016684 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016685 binop(Iop_Add32x4, mkexpr(vC),
16686 binop(Iop_Add32x4,
16687 binop(Iop_Add32x4, mkexpr(abEE), mkexpr(abEO)),
16688 binop(Iop_Add32x4, mkexpr(abOE), mkexpr(abOO)))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016689 break;
16690 }
cerion4a49b032005-11-08 16:23:07 +000016691 case 0x25: { // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201)
16692 IRTemp aEvn, aOdd, bEvn, bOdd;
16693 IRTemp abEE = newTemp(Ity_V128);
16694 IRTemp abEO = newTemp(Ity_V128);
16695 IRTemp abOE = newTemp(Ity_V128);
16696 IRTemp abOO = newTemp(Ity_V128);
16697 aEvn = aOdd = bEvn = bOdd = IRTemp_INVALID;
cerion5b2325f2005-12-23 00:55:09 +000016698 DIP("vmsummbm v%d,v%d,v%d,v%d\n",
16699 vD_addr, vA_addr, vB_addr, vC_addr);
cerion32aad402005-09-10 12:02:24 +000016700
cerion4a49b032005-11-08 16:23:07 +000016701 /* sign-extend vA, zero-extend vB, for mixed-sign multiply
16702 (separating out adjacent lanes to different vectors) */
16703 expand8Sx16( mkexpr(vA), &aEvn, &aOdd );
16704 expand8Ux16( mkexpr(vB), &bEvn, &bOdd );
16705
16706 /* multiply vA, vB, again separating adjacent lanes */
cerion24d06f12005-11-09 21:34:20 +000016707 assign( abEE, MK_Iop_MullOdd16Sx8( mkexpr(aEvn), mkexpr(bEvn) ));
16708 assign( abEO, binop(Iop_MullEven16Sx8, mkexpr(aEvn), mkexpr(bEvn)) );
16709 assign( abOE, MK_Iop_MullOdd16Sx8( mkexpr(aOdd), mkexpr(bOdd) ));
16710 assign( abOO, binop(Iop_MullEven16Sx8, mkexpr(aOdd), mkexpr(bOdd)) );
cerion4a49b032005-11-08 16:23:07 +000016711
16712 /* add results together, + vC */
16713 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016714 binop(Iop_QAdd32Sx4, mkexpr(vC),
16715 binop(Iop_QAdd32Sx4,
16716 binop(Iop_QAdd32Sx4, mkexpr(abEE), mkexpr(abEO)),
16717 binop(Iop_QAdd32Sx4, mkexpr(abOE), mkexpr(abOO)))) );
cerion4a49b032005-11-08 16:23:07 +000016718 break;
16719 }
cerion6f1cc0f2005-09-16 16:02:11 +000016720 case 0x26: { // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205)
cerion5b2325f2005-12-23 00:55:09 +000016721 DIP("vmsumuhm v%d,v%d,v%d,v%d\n",
16722 vD_addr, vA_addr, vB_addr, vC_addr);
cerion24d06f12005-11-09 21:34:20 +000016723 assign( abEvn, MK_Iop_MullOdd16Ux8( mkexpr(vA), mkexpr(vB) ));
16724 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
cerion6f1cc0f2005-09-16 16:02:11 +000016725 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016726 binop(Iop_Add32x4, mkexpr(vC),
16727 binop(Iop_Add32x4, mkexpr(abEvn), mkexpr(abOdd))) );
cerion6f1cc0f2005-09-16 16:02:11 +000016728 break;
16729 }
cerion4a49b032005-11-08 16:23:07 +000016730 case 0x27: { // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206)
cerion5b2325f2005-12-23 00:55:09 +000016731 DIP("vmsumuhs v%d,v%d,v%d,v%d\n",
16732 vD_addr, vA_addr, vB_addr, vC_addr);
cerion4a49b032005-11-08 16:23:07 +000016733 /* widening multiply, separating lanes */
cerion24d06f12005-11-09 21:34:20 +000016734 assign( abEvn, MK_Iop_MullOdd16Ux8(mkexpr(vA), mkexpr(vB) ));
16735 assign( abOdd, binop(Iop_MullEven16Ux8, mkexpr(vA), mkexpr(vB)) );
cerion32aad402005-09-10 12:02:24 +000016736
cerion4a49b032005-11-08 16:23:07 +000016737 /* break V128 to 4xI32's, zero-extending to I64's */
16738 breakV128to4x64U( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
16739 breakV128to4x64U( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
16740 breakV128to4x64U( mkexpr(vC), &c3, &c2, &c1, &c0 );
16741
16742 /* add lanes */
16743 assign( z3, binop(Iop_Add64, mkexpr(c3),
16744 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
16745 assign( z2, binop(Iop_Add64, mkexpr(c2),
16746 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
16747 assign( z1, binop(Iop_Add64, mkexpr(c1),
16748 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
16749 assign( z0, binop(Iop_Add64, mkexpr(c0),
16750 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
16751
16752 /* saturate-narrow to 32bit, and combine to V128 */
16753 putVReg( vD_addr, mkV128from4x64U( mkexpr(z3), mkexpr(z2),
16754 mkexpr(z1), mkexpr(z0)) );
16755
cerion6f1cc0f2005-09-16 16:02:11 +000016756 break;
16757 }
cerion4a49b032005-11-08 16:23:07 +000016758 case 0x28: { // vmsumshm (Multiply Sum Signed HW Modulo, AV p202)
cerion5b2325f2005-12-23 00:55:09 +000016759 DIP("vmsumshm v%d,v%d,v%d,v%d\n",
16760 vD_addr, vA_addr, vB_addr, vC_addr);
cerion24d06f12005-11-09 21:34:20 +000016761 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
16762 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
cerion4a49b032005-11-08 16:23:07 +000016763 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000016764 binop(Iop_Add32x4, mkexpr(vC),
16765 binop(Iop_Add32x4, mkexpr(abOdd), mkexpr(abEvn))) );
cerion4a49b032005-11-08 16:23:07 +000016766 break;
16767 }
16768 case 0x29: { // vmsumshs (Multiply Sum Signed HW Saturate, AV p203)
cerion5b2325f2005-12-23 00:55:09 +000016769 DIP("vmsumshs v%d,v%d,v%d,v%d\n",
16770 vD_addr, vA_addr, vB_addr, vC_addr);
cerion4a49b032005-11-08 16:23:07 +000016771 /* widening multiply, separating lanes */
cerion24d06f12005-11-09 21:34:20 +000016772 assign( abEvn, MK_Iop_MullOdd16Sx8( mkexpr(vA), mkexpr(vB) ));
16773 assign( abOdd, binop(Iop_MullEven16Sx8, mkexpr(vA), mkexpr(vB)) );
cerion32aad402005-09-10 12:02:24 +000016774
cerion4a49b032005-11-08 16:23:07 +000016775 /* break V128 to 4xI32's, sign-extending to I64's */
16776 breakV128to4x64S( mkexpr(abEvn), &ab7, &ab5, &ab3, &ab1 );
16777 breakV128to4x64S( mkexpr(abOdd), &ab6, &ab4, &ab2, &ab0 );
16778 breakV128to4x64S( mkexpr(vC), &c3, &c2, &c1, &c0 );
16779
16780 /* add lanes */
16781 assign( z3, binop(Iop_Add64, mkexpr(c3),
16782 binop(Iop_Add64, mkexpr(ab7), mkexpr(ab6))));
16783 assign( z2, binop(Iop_Add64, mkexpr(c2),
16784 binop(Iop_Add64, mkexpr(ab5), mkexpr(ab4))));
16785 assign( z1, binop(Iop_Add64, mkexpr(c1),
16786 binop(Iop_Add64, mkexpr(ab3), mkexpr(ab2))));
16787 assign( z0, binop(Iop_Add64, mkexpr(c0),
16788 binop(Iop_Add64, mkexpr(ab1), mkexpr(ab0))));
16789
16790 /* saturate-narrow to 32bit, and combine to V128 */
16791 putVReg( vD_addr, mkV128from4x64S( mkexpr(z3), mkexpr(z2),
16792 mkexpr(z1), mkexpr(z0)) );
16793 break;
16794 }
cerion32aad402005-09-10 12:02:24 +000016795 default:
cerion5b2325f2005-12-23 00:55:09 +000016796 vex_printf("dis_av_multarith(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000016797 return False;
16798 }
16799 return True;
16800}
16801
16802/*
carll7deaf952013-10-15 18:11:20 +000016803 AltiVec Polynomial Multiply-Sum Instructions
16804*/
16805static Bool dis_av_polymultarith ( UInt theInstr )
16806{
16807 /* VA-Form */
16808 UChar opc1 = ifieldOPC(theInstr);
16809 UChar vD_addr = ifieldRegDS(theInstr);
16810 UChar vA_addr = ifieldRegA(theInstr);
16811 UChar vB_addr = ifieldRegB(theInstr);
16812 UChar vC_addr = ifieldRegC(theInstr);
16813 UInt opc2 = IFIELD(theInstr, 0, 11);
16814 IRTemp vA = newTemp(Ity_V128);
16815 IRTemp vB = newTemp(Ity_V128);
16816 IRTemp vC = newTemp(Ity_V128);
16817
16818 assign( vA, getVReg(vA_addr));
16819 assign( vB, getVReg(vB_addr));
16820 assign( vC, getVReg(vC_addr));
16821
16822 if (opc1 != 0x4) {
16823 vex_printf("dis_av_polymultarith(ppc)(instr)\n");
16824 return False;
16825 }
16826
16827 switch (opc2) {
16828 /* Polynomial Multiply-Add */
16829 case 0x408: // vpmsumb Vector Polynomial Multipy-sum Byte
16830 DIP("vpmsumb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16831 putVReg( vD_addr, binop(Iop_PolynomialMulAdd8x16,
16832 mkexpr(vA), mkexpr(vB)) );
16833 break;
16834 case 0x448: // vpmsumd Vector Polynomial Multipy-sum Double Word
16835 DIP("vpmsumd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16836 putVReg( vD_addr, binop(Iop_PolynomialMulAdd64x2,
16837 mkexpr(vA), mkexpr(vB)) );
16838 break;
16839 case 0x488: // vpmsumw Vector Polynomial Multipy-sum Word
16840 DIP("vpmsumw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16841 putVReg( vD_addr, binop(Iop_PolynomialMulAdd32x4,
16842 mkexpr(vA), mkexpr(vB)) );
16843 break;
16844 case 0x4C8: // vpmsumh Vector Polynomial Multipy-sum Half Word
16845 DIP("vpmsumh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16846 putVReg( vD_addr, binop(Iop_PolynomialMulAdd16x8,
16847 mkexpr(vA), mkexpr(vB)) );
16848 break;
16849 default:
16850 vex_printf("dis_av_polymultarith(ppc)(opc2=0x%x)\n", opc2);
16851 return False;
16852 }
16853 return True;
16854}
16855
16856/*
cerion32aad402005-09-10 12:02:24 +000016857 AltiVec Shift/Rotate Instructions
16858*/
16859static Bool dis_av_shift ( UInt theInstr )
16860{
cerion76de5cf2005-11-18 18:25:12 +000016861 /* VX-Form */
16862 UChar opc1 = ifieldOPC(theInstr);
16863 UChar vD_addr = ifieldRegDS(theInstr);
16864 UChar vA_addr = ifieldRegA(theInstr);
16865 UChar vB_addr = ifieldRegB(theInstr);
16866 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000016867
cerion27b3d7e2005-09-14 20:35:47 +000016868 IRTemp vA = newTemp(Ity_V128);
16869 IRTemp vB = newTemp(Ity_V128);
16870 assign( vA, getVReg(vA_addr));
16871 assign( vB, getVReg(vB_addr));
16872
cerion32aad402005-09-10 12:02:24 +000016873 if (opc1 != 0x4){
cerion5b2325f2005-12-23 00:55:09 +000016874 vex_printf("dis_av_shift(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000016875 return False;
16876 }
16877
16878 switch (opc2) {
16879 /* Rotate */
16880 case 0x004: // vrlb (Rotate Left Integer B, AV p234)
16881 DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj1bee5612005-11-10 18:10:58 +000016882 putVReg( vD_addr, binop(Iop_Rol8x16, mkexpr(vA), mkexpr(vB)) );
cerion0a7b4f42005-09-16 07:54:40 +000016883 break;
cerion32aad402005-09-10 12:02:24 +000016884
16885 case 0x044: // vrlh (Rotate Left Integer HW, AV p235)
16886 DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj1bee5612005-11-10 18:10:58 +000016887 putVReg( vD_addr, binop(Iop_Rol16x8, mkexpr(vA), mkexpr(vB)) );
cerion0a7b4f42005-09-16 07:54:40 +000016888 break;
cerion32aad402005-09-10 12:02:24 +000016889
16890 case 0x084: // vrlw (Rotate Left Integer W, AV p236)
16891 DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj1bee5612005-11-10 18:10:58 +000016892 putVReg( vD_addr, binop(Iop_Rol32x4, mkexpr(vA), mkexpr(vB)) );
cerion0a7b4f42005-09-16 07:54:40 +000016893 break;
cerion32aad402005-09-10 12:02:24 +000016894
carll48ae46b2013-10-01 15:45:54 +000016895 case 0x0C4: // vrld (Rotate Left Integer Double Word)
16896 DIP("vrld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16897 putVReg( vD_addr, binop(Iop_Rol64x2, mkexpr(vA), mkexpr(vB)) );
16898 break;
16899
cerion32aad402005-09-10 12:02:24 +000016900
16901 /* Shift Left */
16902 case 0x104: // vslb (Shift Left Integer B, AV p240)
16903 DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016904 putVReg( vD_addr, binop(Iop_Shl8x16, mkexpr(vA), mkexpr(vB)) );
16905 break;
cerion32aad402005-09-10 12:02:24 +000016906
16907 case 0x144: // vslh (Shift Left Integer HW, AV p242)
16908 DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016909 putVReg( vD_addr, binop(Iop_Shl16x8, mkexpr(vA), mkexpr(vB)) );
16910 break;
cerion32aad402005-09-10 12:02:24 +000016911
16912 case 0x184: // vslw (Shift Left Integer W, AV p244)
16913 DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016914 putVReg( vD_addr, binop(Iop_Shl32x4, mkexpr(vA), mkexpr(vB)) );
16915 break;
cerion32aad402005-09-10 12:02:24 +000016916
carll48ae46b2013-10-01 15:45:54 +000016917 case 0x5C4: // vsld (Shift Left Integer Double Word)
16918 DIP("vsld v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16919 putVReg( vD_addr, binop(Iop_Shl64x2, mkexpr(vA), mkexpr(vB)) );
16920 break;
16921
cerion0a7b4f42005-09-16 07:54:40 +000016922 case 0x1C4: { // vsl (Shift Left, AV p239)
cerion0a7b4f42005-09-16 07:54:40 +000016923 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016924 DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016925 assign( sh, binop(Iop_And8, mkU8(0x7),
16926 unop(Iop_32to8,
16927 unop(Iop_V128to32, mkexpr(vB)))) );
16928 putVReg( vD_addr,
16929 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
16930 break;
16931 }
16932 case 0x40C: { // vslo (Shift Left by Octet, AV p243)
cerion0a7b4f42005-09-16 07:54:40 +000016933 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016934 DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016935 assign( sh, binop(Iop_And8, mkU8(0x78),
16936 unop(Iop_32to8,
16937 unop(Iop_V128to32, mkexpr(vB)))) );
16938 putVReg( vD_addr,
16939 binop(Iop_ShlV128, mkexpr(vA), mkexpr(sh)) );
16940 break;
16941 }
16942
cerion32aad402005-09-10 12:02:24 +000016943
16944 /* Shift Right */
16945 case 0x204: // vsrb (Shift Right B, AV p256)
16946 DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016947 putVReg( vD_addr, binop(Iop_Shr8x16, mkexpr(vA), mkexpr(vB)) );
16948 break;
cerion32aad402005-09-10 12:02:24 +000016949
16950 case 0x244: // vsrh (Shift Right HW, AV p257)
16951 DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016952 putVReg( vD_addr, binop(Iop_Shr16x8, mkexpr(vA), mkexpr(vB)) );
16953 break;
cerion32aad402005-09-10 12:02:24 +000016954
16955 case 0x284: // vsrw (Shift Right W, AV p259)
16956 DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016957 putVReg( vD_addr, binop(Iop_Shr32x4, mkexpr(vA), mkexpr(vB)) );
16958 break;
cerion32aad402005-09-10 12:02:24 +000016959
cerion27b3d7e2005-09-14 20:35:47 +000016960 case 0x2C4: { // vsr (Shift Right, AV p251)
cerion27b3d7e2005-09-14 20:35:47 +000016961 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016962 DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion27b3d7e2005-09-14 20:35:47 +000016963 assign( sh, binop(Iop_And8, mkU8(0x7),
16964 unop(Iop_32to8,
16965 unop(Iop_V128to32, mkexpr(vB)))) );
16966 putVReg( vD_addr,
16967 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
16968 break;
16969 }
cerion5b2325f2005-12-23 00:55:09 +000016970 case 0x304: // vsrab (Shift Right Alg B, AV p253)
cerion32aad402005-09-10 12:02:24 +000016971 DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016972 putVReg( vD_addr, binop(Iop_Sar8x16, mkexpr(vA), mkexpr(vB)) );
16973 break;
cerion32aad402005-09-10 12:02:24 +000016974
cerion5b2325f2005-12-23 00:55:09 +000016975 case 0x344: // vsrah (Shift Right Alg HW, AV p254)
cerion32aad402005-09-10 12:02:24 +000016976 DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016977 putVReg( vD_addr, binop(Iop_Sar16x8, mkexpr(vA), mkexpr(vB)) );
16978 break;
cerion32aad402005-09-10 12:02:24 +000016979
cerion5b2325f2005-12-23 00:55:09 +000016980 case 0x384: // vsraw (Shift Right Alg W, AV p255)
cerion32aad402005-09-10 12:02:24 +000016981 DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016982 putVReg( vD_addr, binop(Iop_Sar32x4, mkexpr(vA), mkexpr(vB)) );
16983 break;
cerion32aad402005-09-10 12:02:24 +000016984
carll48ae46b2013-10-01 15:45:54 +000016985 case 0x3C4: // vsrad (Shift Right Alg Double Word)
16986 DIP("vsrad v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
16987 putVReg( vD_addr, binop(Iop_Sar64x2, mkexpr(vA), mkexpr(vB)) );
16988 break;
16989
cerion0a7b4f42005-09-16 07:54:40 +000016990 case 0x44C: { // vsro (Shift Right by Octet, AV p258)
cerion0a7b4f42005-09-16 07:54:40 +000016991 IRTemp sh = newTemp(Ity_I8);
sewardj197bd172005-10-12 11:34:33 +000016992 DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion0a7b4f42005-09-16 07:54:40 +000016993 assign( sh, binop(Iop_And8, mkU8(0x78),
16994 unop(Iop_32to8,
16995 unop(Iop_V128to32, mkexpr(vB)))) );
16996 putVReg( vD_addr,
16997 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
16998 break;
16999 }
cerion32aad402005-09-10 12:02:24 +000017000
carll48ae46b2013-10-01 15:45:54 +000017001 case 0x6C4: // vsrd (Shift Right Double Word)
17002 DIP("vsrd v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17003 putVReg( vD_addr, binop(Iop_Shr64x2, mkexpr(vA), mkexpr(vB)) );
17004 break;
17005
17006
cerion32aad402005-09-10 12:02:24 +000017007 default:
cerion5b2325f2005-12-23 00:55:09 +000017008 vex_printf("dis_av_shift(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000017009 return False;
17010 }
17011 return True;
17012}
17013
17014/*
17015 AltiVec Permute Instructions
17016*/
17017static Bool dis_av_permute ( UInt theInstr )
17018{
cerion76de5cf2005-11-18 18:25:12 +000017019 /* VA-Form, VX-Form */
17020 UChar opc1 = ifieldOPC(theInstr);
17021 UChar vD_addr = ifieldRegDS(theInstr);
17022 UChar vA_addr = ifieldRegA(theInstr);
17023 UChar UIMM_5 = vA_addr;
17024 UChar vB_addr = ifieldRegB(theInstr);
17025 UChar vC_addr = ifieldRegC(theInstr);
17026 UChar b10 = ifieldBIT10(theInstr);
17027 UChar SHB_uimm4 = toUChar( IFIELD( theInstr, 6, 4 ) );
17028 UInt opc2 = toUChar( IFIELD( theInstr, 0, 6 ) );
cerion32aad402005-09-10 12:02:24 +000017029
cerion76de5cf2005-11-18 18:25:12 +000017030 UChar SIMM_8 = extend_s_5to8(UIMM_5);
cerion32aad402005-09-10 12:02:24 +000017031
cerion6e7a0ea2005-09-13 13:34:09 +000017032 IRTemp vA = newTemp(Ity_V128);
17033 IRTemp vB = newTemp(Ity_V128);
17034 IRTemp vC = newTemp(Ity_V128);
17035 assign( vA, getVReg(vA_addr));
17036 assign( vB, getVReg(vB_addr));
17037 assign( vC, getVReg(vC_addr));
17038
cerion32aad402005-09-10 12:02:24 +000017039 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000017040 vex_printf("dis_av_permute(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000017041 return False;
17042 }
17043
17044 switch (opc2) {
17045 case 0x2A: // vsel (Conditional Select, AV p238)
17046 DIP("vsel v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
cerion6e7a0ea2005-09-13 13:34:09 +000017047 /* vD = (vA & ~vC) | (vB & vC) */
17048 putVReg( vD_addr, binop(Iop_OrV128,
17049 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
17050 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
17051 return True;
cerion32aad402005-09-10 12:02:24 +000017052
cerion92d9d872005-09-15 21:58:50 +000017053 case 0x2B: { // vperm (Permute, AV p218)
cerion92d9d872005-09-15 21:58:50 +000017054 /* limited to two args for IR, so have to play games... */
sewardjdc1f9132005-10-22 12:49:49 +000017055 IRTemp a_perm = newTemp(Ity_V128);
17056 IRTemp b_perm = newTemp(Ity_V128);
17057 IRTemp mask = newTemp(Ity_V128);
17058 IRTemp vC_andF = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000017059 DIP("vperm v%d,v%d,v%d,v%d\n",
17060 vD_addr, vA_addr, vB_addr, vC_addr);
sewardjdc1f9132005-10-22 12:49:49 +000017061 /* Limit the Perm8x16 steering values to 0 .. 15 as that is what
17062 IR specifies, and also to hide irrelevant bits from
17063 memcheck */
cerion5b2325f2005-12-23 00:55:09 +000017064 assign( vC_andF,
17065 binop(Iop_AndV128, mkexpr(vC),
17066 unop(Iop_Dup8x16, mkU8(0xF))) );
17067 assign( a_perm,
17068 binop(Iop_Perm8x16, mkexpr(vA), mkexpr(vC_andF)) );
17069 assign( b_perm,
17070 binop(Iop_Perm8x16, mkexpr(vB), mkexpr(vC_andF)) );
cerion92d9d872005-09-15 21:58:50 +000017071 // mask[i8] = (vC[i8]_4 == 1) ? 0xFF : 0x0
17072 assign( mask, binop(Iop_SarN8x16,
17073 binop(Iop_ShlN8x16, mkexpr(vC), mkU8(3)),
17074 mkU8(7)) );
17075 // dst = (a & ~mask) | (b & mask)
17076 putVReg( vD_addr, binop(Iop_OrV128,
17077 binop(Iop_AndV128, mkexpr(a_perm),
17078 unop(Iop_NotV128, mkexpr(mask))),
17079 binop(Iop_AndV128, mkexpr(b_perm),
17080 mkexpr(mask))) );
17081 return True;
17082 }
cerion32aad402005-09-10 12:02:24 +000017083 case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
17084 if (b10 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000017085 vex_printf("dis_av_permute(ppc)(vsldoi)\n");
cerion32aad402005-09-10 12:02:24 +000017086 return False;
17087 }
cerion5b2325f2005-12-23 00:55:09 +000017088 DIP("vsldoi v%d,v%d,v%d,%d\n",
17089 vD_addr, vA_addr, vB_addr, SHB_uimm4);
cerion92d9d872005-09-15 21:58:50 +000017090 if (SHB_uimm4 == 0)
17091 putVReg( vD_addr, mkexpr(vA) );
17092 else
17093 putVReg( vD_addr,
cerion5b2325f2005-12-23 00:55:09 +000017094 binop(Iop_OrV128,
17095 binop(Iop_ShlV128, mkexpr(vA), mkU8(SHB_uimm4*8)),
17096 binop(Iop_ShrV128, mkexpr(vB), mkU8((16-SHB_uimm4)*8))) );
cerion92d9d872005-09-15 21:58:50 +000017097 return True;
carll7deaf952013-10-15 18:11:20 +000017098 case 0x2D: { // vpermxor (Vector Permute and Exclusive-OR)
17099 IRTemp a_perm = newTemp(Ity_V128);
17100 IRTemp b_perm = newTemp(Ity_V128);
17101 IRTemp vrc_a = newTemp(Ity_V128);
17102 IRTemp vrc_b = newTemp(Ity_V128);
cerion32aad402005-09-10 12:02:24 +000017103
carll7deaf952013-10-15 18:11:20 +000017104 /* IBM index is 0:7, Change index value to index 7:0 */
17105 assign( vrc_b, binop( Iop_AndV128, mkexpr( vC ),
17106 unop( Iop_Dup8x16, mkU8( 0xF ) ) ) );
17107 assign( vrc_a, binop( Iop_ShrV128,
17108 binop( Iop_AndV128, mkexpr( vC ),
17109 unop( Iop_Dup8x16, mkU8( 0xF0 ) ) ),
17110 mkU8 ( 4 ) ) );
17111 assign( a_perm, binop( Iop_Perm8x16, mkexpr( vA ), mkexpr( vrc_a ) ) );
17112 assign( b_perm, binop( Iop_Perm8x16, mkexpr( vB ), mkexpr( vrc_b ) ) );
17113 putVReg( vD_addr, binop( Iop_XorV128,
17114 mkexpr( a_perm ), mkexpr( b_perm) ) );
17115 return True;
17116 }
cerion32aad402005-09-10 12:02:24 +000017117 default:
17118 break; // Fall through...
17119 }
17120
cerion76de5cf2005-11-18 18:25:12 +000017121 opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000017122 switch (opc2) {
17123
17124 /* Merge */
17125 case 0x00C: // vmrghb (Merge High B, AV p195)
17126 DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017127 putVReg( vD_addr,
17128 binop(Iop_InterleaveHI8x16, mkexpr(vA), mkexpr(vB)) );
17129 break;
cerion32aad402005-09-10 12:02:24 +000017130
17131 case 0x04C: // vmrghh (Merge High HW, AV p196)
17132 DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017133 putVReg( vD_addr,
17134 binop(Iop_InterleaveHI16x8, mkexpr(vA), mkexpr(vB)) );
17135 break;
cerion32aad402005-09-10 12:02:24 +000017136
17137 case 0x08C: // vmrghw (Merge High W, AV p197)
17138 DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017139 putVReg( vD_addr,
17140 binop(Iop_InterleaveHI32x4, mkexpr(vA), mkexpr(vB)) );
17141 break;
cerion32aad402005-09-10 12:02:24 +000017142
17143 case 0x10C: // vmrglb (Merge Low B, AV p198)
17144 DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017145 putVReg( vD_addr,
17146 binop(Iop_InterleaveLO8x16, mkexpr(vA), mkexpr(vB)) );
17147 break;
cerion32aad402005-09-10 12:02:24 +000017148
17149 case 0x14C: // vmrglh (Merge Low HW, AV p199)
17150 DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017151 putVReg( vD_addr,
17152 binop(Iop_InterleaveLO16x8, mkexpr(vA), mkexpr(vB)) );
17153 break;
cerion32aad402005-09-10 12:02:24 +000017154
17155 case 0x18C: // vmrglw (Merge Low W, AV p200)
17156 DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion92d9d872005-09-15 21:58:50 +000017157 putVReg( vD_addr,
17158 binop(Iop_InterleaveLO32x4, mkexpr(vA), mkexpr(vB)) );
17159 break;
17160
cerion32aad402005-09-10 12:02:24 +000017161
17162 /* Splat */
cerion92d9d872005-09-15 21:58:50 +000017163 case 0x20C: { // vspltb (Splat Byte, AV p245)
cerion92d9d872005-09-15 21:58:50 +000017164 /* vD = Dup8x16( vB[UIMM_5] ) */
sewardjd1470942005-10-22 02:01:16 +000017165 UChar sh_uimm = (15 - (UIMM_5 & 15)) * 8;
sewardj197bd172005-10-12 11:34:33 +000017166 DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
cerion92d9d872005-09-15 21:58:50 +000017167 putVReg( vD_addr, unop(Iop_Dup8x16,
17168 unop(Iop_32to8, unop(Iop_V128to32,
17169 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
17170 break;
17171 }
17172 case 0x24C: { // vsplth (Splat Half Word, AV p246)
sewardjd1470942005-10-22 02:01:16 +000017173 UChar sh_uimm = (7 - (UIMM_5 & 7)) * 16;
sewardj197bd172005-10-12 11:34:33 +000017174 DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
cerion92d9d872005-09-15 21:58:50 +000017175 putVReg( vD_addr, unop(Iop_Dup16x8,
17176 unop(Iop_32to16, unop(Iop_V128to32,
17177 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
17178 break;
17179 }
cerion27b3d7e2005-09-14 20:35:47 +000017180 case 0x28C: { // vspltw (Splat Word, AV p250)
cerion27b3d7e2005-09-14 20:35:47 +000017181 /* vD = Dup32x4( vB[UIMM_5] ) */
sewardjd1470942005-10-22 02:01:16 +000017182 UChar sh_uimm = (3 - (UIMM_5 & 3)) * 32;
sewardj197bd172005-10-12 11:34:33 +000017183 DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
cerion27b3d7e2005-09-14 20:35:47 +000017184 putVReg( vD_addr, unop(Iop_Dup32x4,
17185 unop(Iop_V128to32,
17186 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm)))) );
17187 break;
17188 }
cerion32aad402005-09-10 12:02:24 +000017189 case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
17190 DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
cerion92d9d872005-09-15 21:58:50 +000017191 putVReg( vD_addr, unop(Iop_Dup8x16, mkU8(SIMM_8)) );
17192 break;
cerion32aad402005-09-10 12:02:24 +000017193
17194 case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
17195 DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
cerion5b2325f2005-12-23 00:55:09 +000017196 putVReg( vD_addr,
17197 unop(Iop_Dup16x8, mkU16(extend_s_8to32(SIMM_8))) );
cerion92d9d872005-09-15 21:58:50 +000017198 break;
cerion32aad402005-09-10 12:02:24 +000017199
17200 case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
17201 DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
cerion5b2325f2005-12-23 00:55:09 +000017202 putVReg( vD_addr,
17203 unop(Iop_Dup32x4, mkU32(extend_s_8to32(SIMM_8))) );
cerion92d9d872005-09-15 21:58:50 +000017204 break;
cerion32aad402005-09-10 12:02:24 +000017205
carll48ae46b2013-10-01 15:45:54 +000017206 case 0x68C: // vmrgow (Merge Odd Word)
17207 DIP("vmrgow v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17208 /* VD[0] <- VA[1]
17209 VD[1] <- VB[1]
17210 VD[2] <- VA[3]
17211 VD[3] <- VB[3]
17212 */
17213 putVReg( vD_addr,
17214 binop(Iop_CatOddLanes32x4, mkexpr(vA), mkexpr(vB) ) );
17215 break;
17216
17217 case 0x78C: // vmrgew (Merge Even Word)
17218 DIP("vmrgew v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17219 /* VD[0] <- VA[0]
17220 VD[1] <- VB[0]
17221 VD[2] <- VA[2]
17222 VD[3] <- VB[2]
17223 */
17224 putVReg( vD_addr,
17225 binop(Iop_CatEvenLanes32x4, mkexpr(vA), mkexpr(vB) ) );
17226 break;
17227
cerion32aad402005-09-10 12:02:24 +000017228 default:
cerion5b2325f2005-12-23 00:55:09 +000017229 vex_printf("dis_av_permute(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000017230 return False;
17231 }
17232 return True;
17233}
17234
17235/*
17236 AltiVec Pack/Unpack Instructions
17237*/
17238static Bool dis_av_pack ( UInt theInstr )
17239{
cerion76de5cf2005-11-18 18:25:12 +000017240 /* VX-Form */
17241 UChar opc1 = ifieldOPC(theInstr);
17242 UChar vD_addr = ifieldRegDS(theInstr);
17243 UChar vA_addr = ifieldRegA(theInstr);
17244 UChar vB_addr = ifieldRegB(theInstr);
17245 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000017246
sewardj197bd172005-10-12 11:34:33 +000017247 IRTemp signs = IRTemp_INVALID;
17248 IRTemp zeros = IRTemp_INVALID;
cerion76de5cf2005-11-18 18:25:12 +000017249 IRTemp vA = newTemp(Ity_V128);
17250 IRTemp vB = newTemp(Ity_V128);
cerion3c052792005-09-16 07:13:44 +000017251 assign( vA, getVReg(vA_addr));
17252 assign( vB, getVReg(vB_addr));
17253
cerion32aad402005-09-10 12:02:24 +000017254 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000017255 vex_printf("dis_av_pack(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000017256 return False;
17257 }
cerion32aad402005-09-10 12:02:24 +000017258 switch (opc2) {
17259 /* Packing */
17260 case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224)
17261 DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj5f438dd2011-06-16 11:36:23 +000017262 putVReg( vD_addr,
17263 binop(Iop_NarrowBin16to8x16, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017264 return True;
cerion32aad402005-09-10 12:02:24 +000017265
17266 case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226)
17267 DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj5f438dd2011-06-16 11:36:23 +000017268 putVReg( vD_addr,
17269 binop(Iop_NarrowBin32to16x8, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017270 return True;
cerion32aad402005-09-10 12:02:24 +000017271
17272 case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225)
17273 DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017274 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017275 binop(Iop_QNarrowBin16Uto8Ux16, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017276 // TODO: set VSCR[SAT]
17277 return True;
cerion32aad402005-09-10 12:02:24 +000017278
17279 case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227)
17280 DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017281 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017282 binop(Iop_QNarrowBin32Uto16Ux8, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017283 // TODO: set VSCR[SAT]
17284 return True;
cerion32aad402005-09-10 12:02:24 +000017285
cerion3c052792005-09-16 07:13:44 +000017286 case 0x10E: { // vpkshus (Pack Signed HW Unsigned Saturate, AV p221)
cerion3c052792005-09-16 07:13:44 +000017287 // This insn does a signed->unsigned saturating conversion.
17288 // Conversion done here, then uses unsigned->unsigned vpk insn:
17289 // => UnsignedSaturatingNarrow( x & ~ (x >>s 15) )
17290 IRTemp vA_tmp = newTemp(Ity_V128);
17291 IRTemp vB_tmp = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017292 DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017293 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
17294 unop(Iop_NotV128,
17295 binop(Iop_SarN16x8,
17296 mkexpr(vA), mkU8(15)))) );
17297 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
17298 unop(Iop_NotV128,
17299 binop(Iop_SarN16x8,
17300 mkexpr(vB), mkU8(15)))) );
sewardj5f438dd2011-06-16 11:36:23 +000017301 putVReg( vD_addr, binop(Iop_QNarrowBin16Uto8Ux16,
cerion3c052792005-09-16 07:13:44 +000017302 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
17303 // TODO: set VSCR[SAT]
17304 return True;
17305 }
17306 case 0x14E: { // vpkswus (Pack Signed W Unsigned Saturate, AV p223)
cerion3c052792005-09-16 07:13:44 +000017307 // This insn does a signed->unsigned saturating conversion.
17308 // Conversion done here, then uses unsigned->unsigned vpk insn:
17309 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
17310 IRTemp vA_tmp = newTemp(Ity_V128);
17311 IRTemp vB_tmp = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017312 DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017313 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
17314 unop(Iop_NotV128,
17315 binop(Iop_SarN32x4,
17316 mkexpr(vA), mkU8(31)))) );
17317 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
17318 unop(Iop_NotV128,
17319 binop(Iop_SarN32x4,
17320 mkexpr(vB), mkU8(31)))) );
sewardj5f438dd2011-06-16 11:36:23 +000017321 putVReg( vD_addr, binop(Iop_QNarrowBin32Uto16Ux8,
cerion3c052792005-09-16 07:13:44 +000017322 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
17323 // TODO: set VSCR[SAT]
17324 return True;
17325 }
cerion32aad402005-09-10 12:02:24 +000017326 case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220)
17327 DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017328 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017329 binop(Iop_QNarrowBin16Sto8Sx16, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017330 // TODO: set VSCR[SAT]
17331 return True;
cerion32aad402005-09-10 12:02:24 +000017332
17333 case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222)
17334 DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion5b2325f2005-12-23 00:55:09 +000017335 putVReg( vD_addr,
sewardj5f438dd2011-06-16 11:36:23 +000017336 binop(Iop_QNarrowBin32Sto16Sx8, mkexpr(vA), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017337 // TODO: set VSCR[SAT]
17338 return True;
cerion32aad402005-09-10 12:02:24 +000017339
cerion3c052792005-09-16 07:13:44 +000017340 case 0x30E: { // vpkpx (Pack Pixel, AV p219)
cerion3c052792005-09-16 07:13:44 +000017341 /* CAB: Worth a new primop? */
cerion5b2325f2005-12-23 00:55:09 +000017342 /* Using shifts to compact pixel elements, then packing them */
cerion3c052792005-09-16 07:13:44 +000017343 IRTemp a1 = newTemp(Ity_V128);
17344 IRTemp a2 = newTemp(Ity_V128);
17345 IRTemp a3 = newTemp(Ity_V128);
17346 IRTemp a_tmp = newTemp(Ity_V128);
17347 IRTemp b1 = newTemp(Ity_V128);
17348 IRTemp b2 = newTemp(Ity_V128);
17349 IRTemp b3 = newTemp(Ity_V128);
17350 IRTemp b_tmp = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017351 DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017352 assign( a1, binop(Iop_ShlN16x8,
17353 binop(Iop_ShrN32x4, mkexpr(vA), mkU8(19)),
17354 mkU8(10)) );
17355 assign( a2, binop(Iop_ShlN16x8,
17356 binop(Iop_ShrN16x8, mkexpr(vA), mkU8(11)),
17357 mkU8(5)) );
17358 assign( a3, binop(Iop_ShrN16x8,
17359 binop(Iop_ShlN16x8, mkexpr(vA), mkU8(8)),
17360 mkU8(11)) );
17361 assign( a_tmp, binop(Iop_OrV128, mkexpr(a1),
17362 binop(Iop_OrV128, mkexpr(a2), mkexpr(a3))) );
17363
17364 assign( b1, binop(Iop_ShlN16x8,
17365 binop(Iop_ShrN32x4, mkexpr(vB), mkU8(19)),
17366 mkU8(10)) );
17367 assign( b2, binop(Iop_ShlN16x8,
17368 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(11)),
17369 mkU8(5)) );
17370 assign( b3, binop(Iop_ShrN16x8,
17371 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(8)),
17372 mkU8(11)) );
17373 assign( b_tmp, binop(Iop_OrV128, mkexpr(b1),
17374 binop(Iop_OrV128, mkexpr(b2), mkexpr(b3))) );
17375
sewardj5f438dd2011-06-16 11:36:23 +000017376 putVReg( vD_addr, binop(Iop_NarrowBin32to16x8,
cerion3c052792005-09-16 07:13:44 +000017377 mkexpr(a_tmp), mkexpr(b_tmp)) );
17378 return True;
17379 }
cerion32aad402005-09-10 12:02:24 +000017380
carll0c74bb52013-08-12 18:01:40 +000017381 case 0x44E: // vpkudum (Pack Unsigned Double Word Unsigned Modulo)
17382 DIP("vpkudum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17383 putVReg( vD_addr,
17384 binop(Iop_NarrowBin64to32x4, mkexpr(vA), mkexpr(vB)) );
17385 return True;
17386
carll48ae46b2013-10-01 15:45:54 +000017387 case 0x4CE: // vpkudus (Pack Unsigned Double Word Unsigned Saturate)
17388 DIP("vpkudus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17389 putVReg( vD_addr,
17390 binop(Iop_QNarrowBin64Uto32Ux4, mkexpr(vA), mkexpr(vB)) );
17391 // TODO: set VSCR[SAT]
17392 return True;
17393
17394 case 0x54E: { // vpksdus (Pack Signed Double Word Unsigned Saturate)
17395 // This insn does a doubled signed->double unsigned saturating conversion
17396 // Conversion done here, then uses unsigned->unsigned vpk insn:
17397 // => UnsignedSaturatingNarrow( x & ~ (x >>s 31) )
17398 // This is similar to the technique used for vpkswus, except done
17399 // with double word integers versus word integers.
17400 IRTemp vA_tmp = newTemp(Ity_V128);
17401 IRTemp vB_tmp = newTemp(Ity_V128);
17402 DIP("vpksdus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17403 assign( vA_tmp, binop(Iop_AndV128, mkexpr(vA),
17404 unop(Iop_NotV128,
17405 binop(Iop_SarN64x2,
17406 mkexpr(vA), mkU8(63)))) );
17407 assign( vB_tmp, binop(Iop_AndV128, mkexpr(vB),
17408 unop(Iop_NotV128,
17409 binop(Iop_SarN64x2,
17410 mkexpr(vB), mkU8(63)))) );
17411 putVReg( vD_addr, binop(Iop_QNarrowBin64Uto32Ux4,
17412 mkexpr(vA_tmp), mkexpr(vB_tmp)) );
17413 // TODO: set VSCR[SAT]
17414 return True;
17415 }
17416
17417 case 0x5CE: // vpksdss (Pack Signed double word Signed Saturate)
17418 DIP("vpksdss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17419 putVReg( vD_addr,
17420 binop(Iop_QNarrowBin64Sto32Sx4, mkexpr(vA), mkexpr(vB)) );
17421 // TODO: set VSCR[SAT]
17422 return True;
cerion32aad402005-09-10 12:02:24 +000017423 default:
17424 break; // Fall through...
17425 }
17426
17427
17428 if (vA_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000017429 vex_printf("dis_av_pack(ppc)(vA_addr)\n");
cerion32aad402005-09-10 12:02:24 +000017430 return False;
17431 }
17432
sewardj197bd172005-10-12 11:34:33 +000017433 signs = newTemp(Ity_V128);
17434 zeros = newTemp(Ity_V128);
cerion3c052792005-09-16 07:13:44 +000017435 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
17436
cerion32aad402005-09-10 12:02:24 +000017437 switch (opc2) {
17438 /* Unpacking */
cerion3c052792005-09-16 07:13:44 +000017439 case 0x20E: { // vupkhsb (Unpack High Signed B, AV p277)
cerion32aad402005-09-10 12:02:24 +000017440 DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017441 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017442 putVReg( vD_addr,
17443 binop(Iop_InterleaveHI8x16, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017444 break;
17445 }
17446 case 0x24E: { // vupkhsh (Unpack High Signed HW, AV p278)
cerion32aad402005-09-10 12:02:24 +000017447 DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017448 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017449 putVReg( vD_addr,
17450 binop(Iop_InterleaveHI16x8, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017451 break;
17452 }
17453 case 0x28E: { // vupklsb (Unpack Low Signed B, AV p280)
cerion32aad402005-09-10 12:02:24 +000017454 DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017455 assign( signs, binop(Iop_CmpGT8Sx16, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017456 putVReg( vD_addr,
17457 binop(Iop_InterleaveLO8x16, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017458 break;
17459 }
17460 case 0x2CE: { // vupklsh (Unpack Low Signed HW, AV p281)
cerion32aad402005-09-10 12:02:24 +000017461 DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017462 assign( signs, binop(Iop_CmpGT16Sx8, mkexpr(zeros), mkexpr(vB)) );
cerion5b2325f2005-12-23 00:55:09 +000017463 putVReg( vD_addr,
17464 binop(Iop_InterleaveLO16x8, mkexpr(signs), mkexpr(vB)) );
cerion3c052792005-09-16 07:13:44 +000017465 break;
17466 }
17467 case 0x34E: { // vupkhpx (Unpack High Pixel16, AV p276)
cerion3c052792005-09-16 07:13:44 +000017468 /* CAB: Worth a new primop? */
17469 /* Using shifts to isolate pixel elements, then expanding them */
17470 IRTemp z0 = newTemp(Ity_V128);
17471 IRTemp z1 = newTemp(Ity_V128);
17472 IRTemp z01 = newTemp(Ity_V128);
17473 IRTemp z2 = newTemp(Ity_V128);
17474 IRTemp z3 = newTemp(Ity_V128);
17475 IRTemp z23 = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017476 DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017477 assign( z0, binop(Iop_ShlN16x8,
17478 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
17479 mkU8(8)) );
17480 assign( z1, binop(Iop_ShrN16x8,
17481 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
17482 mkU8(11)) );
17483 assign( z01, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
17484 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
17485 assign( z2, binop(Iop_ShrN16x8,
17486 binop(Iop_ShlN16x8,
17487 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
17488 mkU8(11)),
17489 mkU8(3)) );
17490 assign( z3, binop(Iop_ShrN16x8,
17491 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
17492 mkU8(11)) );
17493 assign( z23, binop(Iop_InterleaveHI16x8, mkexpr(zeros),
17494 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
cerion5b2325f2005-12-23 00:55:09 +000017495 putVReg( vD_addr,
17496 binop(Iop_OrV128,
17497 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
17498 mkexpr(z23)) );
cerion3c052792005-09-16 07:13:44 +000017499 break;
17500 }
17501 case 0x3CE: { // vupklpx (Unpack Low Pixel16, AV p279)
cerion3c052792005-09-16 07:13:44 +000017502 /* identical to vupkhpx, except interleaving LO */
17503 IRTemp z0 = newTemp(Ity_V128);
17504 IRTemp z1 = newTemp(Ity_V128);
17505 IRTemp z01 = newTemp(Ity_V128);
17506 IRTemp z2 = newTemp(Ity_V128);
17507 IRTemp z3 = newTemp(Ity_V128);
17508 IRTemp z23 = newTemp(Ity_V128);
sewardj197bd172005-10-12 11:34:33 +000017509 DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr);
cerion3c052792005-09-16 07:13:44 +000017510 assign( z0, binop(Iop_ShlN16x8,
17511 binop(Iop_SarN16x8, mkexpr(vB), mkU8(15)),
17512 mkU8(8)) );
17513 assign( z1, binop(Iop_ShrN16x8,
17514 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(1)),
17515 mkU8(11)) );
17516 assign( z01, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
17517 binop(Iop_OrV128, mkexpr(z0), mkexpr(z1))) );
17518 assign( z2, binop(Iop_ShrN16x8,
17519 binop(Iop_ShlN16x8,
17520 binop(Iop_ShrN16x8, mkexpr(vB), mkU8(5)),
17521 mkU8(11)),
17522 mkU8(3)) );
17523 assign( z3, binop(Iop_ShrN16x8,
17524 binop(Iop_ShlN16x8, mkexpr(vB), mkU8(11)),
17525 mkU8(11)) );
17526 assign( z23, binop(Iop_InterleaveLO16x8, mkexpr(zeros),
17527 binop(Iop_OrV128, mkexpr(z2), mkexpr(z3))) );
cerion5b2325f2005-12-23 00:55:09 +000017528 putVReg( vD_addr,
17529 binop(Iop_OrV128,
17530 binop(Iop_ShlN32x4, mkexpr(z01), mkU8(16)),
17531 mkexpr(z23)) );
cerion3c052792005-09-16 07:13:44 +000017532 break;
17533 }
carll48ae46b2013-10-01 15:45:54 +000017534 case 0x64E: { // vupkhsw (Unpack High Signed Word)
17535 DIP("vupkhsw v%d,v%d\n", vD_addr, vB_addr);
17536 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
17537 putVReg( vD_addr,
17538 binop(Iop_InterleaveHI32x4, mkexpr(signs), mkexpr(vB)) );
17539 break;
17540 }
17541 case 0x6CE: { // vupklsw (Unpack Low Signed Word)
17542 DIP("vupklsw v%d,v%d\n", vD_addr, vB_addr);
17543 assign( signs, binop(Iop_CmpGT32Sx4, mkexpr(zeros), mkexpr(vB)) );
17544 putVReg( vD_addr,
17545 binop(Iop_InterleaveLO32x4, mkexpr(signs), mkexpr(vB)) );
17546 break;
17547 }
cerion32aad402005-09-10 12:02:24 +000017548 default:
cerion5b2325f2005-12-23 00:55:09 +000017549 vex_printf("dis_av_pack(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000017550 return False;
17551 }
17552 return True;
17553}
17554
carll7deaf952013-10-15 18:11:20 +000017555/*
17556 AltiVec Cipher Instructions
17557*/
17558static Bool dis_av_cipher ( UInt theInstr )
17559{
17560 /* VX-Form */
17561 UChar opc1 = ifieldOPC(theInstr);
17562 UChar vD_addr = ifieldRegDS(theInstr);
17563 UChar vA_addr = ifieldRegA(theInstr);
17564 UChar vB_addr = ifieldRegB(theInstr);
17565 UInt opc2 = IFIELD( theInstr, 0, 11 );
17566
17567 IRTemp vA = newTemp(Ity_V128);
17568 IRTemp vB = newTemp(Ity_V128);
17569 assign( vA, getVReg(vA_addr));
17570 assign( vB, getVReg(vB_addr));
17571
17572 if (opc1 != 0x4) {
17573 vex_printf("dis_av_cipher(ppc)(instr)\n");
17574 return False;
17575 }
17576 switch (opc2) {
17577 case 0x508: // vcipher (Vector Inverser Cipher)
17578 DIP("vcipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17579 putVReg( vD_addr,
17580 binop(Iop_CipherV128, mkexpr(vA), mkexpr(vB)) );
17581 return True;
17582
17583 case 0x509: // vcipherlast (Vector Inverser Cipher Last)
17584 DIP("vcipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17585 putVReg( vD_addr,
17586 binop(Iop_CipherLV128, mkexpr(vA), mkexpr(vB)) );
17587 return True;
17588
17589 case 0x548: // vncipher (Vector Inverser Cipher)
17590 DIP("vncipher v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17591 putVReg( vD_addr,
17592 binop(Iop_NCipherV128, mkexpr(vA), mkexpr(vB)) );
17593 return True;
17594
17595 case 0x549: // vncipherlast (Vector Inverser Cipher Last)
17596 DIP("vncipherlast v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
17597 putVReg( vD_addr,
17598 binop(Iop_NCipherLV128, mkexpr(vA), mkexpr(vB)) );
17599 return True;
17600
17601 case 0x5C8: /* vsbox (Vector SubBytes, this does the cipher
17602 * subBytes transform)
17603 */
17604 DIP("vsbox v%d,v%d\n", vD_addr, vA_addr);
17605 putVReg( vD_addr,
17606 unop(Iop_CipherSV128, mkexpr(vA) ) );
17607 return True;
17608
17609 default:
17610 vex_printf("dis_av_cipher(ppc)(opc2)\n");
17611 return False;
17612 }
17613 return True;
17614}
17615
17616/*
17617 AltiVec Secure Hash Instructions
17618*/
17619static Bool dis_av_hash ( UInt theInstr )
17620{
17621 /* VX-Form */
17622 UChar opc1 = ifieldOPC(theInstr);
17623 UChar vRT_addr = ifieldRegDS(theInstr);
17624 UChar vRA_addr = ifieldRegA(theInstr);
17625 UChar s_field = IFIELD( theInstr, 11, 5 ); // st and six field
17626 UChar st = IFIELD( theInstr, 15, 1 ); // st
17627 UChar six = IFIELD( theInstr, 11, 4 ); // six field
17628 UInt opc2 = IFIELD( theInstr, 0, 11 );
17629
17630 IRTemp vA = newTemp(Ity_V128);
17631 IRTemp dst = newTemp(Ity_V128);
17632 assign( vA, getVReg(vRA_addr));
17633
17634 if (opc1 != 0x4) {
17635 vex_printf("dis_av_hash(ppc)(instr)\n");
17636 return False;
17637 }
17638
17639 switch (opc2) {
17640 case 0x682: // vshasigmaw
17641 DIP("vshasigmaw v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
17642 assign( dst, binop( Iop_SHA256, mkexpr( vA ), mkU8( s_field) ) );
17643 putVReg( vRT_addr, mkexpr(dst));
17644 return True;
17645
17646 case 0x6C2: // vshasigmad,
17647 DIP("vshasigmad v%d,v%d,%u,%u\n", vRT_addr, vRA_addr, st, six);
17648 putVReg( vRT_addr, binop( Iop_SHA512, mkexpr( vA ), mkU8( s_field) ) );
17649 return True;
17650
17651 default:
17652 vex_printf("dis_av_hash(ppc)(opc2)\n");
17653 return False;
17654 }
17655 return True;
17656}
17657
17658/*
carll60c6bac2013-10-18 01:19:06 +000017659 * This function is used by the Vector add/subtract [extended] modulo/carry
17660 * instructions.
17661 * - For the non-extended add instructions, the cin arg is set to zero.
17662 * - For the extended add instructions, cin is the integer value of
17663 * src3.bit[127].
17664 * - For the non-extended subtract instructions, src1 is added to the one's
17665 * complement of src2 + 1. We re-use the cin argument to hold the '1'
17666 * value for this operation.
17667 * - For the extended subtract instructions, cin is the integer value of src3.bit[127].
17668 */
17669static IRTemp _get_quad_modulo_or_carry(IRExpr * vecA, IRExpr * vecB,
17670 IRExpr * cin, Bool modulo)
17671{
17672 IRTemp _vecA_32 = IRTemp_INVALID;
17673 IRTemp _vecB_32 = IRTemp_INVALID;
17674 IRTemp res_32 = IRTemp_INVALID;
17675 IRTemp result = IRTemp_INVALID;
17676 IRTemp tmp_result = IRTemp_INVALID;
17677 IRTemp carry = IRTemp_INVALID;
17678 Int i;
17679 IRExpr * _vecA_low64 = unop( Iop_V128to64, vecA );
17680 IRExpr * _vecB_low64 = unop( Iop_V128to64, vecB );
17681 IRExpr * _vecA_high64 = unop( Iop_V128HIto64, vecA );
17682 IRExpr * _vecB_high64 = unop( Iop_V128HIto64, vecB );
17683
17684 for (i = 0; i < 4; i++) {
17685 _vecA_32 = newTemp(Ity_I32);
17686 _vecB_32 = newTemp(Ity_I32);
17687 res_32 = newTemp(Ity_I32);
17688 switch (i) {
17689 case 0:
17690 assign(_vecA_32, unop( Iop_64to32, _vecA_low64 ) );
17691 assign(_vecB_32, unop( Iop_64to32, _vecB_low64 ) );
17692 break;
17693 case 1:
17694 assign(_vecA_32, unop( Iop_64HIto32, _vecA_low64 ) );
17695 assign(_vecB_32, unop( Iop_64HIto32, _vecB_low64 ) );
17696 break;
17697 case 2:
17698 assign(_vecA_32, unop( Iop_64to32, _vecA_high64 ) );
17699 assign(_vecB_32, unop( Iop_64to32, _vecB_high64 ) );
17700 break;
17701 case 3:
17702 assign(_vecA_32, unop( Iop_64HIto32, _vecA_high64 ) );
17703 assign(_vecB_32, unop( Iop_64HIto32, _vecB_high64 ) );
17704 break;
17705 }
17706
17707 assign(res_32, binop( Iop_Add32,
17708 binop( Iop_Add32,
17709 binop ( Iop_Add32,
17710 mkexpr(_vecA_32),
17711 mkexpr(_vecB_32) ),
17712 (i == 0) ? mkU32(0) : mkexpr(carry) ),
17713 (i == 0) ? cin : mkU32(0) ) );
17714 if (modulo) {
17715 result = newTemp(Ity_V128);
17716 assign(result, binop( Iop_OrV128,
17717 (i == 0) ? binop( Iop_64HLtoV128,
17718 mkU64(0),
17719 mkU64(0) ) : mkexpr(tmp_result),
17720 binop( Iop_ShlV128,
17721 binop( Iop_64HLtoV128,
17722 mkU64(0),
17723 binop( Iop_32HLto64,
17724 mkU32(0),
17725 mkexpr(res_32) ) ),
17726 mkU8(i * 32) ) ) );
17727 tmp_result = newTemp(Ity_V128);
17728 assign(tmp_result, mkexpr(result));
17729 }
17730 carry = newTemp(Ity_I32);
17731 assign(carry, unop(Iop_1Uto32, binop( Iop_CmpLT32U,
17732 mkexpr(res_32),
17733 mkexpr(_vecA_32 ) ) ) );
17734 }
17735 if (modulo)
17736 return result;
17737 else
17738 return carry;
17739}
17740
17741
17742static Bool dis_av_quad ( UInt theInstr )
17743{
17744 /* VX-Form */
17745 UChar opc1 = ifieldOPC(theInstr);
17746 UChar vRT_addr = ifieldRegDS(theInstr);
17747 UChar vRA_addr = ifieldRegA(theInstr);
17748 UChar vRB_addr = ifieldRegB(theInstr);
17749 UChar vRC_addr;
17750 UInt opc2 = IFIELD( theInstr, 0, 11 );
17751
17752 IRTemp vA = newTemp(Ity_V128);
17753 IRTemp vB = newTemp(Ity_V128);
17754 IRTemp vC = IRTemp_INVALID;
17755 IRTemp cin = IRTemp_INVALID;
17756 assign( vA, getVReg(vRA_addr));
17757 assign( vB, getVReg(vRB_addr));
17758
17759 if (opc1 != 0x4) {
17760 vex_printf("dis_av_quad(ppc)(instr)\n");
17761 return False;
17762 }
17763
17764 switch (opc2) {
17765 case 0x140: // vaddcuq
17766 DIP("vaddcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17767 putVReg( vRT_addr, unop( Iop_32UtoV128,
17768 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17769 mkexpr(vB),
17770 mkU32(0), False) ) ) );
17771 return True;
17772 case 0x100: // vadduqm
17773 DIP("vadduqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17774 putVReg( vRT_addr, mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17775 mkexpr(vB), mkU32(0), True) ) );
17776 return True;
17777 case 0x540: // vsubcuq
17778 DIP("vsubcuq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17779 putVReg( vRT_addr,
17780 unop( Iop_32UtoV128,
17781 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17782 unop( Iop_NotV128,
17783 mkexpr(vB) ),
17784 mkU32(1), False) ) ) );
17785 return True;
17786 case 0x500: // vsubuqm
17787 DIP("vsubuqm v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17788 putVReg( vRT_addr,
17789 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17790 unop( Iop_NotV128, mkexpr(vB) ),
17791 mkU32(1), True) ) );
17792 return True;
17793 case 0x054C: // vbpermq
17794 {
17795#define BPERMD_IDX_MASK 0x00000000000000FFULL
17796#define BPERMD_BIT_MASK 0x8000000000000000ULL
17797 int i;
17798 IRExpr * vB_expr = mkexpr(vB);
17799 IRExpr * res = binop(Iop_AndV128, mkV128(0), mkV128(0));
17800 DIP("vbpermq v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr);
17801 for (i = 0; i < 16; i++) {
17802 IRTemp idx_tmp = newTemp( Ity_V128 );
17803 IRTemp perm_bit = newTemp( Ity_V128 );
17804 IRTemp idx = newTemp( Ity_I8 );
17805 IRTemp idx_LT127 = newTemp( Ity_I1 );
17806 IRTemp idx_LT127_ity128 = newTemp( Ity_V128 );
17807
17808 assign( idx_tmp,
17809 binop( Iop_AndV128,
17810 binop( Iop_64HLtoV128,
17811 mkU64(0),
17812 mkU64(BPERMD_IDX_MASK) ),
17813 vB_expr ) );
17814 assign( idx_LT127,
17815 binop( Iop_CmpEQ32,
17816 unop ( Iop_64to32,
17817 unop( Iop_V128to64, binop( Iop_ShrV128,
17818 mkexpr(idx_tmp),
17819 mkU8(7) ) ) ),
17820 mkU32(0) ) );
17821
17822 /* Below, we set idx to determine which bit of vA to use for the
17823 * perm bit. If idx_LT127 is 0, the perm bit is forced to '0'.
17824 */
17825 assign( idx,
17826 binop( Iop_And8,
17827 unop( Iop_1Sto8,
17828 mkexpr(idx_LT127) ),
17829 unop( Iop_32to8,
17830 unop( Iop_V128to32, mkexpr( idx_tmp ) ) ) ) );
17831
17832 assign( idx_LT127_ity128,
17833 binop( Iop_64HLtoV128,
17834 mkU64(0),
17835 unop( Iop_32Uto64,
17836 unop( Iop_1Uto32, mkexpr(idx_LT127 ) ) ) ) );
17837 assign( perm_bit,
17838 binop( Iop_AndV128,
17839 mkexpr( idx_LT127_ity128 ),
17840 binop( Iop_ShrV128,
17841 binop( Iop_AndV128,
17842 binop (Iop_64HLtoV128,
17843 mkU64( BPERMD_BIT_MASK ),
17844 mkU64(0)),
17845 binop( Iop_ShlV128,
17846 mkexpr( vA ),
17847 mkexpr( idx ) ) ),
17848 mkU8( 127 ) ) ) );
17849 res = binop( Iop_OrV128,
17850 res,
17851 binop( Iop_ShlV128,
17852 mkexpr( perm_bit ),
17853 mkU8( i ) ) );
17854 vB_expr = binop( Iop_ShrV128, vB_expr, mkU8( 8 ) );
17855 }
17856 putVReg( vRT_addr, res);
17857 return True;
17858#undef BPERMD_IDX_MASK
17859#undef BPERMD_BIT_MASK
17860 }
17861
17862 default:
17863 break; // fall through
17864 }
17865
17866 opc2 = IFIELD( theInstr, 0, 6 );
17867 vRC_addr = ifieldRegC(theInstr);
17868 vC = newTemp(Ity_V128);
17869 cin = newTemp(Ity_I32);
17870 switch (opc2) {
17871 case 0x3D: // vaddecuq
17872 assign( vC, getVReg(vRC_addr));
17873 DIP("vaddecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17874 vRC_addr);
17875 assign(cin, binop( Iop_And32,
17876 unop( Iop_64to32,
17877 unop( Iop_V128to64, mkexpr(vC) ) ),
17878 mkU32(1) ) );
17879 putVReg( vRT_addr,
17880 unop( Iop_32UtoV128,
17881 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
17882 mkexpr(cin),
17883 False) ) ) );
17884 return True;
17885 case 0x3C: // vaddeuqm
17886 assign( vC, getVReg(vRC_addr));
17887 DIP("vaddeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17888 vRC_addr);
17889 assign(cin, binop( Iop_And32,
17890 unop( Iop_64to32,
17891 unop( Iop_V128to64, mkexpr(vC) ) ),
17892 mkU32(1) ) );
17893 putVReg( vRT_addr,
17894 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA), mkexpr(vB),
17895 mkexpr(cin),
17896 True) ) );
17897 return True;
17898 case 0x3F: // vsubecuq
17899 assign( vC, getVReg(vRC_addr));
17900 DIP("vsubecuq v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17901 vRC_addr);
17902 assign(cin, binop( Iop_And32,
17903 unop( Iop_64to32,
17904 unop( Iop_V128to64, mkexpr(vC) ) ),
17905 mkU32(1) ) );
17906 putVReg( vRT_addr,
17907 unop( Iop_32UtoV128,
17908 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17909 unop( Iop_NotV128,
17910 mkexpr(vB) ),
17911 mkexpr(cin),
17912 False) ) ) );
17913 return True;
17914 case 0x3E: // vsubeuqm
17915 assign( vC, getVReg(vRC_addr));
17916 DIP("vsubeuqm v%d,v%d,v%d,v%d\n", vRT_addr, vRA_addr, vRB_addr,
17917 vRC_addr);
17918 assign(cin, binop( Iop_And32,
17919 unop( Iop_64to32,
17920 unop( Iop_V128to64, mkexpr(vC) ) ),
17921 mkU32(1) ) );
17922 putVReg( vRT_addr,
17923 mkexpr(_get_quad_modulo_or_carry(mkexpr(vA),
17924 unop( Iop_NotV128, mkexpr(vB) ),
17925 mkexpr(cin),
17926 True) ) );
17927 return True;
17928 default:
17929 vex_printf("dis_av_quad(ppc)(opc2.2)\n");
17930 return False;
17931 }
17932
17933 return True;
17934}
17935
17936
17937/*
carll7deaf952013-10-15 18:11:20 +000017938 AltiVec BCD Arithmetic instructions.
17939 These instructions modify CR6 for various conditions in the result,
17940 including when an overflow occurs. We could easily detect all conditions
17941 except when an overflow occurs. But since we can't be 100% accurate
17942 in our emulation of CR6, it seems best to just not support it all.
17943*/
17944static Bool dis_av_bcd ( UInt theInstr )
17945{
17946 /* VX-Form */
17947 UChar opc1 = ifieldOPC(theInstr);
17948 UChar vRT_addr = ifieldRegDS(theInstr);
17949 UChar vRA_addr = ifieldRegA(theInstr);
17950 UChar vRB_addr = ifieldRegB(theInstr);
17951 UChar ps = IFIELD( theInstr, 9, 1 );
17952 UInt opc2 = IFIELD( theInstr, 0, 9 );
17953
17954 IRTemp vA = newTemp(Ity_V128);
17955 IRTemp vB = newTemp(Ity_V128);
17956 IRTemp dst = newTemp(Ity_V128);
17957 assign( vA, getVReg(vRA_addr));
17958 assign( vB, getVReg(vRB_addr));
17959
17960 if (opc1 != 0x4) {
17961 vex_printf("dis_av_bcd(ppc)(instr)\n");
17962 return False;
17963 }
17964
17965 switch (opc2) {
17966 case 0x1: // bcdadd
17967 DIP("bcdadd. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
17968 assign( dst, triop( Iop_BCDAdd, mkexpr( vA ),
17969 mkexpr( vB ), mkU8( ps ) ) );
17970 putVReg( vRT_addr, mkexpr(dst));
17971 return True;
17972
17973 case 0x41: // bcdsub
17974 DIP("bcdsub. v%d,v%d,v%d,%u\n", vRT_addr, vRA_addr, vRB_addr, ps);
17975 assign( dst, triop( Iop_BCDSub, mkexpr( vA ),
17976 mkexpr( vB ), mkU8( ps ) ) );
17977 putVReg( vRT_addr, mkexpr(dst));
17978 return True;
17979
17980 default:
17981 vex_printf("dis_av_bcd(ppc)(opc2)\n");
17982 return False;
17983 }
17984 return True;
17985}
cerion32aad402005-09-10 12:02:24 +000017986
17987/*
17988 AltiVec Floating Point Arithmetic Instructions
17989*/
17990static Bool dis_av_fp_arith ( UInt theInstr )
17991{
cerion76de5cf2005-11-18 18:25:12 +000017992 /* VA-Form */
17993 UChar opc1 = ifieldOPC(theInstr);
17994 UChar vD_addr = ifieldRegDS(theInstr);
17995 UChar vA_addr = ifieldRegA(theInstr);
17996 UChar vB_addr = ifieldRegB(theInstr);
17997 UChar vC_addr = ifieldRegC(theInstr);
cerion32aad402005-09-10 12:02:24 +000017998 UInt opc2=0;
17999
cerion8ea0d3e2005-11-14 00:44:47 +000018000 IRTemp vA = newTemp(Ity_V128);
18001 IRTemp vB = newTemp(Ity_V128);
18002 IRTemp vC = newTemp(Ity_V128);
18003 assign( vA, getVReg(vA_addr));
18004 assign( vB, getVReg(vB_addr));
18005 assign( vC, getVReg(vC_addr));
18006
cerion32aad402005-09-10 12:02:24 +000018007 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000018008 vex_printf("dis_av_fp_arith(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000018009 return False;
18010 }
18011
sewardj20a760e2014-05-05 10:03:56 +000018012 IRTemp rm = newTemp(Ity_I32);
18013 assign(rm, get_IR_roundingmode());
18014
cerion76de5cf2005-11-18 18:25:12 +000018015 opc2 = IFIELD( theInstr, 0, 6 );
cerion32aad402005-09-10 12:02:24 +000018016 switch (opc2) {
18017 case 0x2E: // vmaddfp (Multiply Add FP, AV p177)
cerion5b2325f2005-12-23 00:55:09 +000018018 DIP("vmaddfp v%d,v%d,v%d,v%d\n",
18019 vD_addr, vA_addr, vC_addr, vB_addr);
18020 putVReg( vD_addr,
sewardj20a760e2014-05-05 10:03:56 +000018021 triop(Iop_Add32Fx4, mkU32(Irrm_NEAREST),
18022 mkexpr(vB),
18023 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
18024 mkexpr(vA), mkexpr(vC))) );
cerionf3f173c2005-11-14 02:37:44 +000018025 return True;
cerion32aad402005-09-10 12:02:24 +000018026
cerionf3f173c2005-11-14 02:37:44 +000018027 case 0x2F: { // vnmsubfp (Negative Multiply-Subtract FP, AV p215)
cerion5b2325f2005-12-23 00:55:09 +000018028 DIP("vnmsubfp v%d,v%d,v%d,v%d\n",
18029 vD_addr, vA_addr, vC_addr, vB_addr);
18030 putVReg( vD_addr,
sewardj20a760e2014-05-05 10:03:56 +000018031 triop(Iop_Sub32Fx4, mkU32(Irrm_NEAREST),
cerion5b2325f2005-12-23 00:55:09 +000018032 mkexpr(vB),
sewardj20a760e2014-05-05 10:03:56 +000018033 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
18034 mkexpr(vA), mkexpr(vC))) );
cerionf3f173c2005-11-14 02:37:44 +000018035 return True;
18036 }
cerion32aad402005-09-10 12:02:24 +000018037
18038 default:
18039 break; // Fall through...
18040 }
18041
cerion76de5cf2005-11-18 18:25:12 +000018042 opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000018043 switch (opc2) {
18044 case 0x00A: // vaddfp (Add FP, AV p137)
18045 DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj20a760e2014-05-05 10:03:56 +000018046 putVReg( vD_addr, triop(Iop_Add32Fx4,
18047 mkU32(Irrm_NEAREST), mkexpr(vA), mkexpr(vB)) );
cerion8ea0d3e2005-11-14 00:44:47 +000018048 return True;
cerion32aad402005-09-10 12:02:24 +000018049
18050 case 0x04A: // vsubfp (Subtract FP, AV p261)
18051 DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
sewardj20a760e2014-05-05 10:03:56 +000018052 putVReg( vD_addr, triop(Iop_Sub32Fx4,
18053 mkU32(Irrm_NEAREST), mkexpr(vA), mkexpr(vB)) );
cerion8ea0d3e2005-11-14 00:44:47 +000018054 return True;
cerion32aad402005-09-10 12:02:24 +000018055
18056 case 0x40A: // vmaxfp (Maximum FP, AV p178)
18057 DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018058 putVReg( vD_addr, binop(Iop_Max32Fx4, mkexpr(vA), mkexpr(vB)) );
18059 return True;
cerion32aad402005-09-10 12:02:24 +000018060
18061 case 0x44A: // vminfp (Minimum FP, AV p187)
18062 DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018063 putVReg( vD_addr, binop(Iop_Min32Fx4, mkexpr(vA), mkexpr(vB)) );
18064 return True;
cerion32aad402005-09-10 12:02:24 +000018065
18066 default:
18067 break; // Fall through...
18068 }
18069
18070
18071 if (vA_addr != 0) {
cerion5b2325f2005-12-23 00:55:09 +000018072 vex_printf("dis_av_fp_arith(ppc)(vA_addr)\n");
cerion32aad402005-09-10 12:02:24 +000018073 return False;
18074 }
18075
18076 switch (opc2) {
18077 case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228)
18078 DIP("vrefp v%d,v%d\n", vD_addr, vB_addr);
sewardj1ddee212014-08-24 14:00:19 +000018079 putVReg( vD_addr, unop(Iop_RecipEst32Fx4, mkexpr(vB)) );
cerion8ea0d3e2005-11-14 00:44:47 +000018080 return True;
cerion32aad402005-09-10 12:02:24 +000018081
cerion5b2325f2005-12-23 00:55:09 +000018082 case 0x14A: // vrsqrtefp (Reciprocal Sqrt Estimate FP, AV p237)
cerion32aad402005-09-10 12:02:24 +000018083 DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr);
sewardj1ddee212014-08-24 14:00:19 +000018084 putVReg( vD_addr, unop(Iop_RSqrtEst32Fx4, mkexpr(vB)) );
cerion8ea0d3e2005-11-14 00:44:47 +000018085 return True;
cerion32aad402005-09-10 12:02:24 +000018086
18087 case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173)
18088 DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr);
18089 DIP(" => not implemented\n");
18090 return False;
18091
18092 case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175)
18093 DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr);
18094 DIP(" => not implemented\n");
18095 return False;
18096
18097 default:
cerion5b2325f2005-12-23 00:55:09 +000018098 vex_printf("dis_av_fp_arith(ppc)(opc2=0x%x)\n",opc2);
cerion32aad402005-09-10 12:02:24 +000018099 return False;
18100 }
18101 return True;
18102}
18103
18104/*
18105 AltiVec Floating Point Compare Instructions
18106*/
18107static Bool dis_av_fp_cmp ( UInt theInstr )
18108{
cerion76de5cf2005-11-18 18:25:12 +000018109 /* VXR-Form */
18110 UChar opc1 = ifieldOPC(theInstr);
18111 UChar vD_addr = ifieldRegDS(theInstr);
18112 UChar vA_addr = ifieldRegA(theInstr);
18113 UChar vB_addr = ifieldRegB(theInstr);
18114 UChar flag_rC = ifieldBIT10(theInstr);
18115 UInt opc2 = IFIELD( theInstr, 0, 10 );
cerion32aad402005-09-10 12:02:24 +000018116
cerion8ea0d3e2005-11-14 00:44:47 +000018117 Bool cmp_bounds = False;
18118
18119 IRTemp vA = newTemp(Ity_V128);
18120 IRTemp vB = newTemp(Ity_V128);
18121 IRTemp vD = newTemp(Ity_V128);
18122 assign( vA, getVReg(vA_addr));
18123 assign( vB, getVReg(vB_addr));
18124
cerion32aad402005-09-10 12:02:24 +000018125 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000018126 vex_printf("dis_av_fp_cmp(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000018127 return False;
18128 }
18129
18130 switch (opc2) {
18131 case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159)
cerion5b2325f2005-12-23 00:55:09 +000018132 DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18133 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018134 assign( vD, binop(Iop_CmpEQ32Fx4, mkexpr(vA), mkexpr(vB)) );
18135 break;
cerion32aad402005-09-10 12:02:24 +000018136
cerion5b2325f2005-12-23 00:55:09 +000018137 case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to, AV p163)
18138 DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18139 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018140 assign( vD, binop(Iop_CmpGE32Fx4, mkexpr(vA), mkexpr(vB)) );
18141 break;
cerion32aad402005-09-10 12:02:24 +000018142
18143 case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164)
cerion5b2325f2005-12-23 00:55:09 +000018144 DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18145 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018146 assign( vD, binop(Iop_CmpGT32Fx4, mkexpr(vA), mkexpr(vB)) );
18147 break;
cerion32aad402005-09-10 12:02:24 +000018148
cerion8ea0d3e2005-11-14 00:44:47 +000018149 case 0x3C6: { // vcmpbfp (Compare Bounds FP, AV p157)
18150 IRTemp gt = newTemp(Ity_V128);
18151 IRTemp lt = newTemp(Ity_V128);
18152 IRTemp zeros = newTemp(Ity_V128);
cerion5b2325f2005-12-23 00:55:09 +000018153 DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_rC ? ".":""),
18154 vD_addr, vA_addr, vB_addr);
cerion8ea0d3e2005-11-14 00:44:47 +000018155 cmp_bounds = True;
18156 assign( zeros, unop(Iop_Dup32x4, mkU32(0)) );
18157
18158 /* Note: making use of fact that the ppc backend for compare insns
cerion5b2325f2005-12-23 00:55:09 +000018159 return zero'd lanes if either of the corresponding arg lanes is
18160 a nan.
cerion8ea0d3e2005-11-14 00:44:47 +000018161
18162 Perhaps better to have an irop Iop_isNan32Fx4, but then we'd
18163 need this for the other compares too (vcmpeqfp etc)...
18164 Better still, tighten down the spec for compare irops.
18165 */
18166 assign( gt, unop(Iop_NotV128,
18167 binop(Iop_CmpLE32Fx4, mkexpr(vA), mkexpr(vB))) );
18168 assign( lt, unop(Iop_NotV128,
18169 binop(Iop_CmpGE32Fx4, mkexpr(vA),
sewardj20a760e2014-05-05 10:03:56 +000018170 triop(Iop_Sub32Fx4, mkU32(Irrm_NEAREST),
18171 mkexpr(zeros),
18172 mkexpr(vB)))) );
cerion8ea0d3e2005-11-14 00:44:47 +000018173
18174 // finally, just shift gt,lt to correct position
18175 assign( vD, binop(Iop_ShlN32x4,
18176 binop(Iop_OrV128,
18177 binop(Iop_AndV128, mkexpr(gt),
18178 unop(Iop_Dup32x4, mkU32(0x2))),
18179 binop(Iop_AndV128, mkexpr(lt),
18180 unop(Iop_Dup32x4, mkU32(0x1)))),
18181 mkU8(30)) );
18182 break;
18183 }
cerion32aad402005-09-10 12:02:24 +000018184
18185 default:
cerion5b2325f2005-12-23 00:55:09 +000018186 vex_printf("dis_av_fp_cmp(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000018187 return False;
18188 }
cerion8ea0d3e2005-11-14 00:44:47 +000018189
18190 putVReg( vD_addr, mkexpr(vD) );
18191
cerion76de5cf2005-11-18 18:25:12 +000018192 if (flag_rC) {
cerion8ea0d3e2005-11-14 00:44:47 +000018193 set_AV_CR6( mkexpr(vD), !cmp_bounds );
18194 }
cerion32aad402005-09-10 12:02:24 +000018195 return True;
18196}
18197
18198/*
18199 AltiVec Floating Point Convert/Round Instructions
18200*/
18201static Bool dis_av_fp_convert ( UInt theInstr )
18202{
cerion76de5cf2005-11-18 18:25:12 +000018203 /* VX-Form */
18204 UChar opc1 = ifieldOPC(theInstr);
18205 UChar vD_addr = ifieldRegDS(theInstr);
18206 UChar UIMM_5 = ifieldRegA(theInstr);
18207 UChar vB_addr = ifieldRegB(theInstr);
18208 UInt opc2 = IFIELD( theInstr, 0, 11 );
cerion32aad402005-09-10 12:02:24 +000018209
cerion76de5cf2005-11-18 18:25:12 +000018210 IRTemp vB = newTemp(Ity_V128);
18211 IRTemp vScale = newTemp(Ity_V128);
ceriond963eb42005-11-16 18:02:58 +000018212 IRTemp vInvScale = newTemp(Ity_V128);
sewardj41a7b702005-11-18 22:18:23 +000018213
18214 float scale, inv_scale;
18215
ceriond963eb42005-11-16 18:02:58 +000018216 assign( vB, getVReg(vB_addr));
18217
18218 /* scale = 2^UIMM, cast to float, reinterpreted as uint */
sewardj41a7b702005-11-18 22:18:23 +000018219 scale = (float)( (unsigned int) 1<<UIMM_5 );
sewardj2ead5222005-11-23 03:53:45 +000018220 assign( vScale, unop(Iop_Dup32x4, mkU32( float_to_bits(scale) )) );
sewardj41a7b702005-11-18 22:18:23 +000018221 inv_scale = 1/scale;
cerion5b2325f2005-12-23 00:55:09 +000018222 assign( vInvScale,
18223 unop(Iop_Dup32x4, mkU32( float_to_bits(inv_scale) )) );
ceriond963eb42005-11-16 18:02:58 +000018224
cerion32aad402005-09-10 12:02:24 +000018225 if (opc1 != 0x4) {
cerion5b2325f2005-12-23 00:55:09 +000018226 vex_printf("dis_av_fp_convert(ppc)(instr)\n");
cerion32aad402005-09-10 12:02:24 +000018227 return False;
18228 }
18229
18230 switch (opc2) {
18231 case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156)
18232 DIP("vcfux v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
sewardj20a760e2014-05-05 10:03:56 +000018233 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
ceriond963eb42005-11-16 18:02:58 +000018234 unop(Iop_I32UtoFx4, mkexpr(vB)),
18235 mkexpr(vInvScale)) );
18236 return True;
cerion32aad402005-09-10 12:02:24 +000018237
18238 case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155)
18239 DIP("vcfsx v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
ceriond963eb42005-11-16 18:02:58 +000018240
sewardj20a760e2014-05-05 10:03:56 +000018241 putVReg( vD_addr, triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
ceriond963eb42005-11-16 18:02:58 +000018242 unop(Iop_I32StoFx4, mkexpr(vB)),
18243 mkexpr(vInvScale)) );
18244 return True;
cerion32aad402005-09-10 12:02:24 +000018245
18246 case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172)
18247 DIP("vctuxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
ceriond963eb42005-11-16 18:02:58 +000018248 putVReg( vD_addr,
18249 unop(Iop_QFtoI32Ux4_RZ,
sewardj20a760e2014-05-05 10:03:56 +000018250 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
18251 mkexpr(vB), mkexpr(vScale))) );
ceriond963eb42005-11-16 18:02:58 +000018252 return True;
cerion32aad402005-09-10 12:02:24 +000018253
18254 case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171)
18255 DIP("vctsxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
ceriond963eb42005-11-16 18:02:58 +000018256 putVReg( vD_addr,
18257 unop(Iop_QFtoI32Sx4_RZ,
sewardj20a760e2014-05-05 10:03:56 +000018258 triop(Iop_Mul32Fx4, mkU32(Irrm_NEAREST),
18259 mkexpr(vB), mkexpr(vScale))) );
ceriond963eb42005-11-16 18:02:58 +000018260 return True;
cerion32aad402005-09-10 12:02:24 +000018261
18262 default:
18263 break; // Fall through...
18264 }
18265
18266 if (UIMM_5 != 0) {
cerion5b2325f2005-12-23 00:55:09 +000018267 vex_printf("dis_av_fp_convert(ppc)(UIMM_5)\n");
cerion32aad402005-09-10 12:02:24 +000018268 return False;
18269 }
18270
18271 switch (opc2) {
18272 case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231)
18273 DIP("vrfin v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018274 putVReg( vD_addr, unop(Iop_RoundF32x4_RN, mkexpr(vB)) );
18275 break;
cerion32aad402005-09-10 12:02:24 +000018276
18277 case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233)
18278 DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018279 putVReg( vD_addr, unop(Iop_RoundF32x4_RZ, mkexpr(vB)) );
18280 break;
cerion32aad402005-09-10 12:02:24 +000018281
18282 case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232)
18283 DIP("vrfip v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018284 putVReg( vD_addr, unop(Iop_RoundF32x4_RP, mkexpr(vB)) );
18285 break;
cerion32aad402005-09-10 12:02:24 +000018286
18287 case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230)
18288 DIP("vrfim v%d,v%d\n", vD_addr, vB_addr);
ceriond963eb42005-11-16 18:02:58 +000018289 putVReg( vD_addr, unop(Iop_RoundF32x4_RM, mkexpr(vB)) );
18290 break;
cerion32aad402005-09-10 12:02:24 +000018291
18292 default:
cerion5b2325f2005-12-23 00:55:09 +000018293 vex_printf("dis_av_fp_convert(ppc)(opc2)\n");
cerion32aad402005-09-10 12:02:24 +000018294 return False;
18295 }
18296 return True;
18297}
cerion3d870a32005-03-18 12:23:33 +000018298
carll8943d022013-10-02 16:25:57 +000018299static Bool dis_transactional_memory ( UInt theInstr, UInt nextInstr,
18300 VexAbiInfo* vbi,
18301 /*OUT*/DisResult* dres,
18302 Bool (*resteerOkFn)(void*,Addr64),
18303 void* callback_opaque )
18304{
18305 UInt opc2 = IFIELD( theInstr, 1, 10 );
18306
18307 switch (opc2) {
18308 case 0x28E: { //tbegin.
18309 /* The current implementation is to just fail the tbegin and execute
18310 * the failure path. The failure path is assumed to be functionaly
18311 * equivalent to the transactional path with the needed data locking
18312 * to ensure correctness. The tend is just a noop and shouldn't
18313 * actually get executed.
18314 * 1) set cr0 to 0x2
18315 * 2) Initialize TFHAR to CIA+4
18316 * 3) Initialize TEXASR
18317 * 4) Initialize TFIAR (probably to CIA, ie, the address of tbegin.)
18318 * 5) Continue executing at the next instruction.
18319 */
18320 UInt R = IFIELD( theInstr, 21, 1 );
18321
18322 ULong tm_reason;
18323 UInt failure_code = 0; /* Forcing failure, will not be due to tabort
18324 * or treclaim.
18325 */
18326 UInt persistant = 1; /* set persistant since we are always failing
18327 * the tbegin.
18328 */
18329 UInt nest_overflow = 1; /* Alowed nesting depth overflow, we use this
18330 as the reason for failing the trasaction */
18331 UInt tm_exact = 1; /* have exact address for failure */
18332
18333 DIP("tbegin. %d\n", R);
18334
18335 /* Set the CR0 field to indicate the tbegin failed. Then let
18336 * the code do the branch to the failure path.
18337 *
18338 * 000 || 0 Transaction initiation successful,
18339 * unnested (Transaction state of
18340 * Non-transactional prior to tbegin.)
18341 * 010 || 0 Transaction initiation successful, nested
18342 * (Transaction state of Transactional
18343 * prior to tbegin.)
18344 * 001 || 0 Transaction initiation unsuccessful,
18345 * (Transaction state of Suspended prior
18346 * to tbegin.)
18347 */
18348 putCR321( 0, mkU8( 0x2 ) );
18349
18350 tm_reason = generate_TMreason( failure_code, persistant,
18351 nest_overflow, tm_exact );
18352
18353 storeTMfailure( guest_CIA_curr_instr, tm_reason,
18354 guest_CIA_curr_instr+4 );
18355
18356 return True;
18357
18358 break;
18359 }
18360
18361 case 0x2AE: { //tend.
18362 /* The tend. is just a noop. Do nothing */
18363 UInt A = IFIELD( theInstr, 25, 1 );
18364
18365 DIP("tend. %d\n", A);
18366 break;
18367 }
18368
18369 case 0x2EE: { //tsr.
18370 /* The tsr. is just a noop. Do nothing */
18371 UInt L = IFIELD( theInstr, 21, 1 );
18372
18373 DIP("tsr. %d\n", L);
18374 break;
18375 }
18376
18377 case 0x2CE: { //tcheck.
18378 /* The tcheck. is just a noop. Do nothing */
18379 UInt BF = IFIELD( theInstr, 25, 1 );
18380
18381 DIP("tcheck. %d\n", BF);
18382 break;
18383 }
18384
18385 case 0x30E: { //tbortwc.
18386 /* The tabortwc. is just a noop. Do nothing */
18387 UInt TO = IFIELD( theInstr, 25, 1 );
18388 UInt RA = IFIELD( theInstr, 16, 5 );
18389 UInt RB = IFIELD( theInstr, 11, 5 );
18390
18391 DIP("tabortwc. %d,%d,%d\n", TO, RA, RB);
18392 break;
18393 }
18394
18395 case 0x32E: { //tbortdc.
18396 /* The tabortdc. is just a noop. Do nothing */
18397 UInt TO = IFIELD( theInstr, 25, 1 );
18398 UInt RA = IFIELD( theInstr, 16, 5 );
18399 UInt RB = IFIELD( theInstr, 11, 5 );
18400
18401 DIP("tabortdc. %d,%d,%d\n", TO, RA, RB);
18402 break;
18403 }
18404
18405 case 0x34E: { //tbortwci.
18406 /* The tabortwci. is just a noop. Do nothing */
18407 UInt TO = IFIELD( theInstr, 25, 1 );
18408 UInt RA = IFIELD( theInstr, 16, 5 );
18409 UInt SI = IFIELD( theInstr, 11, 5 );
18410
18411 DIP("tabortwci. %d,%d,%d\n", TO, RA, SI);
18412 break;
18413 }
18414
18415 case 0x36E: { //tbortdci.
18416 /* The tabortdci. is just a noop. Do nothing */
18417 UInt TO = IFIELD( theInstr, 25, 1 );
18418 UInt RA = IFIELD( theInstr, 16, 5 );
18419 UInt SI = IFIELD( theInstr, 11, 5 );
18420
18421 DIP("tabortdci. %d,%d,%d\n", TO, RA, SI);
18422 break;
18423 }
18424
18425 case 0x38E: { //tbort.
18426 /* The tabort. is just a noop. Do nothing */
18427 UInt RA = IFIELD( theInstr, 16, 5 );
18428
18429 DIP("tabort. %d\n", RA);
18430 break;
18431 }
18432
carllfcce5f82013-10-09 17:52:01 +000018433 case 0x3AE: { //treclaim.
18434 /* The treclaim. is just a noop. Do nothing */
18435 UInt RA = IFIELD( theInstr, 16, 5 );
18436
18437 DIP("treclaim. %d\n", RA);
18438 break;
18439 }
18440
18441 case 0x3EE: { //trechkpt.
18442 /* The trechkpt. is just a noop. Do nothing */
18443 DIP("trechkpt.\n");
18444 break;
18445 }
18446
carll8943d022013-10-02 16:25:57 +000018447 default:
18448 vex_printf("dis_transactional_memory(ppc): unrecognized instruction\n");
18449 return False;
18450 }
18451
18452 return True;
18453}
18454
cerion3d870a32005-03-18 12:23:33 +000018455
sewardj66d5ef22011-04-15 11:55:00 +000018456/* The 0x3C primary opcode (VSX category) uses several different forms of
18457 * extended opcodes:
18458 * o XX2-form:
18459 * - [10:2] (IBM notation [21:29])
18460 * o XX3-form variants:
18461 * - variant 1: [10:3] (IBM notation [21:28])
18462 * - variant 2: [9:3] (IBM notation [22:28])
18463 * - variant 3: [7:3] (IBM notation [24:28])
18464 * o XX-4 form:
18465 * - [10:6] (IBM notation [21:25])
18466 *
18467 * The XX2-form needs bit 0 masked from the standard extended opcode
18468 * as returned by ifieldOPClo10; the XX3-form needs bits 0 and 1 masked;
18469 * and the XX4-form needs bits 0, 1, and 2 masked. Additionally, the
18470 * XX4 and XX3 (variants 2 and 3) forms need certain bits masked on the
18471 * front end since their encoding does not begin at bit 21 like the standard
18472 * format.
18473 *
18474 * The get_VSX60_opc2() function uses the vsx_insn array below to obtain the
18475 * secondary opcode for such VSX instructions.
18476 *
18477*/
cerion91ad5362005-01-27 23:02:41 +000018478
cerion91ad5362005-01-27 23:02:41 +000018479
sewardj66d5ef22011-04-15 11:55:00 +000018480struct vsx_insn {
18481 UInt opcode;
florian55085f82012-11-21 00:36:55 +000018482 const HChar * name;
sewardj66d5ef22011-04-15 11:55:00 +000018483};
18484
18485// ATTENTION: Keep this array sorted on the opcocde!!!
18486static struct vsx_insn vsx_all[] = {
carll6c758b62013-10-03 21:38:45 +000018487 { 0x0, "xsaddsp" },
18488 { 0x4, "xsmaddasp" },
sewardj66d5ef22011-04-15 11:55:00 +000018489 { 0x8, "xxsldwi" },
carll6c758b62013-10-03 21:38:45 +000018490 { 0x14, "xsrsqrtesp" },
18491 { 0x16, "xssqrtsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018492 { 0x18, "xxsel" },
carll6c758b62013-10-03 21:38:45 +000018493 { 0x20, "xssubsp" },
18494 { 0x24, "xsmaddmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018495 { 0x28, "xxpermdi" },
carll6c758b62013-10-03 21:38:45 +000018496 { 0x34, "xsresp" },
18497 { 0x40, "xsmulsp" },
18498 { 0x44, "xsmsubasp" },
sewardj66d5ef22011-04-15 11:55:00 +000018499 { 0x48, "xxmrghw" },
carll6c758b62013-10-03 21:38:45 +000018500 { 0x60, "xsdivsp" },
18501 { 0x64, "xsmsubmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018502 { 0x80, "xsadddp" },
18503 { 0x84, "xsmaddadp" },
18504 { 0x8c, "xscmpudp" },
18505 { 0x90, "xscvdpuxws" },
18506 { 0x92, "xsrdpi" },
18507 { 0x94, "xsrsqrtedp" },
18508 { 0x96, "xssqrtdp" },
18509 { 0xa0, "xssubdp" },
18510 { 0xa4, "xsmaddmdp" },
18511 { 0xac, "xscmpodp" },
18512 { 0xb0, "xscvdpsxws" },
18513 { 0xb2, "xsrdpiz" },
18514 { 0xb4, "xsredp" },
18515 { 0xc0, "xsmuldp" },
18516 { 0xc4, "xsmsubadp" },
18517 { 0xc8, "xxmrglw" },
18518 { 0xd2, "xsrdpip" },
18519 { 0xd4, "xstsqrtdp" },
18520 { 0xd6, "xsrdpic" },
18521 { 0xe0, "xsdivdp" },
18522 { 0xe4, "xsmsubmdp" },
18523 { 0xf2, "xsrdpim" },
18524 { 0xf4, "xstdivdp" },
18525 { 0x100, "xvaddsp" },
18526 { 0x104, "xvmaddasp" },
18527 { 0x10c, "xvcmpeqsp" },
18528 { 0x110, "xvcvspuxws" },
18529 { 0x112, "xvrspi" },
18530 { 0x114, "xvrsqrtesp" },
18531 { 0x116, "xvsqrtsp" },
18532 { 0x120, "xvsubsp" },
18533 { 0x124, "xvmaddmsp" },
18534 { 0x12c, "xvcmpgtsp" },
18535 { 0x130, "xvcvspsxws" },
18536 { 0x132, "xvrspiz" },
18537 { 0x134, "xvresp" },
18538 { 0x140, "xvmulsp" },
18539 { 0x144, "xvmsubasp" },
18540 { 0x148, "xxspltw" },
18541 { 0x14c, "xvcmpgesp" },
18542 { 0x150, "xvcvuxwsp" },
18543 { 0x152, "xvrspip" },
18544 { 0x154, "xvtsqrtsp" },
18545 { 0x156, "xvrspic" },
18546 { 0x160, "xvdivsp" },
18547 { 0x164, "xvmsubmsp" },
18548 { 0x170, "xvcvsxwsp" },
18549 { 0x172, "xvrspim" },
18550 { 0x174, "xvtdivsp" },
18551 { 0x180, "xvadddp" },
18552 { 0x184, "xvmaddadp" },
18553 { 0x18c, "xvcmpeqdp" },
18554 { 0x190, "xvcvdpuxws" },
18555 { 0x192, "xvrdpi" },
18556 { 0x194, "xvrsqrtedp" },
18557 { 0x196, "xvsqrtdp" },
18558 { 0x1a0, "xvsubdp" },
18559 { 0x1a4, "xvmaddmdp" },
18560 { 0x1ac, "xvcmpgtdp" },
18561 { 0x1b0, "xvcvdpsxws" },
18562 { 0x1b2, "xvrdpiz" },
18563 { 0x1b4, "xvredp" },
18564 { 0x1c0, "xvmuldp" },
18565 { 0x1c4, "xvmsubadp" },
18566 { 0x1cc, "xvcmpgedp" },
18567 { 0x1d0, "xvcvuxwdp" },
18568 { 0x1d2, "xvrdpip" },
18569 { 0x1d4, "xvtsqrtdp" },
18570 { 0x1d6, "xvrdpic" },
18571 { 0x1e0, "xvdivdp" },
18572 { 0x1e4, "xvmsubmdp" },
18573 { 0x1f0, "xvcvsxwdp" },
18574 { 0x1f2, "xvrdpim" },
18575 { 0x1f4, "xvtdivdp" },
carll6c758b62013-10-03 21:38:45 +000018576 { 0x204, "xsnmaddasp" },
sewardj66d5ef22011-04-15 11:55:00 +000018577 { 0x208, "xxland" },
18578 { 0x212, "xscvdpsp" },
carll0c74bb52013-08-12 18:01:40 +000018579 { 0x216, "xscvdpspn" },
carll6c758b62013-10-03 21:38:45 +000018580 { 0x224, "xsnmaddmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018581 { 0x228, "xxlandc" },
carll6c758b62013-10-03 21:38:45 +000018582 { 0x232, "xxrsp" },
18583 { 0x244, "xsnmsubasp" },
18584 { 0x248, "xxlor" },
18585 { 0x250, "xscvuxdsp" },
18586 { 0x264, "xsnmsubmsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018587 { 0x268, "xxlxor" },
carll6c758b62013-10-03 21:38:45 +000018588 { 0x270, "xscvsxdsp" },
sewardj66d5ef22011-04-15 11:55:00 +000018589 { 0x280, "xsmaxdp" },
18590 { 0x284, "xsnmaddadp" },
18591 { 0x288, "xxlnor" },
18592 { 0x290, "xscvdpuxds" },
18593 { 0x292, "xscvspdp" },
carll0c74bb52013-08-12 18:01:40 +000018594 { 0x296, "xscvspdpn" },
sewardj66d5ef22011-04-15 11:55:00 +000018595 { 0x2a0, "xsmindp" },
18596 { 0x2a4, "xsnmaddmdp" },
carll6c758b62013-10-03 21:38:45 +000018597 { 0x2a8, "xxlorc" },
sewardj66d5ef22011-04-15 11:55:00 +000018598 { 0x2b0, "xscvdpsxds" },
18599 { 0x2b2, "xsabsdp" },
18600 { 0x2c0, "xscpsgndp" },
18601 { 0x2c4, "xsnmsubadp" },
carll6c758b62013-10-03 21:38:45 +000018602 { 0x2c8, "xxlnand" },
sewardj66d5ef22011-04-15 11:55:00 +000018603 { 0x2d0, "xscvuxddp" },
18604 { 0x2d2, "xsnabsdp" },
18605 { 0x2e4, "xsnmsubmdp" },
carll6c758b62013-10-03 21:38:45 +000018606 { 0x2e8, "xxleqv" },
sewardj66d5ef22011-04-15 11:55:00 +000018607 { 0x2f0, "xscvsxddp" },
18608 { 0x2f2, "xsnegdp" },
18609 { 0x300, "xvmaxsp" },
18610 { 0x304, "xvnmaddasp" },
18611 { 0x30c, "xvcmpeqsp." },
18612 { 0x310, "xvcvspuxds" },
18613 { 0x312, "xvcvdpsp" },
18614 { 0x320, "xvminsp" },
18615 { 0x324, "xvnmaddmsp" },
18616 { 0x32c, "xvcmpgtsp." },
18617 { 0x330, "xvcvspsxds" },
18618 { 0x332, "xvabssp" },
18619 { 0x340, "xvcpsgnsp" },
18620 { 0x344, "xvnmsubasp" },
18621 { 0x34c, "xvcmpgesp." },
18622 { 0x350, "xvcvuxdsp" },
18623 { 0x352, "xvnabssp" },
18624 { 0x364, "xvnmsubmsp" },
18625 { 0x370, "xvcvsxdsp" },
18626 { 0x372, "xvnegsp" },
18627 { 0x380, "xvmaxdp" },
18628 { 0x384, "xvnmaddadp" },
18629 { 0x38c, "xvcmpeqdp." },
18630 { 0x390, "xvcvdpuxds" },
18631 { 0x392, "xvcvspdp" },
18632 { 0x3a0, "xvmindp" },
18633 { 0x3a4, "xvnmaddmdp" },
18634 { 0x3ac, "xvcmpgtdp." },
18635 { 0x3b0, "xvcvdpsxds" },
18636 { 0x3b2, "xvabsdp" },
18637 { 0x3c0, "xvcpsgndp" },
18638 { 0x3c4, "xvnmsubadp" },
18639 { 0x3cc, "xvcmpgedp." },
18640 { 0x3d0, "xvcvuxddp" },
18641 { 0x3d2, "xvnabsdp" },
18642 { 0x3e4, "xvnmsubmdp" },
18643 { 0x3f0, "xvcvsxddp" },
18644 { 0x3f2, "xvnegdp" }
18645};
carll0c74bb52013-08-12 18:01:40 +000018646#define VSX_ALL_LEN (sizeof vsx_all / sizeof *vsx_all)
18647
sewardj66d5ef22011-04-15 11:55:00 +000018648
18649// ATTENTION: This search function assumes vsx_all array is sorted.
18650static Int findVSXextOpCode(UInt opcode)
18651{
18652 Int low, mid, high;
18653 low = 0;
18654 high = VSX_ALL_LEN - 1;
18655 while (low <= high) {
18656 mid = (low + high)/2;
18657 if (opcode < vsx_all[mid].opcode)
18658 high = mid - 1;
18659 else if (opcode > vsx_all[mid].opcode)
18660 low = mid + 1;
18661 else
18662 return mid;
18663 }
18664 return -1;
18665}
18666
18667
18668/* The full 10-bit extended opcode retrieved via ifieldOPClo10 is
sewardj4aa412a2011-07-24 14:13:21 +000018669 * passed, and we then try to match it up with one of the VSX forms
18670 * below.
sewardj66d5ef22011-04-15 11:55:00 +000018671 */
18672static UInt get_VSX60_opc2(UInt opc2_full)
18673{
18674#define XX2_MASK 0x000003FE
18675#define XX3_1_MASK 0x000003FC
18676#define XX3_2_MASK 0x000001FC
18677#define XX3_3_MASK 0x0000007C
sewardj4aa412a2011-07-24 14:13:21 +000018678#define XX4_MASK 0x00000018
sewardj66d5ef22011-04-15 11:55:00 +000018679 Int ret;
18680 UInt vsxExtOpcode = 0;
18681
18682 if (( ret = findVSXextOpCode(opc2_full & XX2_MASK)) >= 0)
18683 vsxExtOpcode = vsx_all[ret].opcode;
18684 else if (( ret = findVSXextOpCode(opc2_full & XX3_1_MASK)) >= 0)
18685 vsxExtOpcode = vsx_all[ret].opcode;
18686 else if (( ret = findVSXextOpCode(opc2_full & XX3_2_MASK)) >= 0)
18687 vsxExtOpcode = vsx_all[ret].opcode;
18688 else if (( ret = findVSXextOpCode(opc2_full & XX3_3_MASK)) >= 0)
18689 vsxExtOpcode = vsx_all[ret].opcode;
18690 else if (( ret = findVSXextOpCode(opc2_full & XX4_MASK)) >= 0)
18691 vsxExtOpcode = vsx_all[ret].opcode;
18692
18693 return vsxExtOpcode;
18694}
cerion91ad5362005-01-27 23:02:41 +000018695
cerion896a1372005-01-25 12:24:25 +000018696/*------------------------------------------------------------*/
18697/*--- Disassemble a single instruction ---*/
18698/*------------------------------------------------------------*/
18699
18700/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +000018701 is located in host memory at &guest_code[delta]. */
18702
18703static
cerion5b2325f2005-12-23 00:55:09 +000018704DisResult disInstr_PPC_WRK (
sewardjc716aea2006-01-17 01:48:46 +000018705 Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000018706 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000018707 void* callback_opaque,
sewardj9e6491a2005-07-02 19:24:10 +000018708 Long delta64,
sewardjaca070a2006-10-17 00:28:22 +000018709 VexArchInfo* archinfo,
sewardj442e51a2012-12-06 18:08:04 +000018710 VexAbiInfo* abiinfo,
18711 Bool sigill_diag
sewardj9e6491a2005-07-02 19:24:10 +000018712 )
cerion896a1372005-01-25 12:24:25 +000018713{
sewardj9e6491a2005-07-02 19:24:10 +000018714 UChar opc1;
18715 UInt opc2;
18716 DisResult dres;
cerion896a1372005-01-25 12:24:25 +000018717 UInt theInstr;
ceriond953ebb2005-11-29 13:27:20 +000018718 IRType ty = mode64 ? Ity_I64 : Ity_I32;
sewardj5117ce12006-01-27 21:20:15 +000018719 Bool allow_F = False;
18720 Bool allow_V = False;
18721 Bool allow_FX = False;
18722 Bool allow_GX = False;
sewardj4aa412a2011-07-24 14:13:21 +000018723 Bool allow_VX = False; // Equates to "supports Power ISA 2.06
sewardjc66d6fa2012-04-02 21:24:12 +000018724 Bool allow_DFP = False;
carll0c74bb52013-08-12 18:01:40 +000018725 Bool allow_isa_2_07 = False;
sewardj5117ce12006-01-27 21:20:15 +000018726 UInt hwcaps = archinfo->hwcaps;
18727 Long delta;
cerion896a1372005-01-25 12:24:25 +000018728
sewardj059601a2005-11-13 00:53:05 +000018729 /* What insn variants are we supporting today? */
sewardj5117ce12006-01-27 21:20:15 +000018730 if (mode64) {
18731 allow_F = True;
18732 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC64_V));
18733 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC64_FX));
18734 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC64_GX));
sewardj66d5ef22011-04-15 11:55:00 +000018735 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC64_VX));
sewardjc66d6fa2012-04-02 21:24:12 +000018736 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC64_DFP));
carll0c74bb52013-08-12 18:01:40 +000018737 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA2_07));
sewardj5117ce12006-01-27 21:20:15 +000018738 } else {
18739 allow_F = (0 != (hwcaps & VEX_HWCAPS_PPC32_F));
18740 allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC32_V));
18741 allow_FX = (0 != (hwcaps & VEX_HWCAPS_PPC32_FX));
18742 allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC32_GX));
sewardj66d5ef22011-04-15 11:55:00 +000018743 allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC32_VX));
sewardjc66d6fa2012-04-02 21:24:12 +000018744 allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC32_DFP));
carll0c74bb52013-08-12 18:01:40 +000018745 allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA2_07));
sewardj5117ce12006-01-27 21:20:15 +000018746 }
sewardj059601a2005-11-13 00:53:05 +000018747
sewardj9e6491a2005-07-02 19:24:10 +000018748 /* The running delta */
sewardj5117ce12006-01-27 21:20:15 +000018749 delta = (Long)mkSzAddr(ty, (ULong)delta64);
sewardj9e6491a2005-07-02 19:24:10 +000018750
18751 /* Set result defaults. */
sewardj3dee8492012-04-20 00:13:28 +000018752 dres.whatNext = Dis_Continue;
18753 dres.len = 0;
18754 dres.continueAt = 0;
18755 dres.jk_StopHere = Ijk_INVALID;
cerion896a1372005-01-25 12:24:25 +000018756
cerion1515db92005-01-25 17:21:23 +000018757 /* At least this is simple on PPC32: insns are all 4 bytes long, and
cerion896a1372005-01-25 12:24:25 +000018758 4-aligned. So just fish the whole thing out of memory right now
18759 and have done. */
florian8462d112014-09-24 15:18:09 +000018760 theInstr = getUIntPPCendianly( &guest_code[delta] );
cerion896a1372005-01-25 12:24:25 +000018761
sewardj5117ce12006-01-27 21:20:15 +000018762 if (0) vex_printf("insn: 0x%x\n", theInstr);
cerionf0de28c2005-12-13 20:21:11 +000018763
sewardj1eb7e6b2006-01-12 21:13:14 +000018764 DIP("\t0x%llx: ", (ULong)guest_CIA_curr_instr);
sewardjb51f0f42005-07-18 11:38:02 +000018765
sewardjce02aa72006-01-12 12:27:58 +000018766 /* Spot "Special" instructions (see comment at top of file). */
sewardj1eb7e6b2006-01-12 21:13:14 +000018767 {
florian8462d112014-09-24 15:18:09 +000018768 const UChar* code = guest_code + delta;
sewardj1eb7e6b2006-01-12 21:13:14 +000018769 /* Spot the 16-byte preamble:
18770 32-bit mode:
sewardj2171afd2014-02-10 12:27:29 +000018771 5400183E rlwinm 0,0,3,0,31
18772 5400683E rlwinm 0,0,13,0,31
18773 5400E83E rlwinm 0,0,29,0,31
18774 5400983E rlwinm 0,0,19,0,31
sewardj1eb7e6b2006-01-12 21:13:14 +000018775 64-bit mode:
18776 78001800 rotldi 0,0,3
18777 78006800 rotldi 0,0,13
18778 7800E802 rotldi 0,0,61
18779 78009802 rotldi 0,0,51
cerion896a1372005-01-25 12:24:25 +000018780 */
sewardj2171afd2014-02-10 12:27:29 +000018781 UInt word1 = mode64 ? 0x78001800 : 0x5400183E;
18782 UInt word2 = mode64 ? 0x78006800 : 0x5400683E;
18783 UInt word3 = mode64 ? 0x7800E802 : 0x5400E83E;
18784 UInt word4 = mode64 ? 0x78009802 : 0x5400983E;
mjwd2c19b42014-11-13 14:29:03 +000018785 Bool is_special_preamble = False;
carll1f5fe1f2014-08-07 23:25:23 +000018786 if (getUIntPPCendianly(code+ 0) == word1 &&
18787 getUIntPPCendianly(code+ 4) == word2 &&
18788 getUIntPPCendianly(code+ 8) == word3 &&
18789 getUIntPPCendianly(code+12) == word4) {
mjwd2c19b42014-11-13 14:29:03 +000018790 is_special_preamble = True;
18791 } else if (! mode64 &&
18792 getUIntPPCendianly(code+ 0) == 0x54001800 &&
18793 getUIntPPCendianly(code+ 4) == 0x54006800 &&
18794 getUIntPPCendianly(code+ 8) == 0x5400E800 &&
18795 getUIntPPCendianly(code+12) == 0x54009800) {
18796 static Bool reported = False;
18797 if (!reported) {
18798 vex_printf("disInstr(ppc): old ppc32 instruction magic detected. Code might clobber r0.\n");
18799 vex_printf("disInstr(ppc): source needs to be recompiled against latest valgrind.h.\n");
18800 reported = True;
18801 }
18802 is_special_preamble = True;
18803 }
18804 if (is_special_preamble) {
sewardjce02aa72006-01-12 12:27:58 +000018805 /* Got a "Special" instruction preamble. Which one is it? */
carll1f5fe1f2014-08-07 23:25:23 +000018806 if (getUIntPPCendianly(code+16) == 0x7C210B78 /* or 1,1,1 */) {
sewardjce02aa72006-01-12 12:27:58 +000018807 /* %R3 = client_request ( %R4 ) */
18808 DIP("r3 = client_request ( %%r4 )\n");
18809 delta += 20;
sewardj3dee8492012-04-20 00:13:28 +000018810 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
18811 dres.jk_StopHere = Ijk_ClientReq;
18812 dres.whatNext = Dis_StopHere;
sewardjce02aa72006-01-12 12:27:58 +000018813 goto decode_success;
18814 }
18815 else
carll1f5fe1f2014-08-07 23:25:23 +000018816 if (getUIntPPCendianly(code+16) == 0x7C421378 /* or 2,2,2 */) {
sewardjce02aa72006-01-12 12:27:58 +000018817 /* %R3 = guest_NRADDR */
18818 DIP("r3 = guest_NRADDR\n");
18819 delta += 20;
18820 dres.len = 20;
18821 putIReg(3, IRExpr_Get( OFFB_NRADDR, ty ));
18822 goto decode_success;
18823 }
18824 else
carll1f5fe1f2014-08-07 23:25:23 +000018825 if (getUIntPPCendianly(code+16) == 0x7C631B78 /* or 3,3,3 */) {
sewardjce02aa72006-01-12 12:27:58 +000018826 delta += 20;
carll1f5fe1f2014-08-07 23:25:23 +000018827 if (host_endness == VexEndnessLE) {
18828 /* branch-and-link-to-noredir %R12 */
18829 DIP("branch-and-link-to-noredir r12\n");
18830 putGST( PPC_GST_LR,
18831 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
18832 putGST( PPC_GST_CIA, getIReg(12));
18833 } else {
18834 /* branch-and-link-to-noredir %R11 */
18835 DIP("branch-and-link-to-noredir r11\n");
18836 putGST( PPC_GST_LR,
18837 mkSzImm(ty, guest_CIA_bbstart + (Long)delta) );
18838 putGST( PPC_GST_CIA, getIReg(11));
18839 }
sewardj3dee8492012-04-20 00:13:28 +000018840 dres.jk_StopHere = Ijk_NoRedir;
18841 dres.whatNext = Dis_StopHere;
sewardjce02aa72006-01-12 12:27:58 +000018842 goto decode_success;
18843 }
sewardj5ff11dd2006-01-20 14:19:25 +000018844 else
carll1f5fe1f2014-08-07 23:25:23 +000018845 if (getUIntPPCendianly(code+16) == 0x7C842378 /* or 4,4,4 */) {
sewardj5ff11dd2006-01-20 14:19:25 +000018846 /* %R3 = guest_NRADDR_GPR2 */
18847 DIP("r3 = guest_NRADDR_GPR2\n");
18848 delta += 20;
18849 dres.len = 20;
sewardjaca070a2006-10-17 00:28:22 +000018850 putIReg(3, IRExpr_Get( OFFB_NRADDR_GPR2, ty ));
sewardj5ff11dd2006-01-20 14:19:25 +000018851 goto decode_success;
18852 }
florian2245ce92012-08-28 16:49:30 +000018853 else
carll1f5fe1f2014-08-07 23:25:23 +000018854 if (getUIntPPCendianly(code+16) == 0x7CA52B78 /* or 5,5,5 */) {
florian2245ce92012-08-28 16:49:30 +000018855 DIP("IR injection\n");
carll1f5fe1f2014-08-07 23:25:23 +000018856 if (host_endness == VexEndnessBE)
18857 vex_inject_ir(irsb, Iend_BE);
18858 else
18859 vex_inject_ir(irsb, Iend_LE);
florian2245ce92012-08-28 16:49:30 +000018860
18861 delta += 20;
18862 dres.len = 20;
18863
18864 // Invalidate the current insn. The reason is that the IRop we're
18865 // injecting here can change. In which case the translation has to
18866 // be redone. For ease of handling, we simply invalidate all the
18867 // time.
florian9e238732012-08-29 15:00:13 +000018868
sewardj05f5e012014-05-04 10:52:11 +000018869 stmt(IRStmt_Put(OFFB_CMSTART, mkSzImm(ty, guest_CIA_curr_instr)));
18870 stmt(IRStmt_Put(OFFB_CMLEN, mkSzImm(ty, 20)));
florian2245ce92012-08-28 16:49:30 +000018871
18872 putGST( PPC_GST_CIA, mkSzImm( ty, guest_CIA_bbstart + delta ));
18873 dres.whatNext = Dis_StopHere;
sewardj05f5e012014-05-04 10:52:11 +000018874 dres.jk_StopHere = Ijk_InvalICache;
florian2245ce92012-08-28 16:49:30 +000018875 goto decode_success;
18876 }
sewardjce02aa72006-01-12 12:27:58 +000018877 /* We don't know what it is. Set opc1/opc2 so decode_failure
18878 can print the insn following the Special-insn preamble. */
carll1f5fe1f2014-08-07 23:25:23 +000018879 theInstr = getUIntPPCendianly(code+16);
sewardjce02aa72006-01-12 12:27:58 +000018880 opc1 = ifieldOPC(theInstr);
18881 opc2 = ifieldOPClo10(theInstr);
18882 goto decode_failure;
18883 /*NOTREACHED*/
cerion896a1372005-01-25 12:24:25 +000018884 }
18885 }
18886
cerion76de5cf2005-11-18 18:25:12 +000018887 opc1 = ifieldOPC(theInstr);
sewardjb51f0f42005-07-18 11:38:02 +000018888 opc2 = ifieldOPClo10(theInstr);
cerion932ad942005-01-30 10:18:50 +000018889
cerion91ad5362005-01-27 23:02:41 +000018890 // Note: all 'reserved' bits must be cleared, else invalid
18891 switch (opc1) {
cerion896a1372005-01-25 12:24:25 +000018892
cerione9d361a2005-03-04 17:35:29 +000018893 /* Integer Arithmetic Instructions */
18894 case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
18895 case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
18896 if (dis_int_arith( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018897 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000018898
cerione9d361a2005-03-04 17:35:29 +000018899 /* Integer Compare Instructions */
18900 case 0x0B: case 0x0A: // cmpi, cmpli
18901 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018902 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000018903
cerione9d361a2005-03-04 17:35:29 +000018904 /* Integer Logical Instructions */
18905 case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
18906 case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
18907 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018908 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000018909
cerione9d361a2005-03-04 17:35:29 +000018910 /* Integer Rotate Instructions */
18911 case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
18912 if (dis_int_rot( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018913 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000018914
cerionf0de28c2005-12-13 20:21:11 +000018915 /* 64bit Integer Rotate Instructions */
18916 case 0x1E: // rldcl, rldcr, rldic, rldicl, rldicr, rldimi
carllbb3f4012012-10-29 20:23:41 +000018917 if (!mode64) goto decode_failure;
cerionf0de28c2005-12-13 20:21:11 +000018918 if (dis_int_rot( theInstr )) goto decode_success;
18919 goto decode_failure;
18920
cerione9d361a2005-03-04 17:35:29 +000018921 /* Integer Load Instructions */
18922 case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
18923 case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
18924 case 0x20: case 0x21: // lwz, lwzu
18925 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018926 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000018927
cerione9d361a2005-03-04 17:35:29 +000018928 /* Integer Store Instructions */
18929 case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
18930 case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
sewardjdd40fdf2006-12-24 02:20:24 +000018931 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018932 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +000018933
sewardj7787af42005-08-04 18:32:19 +000018934 /* Integer Load and Store Multiple Instructions */
18935 case 0x2E: case 0x2F: // lmw, stmw
18936 if (dis_int_ldst_mult( theInstr )) goto decode_success;
18937 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000018938
cerione9d361a2005-03-04 17:35:29 +000018939 /* Branch Instructions */
18940 case 0x12: case 0x10: // b, bc
sewardjdd40fdf2006-12-24 02:20:24 +000018941 if (dis_branch(theInstr, abiinfo, &dres,
sewardjaca070a2006-10-17 00:28:22 +000018942 resteerOkFn, callback_opaque))
sewardjc716aea2006-01-17 01:48:46 +000018943 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018944 goto decode_failure;
cerion896a1372005-01-25 12:24:25 +000018945
cerione9d361a2005-03-04 17:35:29 +000018946 /* System Linkage Instructions */
cerion8c3adda2005-01-31 11:54:05 +000018947 case 0x11: // sc
sewardjdd40fdf2006-12-24 02:20:24 +000018948 if (dis_syslink(theInstr, abiinfo, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000018949 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +000018950
sewardj334870d2006-02-07 16:42:39 +000018951 /* Trap Instructions */
carllbb3f4012012-10-29 20:23:41 +000018952 case 0x02: // tdi
18953 if (!mode64) goto decode_failure;
18954 if (dis_trapi(theInstr, &dres)) goto decode_success;
18955 goto decode_failure;
18956
18957 case 0x03: // twi
sewardj334870d2006-02-07 16:42:39 +000018958 if (dis_trapi(theInstr, &dres)) goto decode_success;
18959 goto decode_failure;
cerion8c3adda2005-01-31 11:54:05 +000018960
cerion3d870a32005-03-18 12:23:33 +000018961 /* Floating Point Load Instructions */
cerion094d1392005-06-20 13:45:57 +000018962 case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd
18963 case 0x33: // lfdu
sewardj5117ce12006-01-27 21:20:15 +000018964 if (!allow_F) goto decode_noF;
cerion3d870a32005-03-18 12:23:33 +000018965 if (dis_fp_load( theInstr )) goto decode_success;
cerione9d361a2005-03-04 17:35:29 +000018966 goto decode_failure;
cerion995bc362005-02-03 11:03:31 +000018967
cerion3d870a32005-03-18 12:23:33 +000018968 /* Floating Point Store Instructions */
18969 case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx
18970 case 0x37: // stfdux
sewardj5117ce12006-01-27 21:20:15 +000018971 if (!allow_F) goto decode_noF;
cerion3d870a32005-03-18 12:23:33 +000018972 if (dis_fp_store( theInstr )) goto decode_success;
18973 goto decode_failure;
18974
sewardj7e846302010-09-03 23:37:02 +000018975 /* Floating Point Load Double Pair Instructions */
18976 case 0x39: case 0x3D:
18977 if (!allow_F) goto decode_noF;
18978 if (dis_fp_pair( theInstr )) goto decode_success;
18979 goto decode_failure;
18980
carll78850ae2013-09-10 18:46:40 +000018981 /* 128-bit Integer Load */
18982 case 0x38: // lq
18983 if (dis_int_load( theInstr )) goto decode_success;
18984 goto decode_failure;
18985
cerionf0de28c2005-12-13 20:21:11 +000018986 /* 64bit Integer Loads */
18987 case 0x3A: // ld, ldu, lwa
18988 if (!mode64) goto decode_failure;
18989 if (dis_int_load( theInstr )) goto decode_success;
18990 goto decode_failure;
18991
sewardje14bb9f2005-07-22 09:39:02 +000018992 case 0x3B:
sewardj5117ce12006-01-27 21:20:15 +000018993 if (!allow_F) goto decode_noF;
sewardj66d5ef22011-04-15 11:55:00 +000018994 opc2 = ifieldOPClo10(theInstr);
sewardjc6bbd472012-04-02 10:20:48 +000018995
sewardj66d5ef22011-04-15 11:55:00 +000018996 switch (opc2) {
sewardjc6bbd472012-04-02 10:20:48 +000018997 case 0x2: // dadd - DFP Add
18998 case 0x202: // dsub - DFP Subtract
18999 case 0x22: // dmul - DFP Mult
19000 case 0x222: // ddiv - DFP Divide
sewardjc66d6fa2012-04-02 21:24:12 +000019001 if (!allow_DFP) goto decode_noDFP;
sewardjc6bbd472012-04-02 10:20:48 +000019002 if (dis_dfp_arith( theInstr ))
19003 goto decode_success;
sewardjcdc376d2012-04-23 11:21:12 +000019004 case 0x82: // dcmpo, DFP comparison ordered instruction
19005 case 0x282: // dcmpu, DFP comparison unordered instruction
19006 if (!allow_DFP)
19007 goto decode_failure;
19008 if (dis_dfp_compare( theInstr ) )
19009 goto decode_success;
19010 goto decode_failure;
sewardj26217b02012-04-12 17:19:48 +000019011 case 0x102: // dctdp - DFP convert to DFP long
19012 case 0x302: // drsp - DFP round to dfp short
19013 case 0x122: // dctfix - DFP convert to fixed
19014 if (!allow_DFP)
19015 goto decode_failure;
19016 if (dis_dfp_fmt_conv( theInstr ))
19017 goto decode_success;
19018 goto decode_failure;
19019 case 0x322: // POWER 7 inst, dcffix - DFP convert from fixed
19020 if (!allow_VX)
19021 goto decode_failure;
19022 if (dis_dfp_fmt_conv( theInstr ))
19023 goto decode_success;
19024 goto decode_failure;
sewardj4c96e612012-06-02 23:47:02 +000019025 case 0x2A2: // dtstsf - DFP number of significant digits
19026 if (!allow_DFP)
19027 goto decode_failure;
19028 if (dis_dfp_significant_digits(theInstr))
19029 goto decode_success;
19030 goto decode_failure;
19031 case 0x142: // ddedpd DFP Decode DPD to BCD
19032 case 0x342: // denbcd DFP Encode BCD to DPD
19033 if (!allow_DFP)
19034 goto decode_failure;
19035 if (dis_dfp_bcd(theInstr))
19036 goto decode_success;
19037 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000019038 case 0x162: // dxex - Extract exponent
19039 case 0x362: // diex - Insert exponent
19040 if (!allow_DFP)
19041 goto decode_failure;
19042 if (dis_dfp_extract_insert( theInstr ) )
19043 goto decode_success;
19044 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019045 case 0x3CE: // fcfidus (implemented as native insn)
sewardj66d5ef22011-04-15 11:55:00 +000019046 if (!allow_VX)
19047 goto decode_noVX;
19048 if (dis_fp_round( theInstr ))
19049 goto decode_success;
19050 goto decode_failure;
19051 case 0x34E: // fcfids
19052 if (dis_fp_round( theInstr ))
19053 goto decode_success;
19054 goto decode_failure;
19055 }
19056
sewardj26217b02012-04-12 17:19:48 +000019057 opc2 = ifieldOPClo9( theInstr );
19058 switch (opc2) {
19059 case 0x42: // dscli, DFP shift left
19060 case 0x62: // dscri, DFP shift right
19061 if (!allow_DFP)
19062 goto decode_failure;
19063 if (dis_dfp_shift( theInstr ))
19064 goto decode_success;
19065 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019066 case 0xc2: // dtstdc, DFP test data class
19067 case 0xe2: // dtstdg, DFP test data group
19068 if (!allow_DFP)
19069 goto decode_failure;
19070 if (dis_dfp_class_test( theInstr ))
19071 goto decode_success;
19072 goto decode_failure;
sewardj26217b02012-04-12 17:19:48 +000019073 }
19074
sewardjcdc376d2012-04-23 11:21:12 +000019075 opc2 = ifieldOPClo8( theInstr );
19076 switch (opc2) {
19077 case 0x3: // dqua - DFP Quantize
19078 case 0x23: // drrnd - DFP Reround
19079 case 0x43: // dquai - DFP Quantize immediate
19080 if (!allow_DFP)
19081 goto decode_failure;
19082 if (dis_dfp_quantize_sig_rrnd( theInstr ) )
19083 goto decode_success;
19084 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019085 case 0xA2: // dtstex - DFP Test exponent
19086 if (!allow_DFP)
19087 goto decode_failure;
19088 if (dis_dfp_exponent_test( theInstr ) )
19089 goto decode_success;
19090 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000019091 case 0x63: // drintx - Round to an integer value
19092 case 0xE3: // drintn - Round to an integer value
19093 if (!allow_DFP)
19094 goto decode_failure;
19095 if (dis_dfp_round( theInstr ) ) {
19096 goto decode_success;
19097 }
19098 goto decode_failure;
19099 default:
19100 break; /* fall through to next opc2 check */
19101 }
19102
cerion76de5cf2005-11-18 18:25:12 +000019103 opc2 = IFIELD(theInstr, 1, 5);
sewardje14bb9f2005-07-22 09:39:02 +000019104 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +000019105 /* Floating Point Arith Instructions */
19106 case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds
sewardj5117ce12006-01-27 21:20:15 +000019107 case 0x19: // fmuls
ceriond953ebb2005-11-29 13:27:20 +000019108 if (dis_fp_arith(theInstr)) goto decode_success;
19109 goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000019110 case 0x16: // fsqrts
19111 if (!allow_FX) goto decode_noFX;
19112 if (dis_fp_arith(theInstr)) goto decode_success;
19113 goto decode_failure;
19114 case 0x18: // fres
19115 if (!allow_GX) goto decode_noGX;
19116 if (dis_fp_arith(theInstr)) goto decode_success;
19117 goto decode_failure;
19118
ceriond953ebb2005-11-29 13:27:20 +000019119 /* Floating Point Mult-Add Instructions */
19120 case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs
19121 case 0x1F: // fnmadds
19122 if (dis_fp_multadd(theInstr)) goto decode_success;
19123 goto decode_failure;
sewardj79fd33f2006-01-29 17:07:57 +000019124
19125 case 0x1A: // frsqrtes
19126 if (!allow_GX) goto decode_noGX;
19127 if (dis_fp_arith(theInstr)) goto decode_success;
19128 goto decode_failure;
sewardj66d5ef22011-04-15 11:55:00 +000019129
ceriond953ebb2005-11-29 13:27:20 +000019130 default:
19131 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019132 }
19133 break;
cerion3d870a32005-03-18 12:23:33 +000019134
sewardj66d5ef22011-04-15 11:55:00 +000019135 case 0x3C: // VSX instructions (except load/store)
19136 {
floriandc7948f2012-02-15 04:05:05 +000019137 // All of these VSX instructions use some VMX facilities, so
19138 // if allow_V is not set, we'll skip trying to decode.
19139 if (!allow_V) goto decode_noVX;
19140
sewardj66d5ef22011-04-15 11:55:00 +000019141 UInt vsxOpc2 = get_VSX60_opc2(opc2);
19142 /* The vsxOpc2 returned is the "normalized" value, representing the
19143 * instructions secondary opcode as taken from the standard secondary
19144 * opcode field [21:30] (IBM notatition), even if the actual field
19145 * is non-standard. These normalized values are given in the opcode
19146 * appendices of the ISA 2.06 document.
19147 */
sewardj66d5ef22011-04-15 11:55:00 +000019148
19149 switch (vsxOpc2) {
19150 case 0x8: case 0x28: case 0x48: case 0xc8: // xxsldwi, xxpermdi, xxmrghw, xxmrglw
sewardj4aa412a2011-07-24 14:13:21 +000019151 case 0x018: case 0x148: // xxsel, xxspltw
19152 if (dis_vx_permute_misc(theInstr, vsxOpc2)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019153 goto decode_failure;
carll6c758b62013-10-03 21:38:45 +000019154 case 0x268: case 0x248: case 0x288: // xxlxor, xxlor, xxlnor,
19155 case 0x208: case 0x228: case 0x2A8: // xxland, xxlandc, xxlorc
19156 case 0x2C8: case 0x2E8: // xxlnand, xxleqv
sewardj66d5ef22011-04-15 11:55:00 +000019157 if (dis_vx_logic(theInstr, vsxOpc2)) goto decode_success;
19158 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019159 case 0x2B2: case 0x2C0: // xsabsdp, xscpsgndp
19160 case 0x2D2: case 0x2F2: // xsnabsdp, xsnegdp
19161 case 0x280: case 0x2A0: // xsmaxdp, xsmindp
19162 case 0x0F2: case 0x0D2: // xsrdpim, xsrdpip
carll6c758b62013-10-03 21:38:45 +000019163 case 0x034: case 0x014: // xsresp, xsrsqrtesp
sewardje71e56a2011-09-05 12:11:06 +000019164 case 0x0B4: case 0x094: // xsredp, xsrsqrtedp
19165 case 0x0D6: case 0x0B2: // xsrdpic, xsrdpiz
carll6c758b62013-10-03 21:38:45 +000019166 case 0x092: case 0x232: // xsrdpi, xsrsp
sewardj4aa412a2011-07-24 14:13:21 +000019167 if (dis_vxs_misc(theInstr, vsxOpc2)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019168 goto decode_failure;
19169 case 0x08C: case 0x0AC: // xscmpudp, xscmpodp
19170 if (dis_vx_cmp(theInstr, vsxOpc2)) goto decode_success;
19171 goto decode_failure;
carll6c758b62013-10-03 21:38:45 +000019172 case 0x0: case 0x020: // xsaddsp, xssubsp
19173 case 0x080: // xsadddp
19174 case 0x060: case 0x0E0: // xsdivsp, xsdivdp
19175 case 0x004: case 0x024: // xsmaddasp, xsmaddmsp
sewardj66d5ef22011-04-15 11:55:00 +000019176 case 0x084: case 0x0A4: // xsmaddadp, xsmaddmdp
carll6c758b62013-10-03 21:38:45 +000019177 case 0x044: case 0x064: // xsmsubasp, xsmsubmsp
sewardj66d5ef22011-04-15 11:55:00 +000019178 case 0x0C4: case 0x0E4: // xsmsubadp, xsmsubmdp
carll6c758b62013-10-03 21:38:45 +000019179 case 0x204: case 0x224: // xsnmaddasp, xsnmaddmsp
sewardj66d5ef22011-04-15 11:55:00 +000019180 case 0x284: case 0x2A4: // xsnmaddadp, xsnmaddmdp
carll6c758b62013-10-03 21:38:45 +000019181 case 0x244: case 0x264: // xsnmsubasp, xsnmsubmsp
sewardj4aa412a2011-07-24 14:13:21 +000019182 case 0x2C4: case 0x2E4: // xsnmsubadp, xsnmsubmdp
carll6c758b62013-10-03 21:38:45 +000019183 case 0x040: case 0x0C0: // xsmulsp, xsmuldp
19184 case 0x0A0: // xssubdp
19185 case 0x016: case 0x096: // xssqrtsp,xssqrtdp
19186 case 0x0F4: case 0x0D4: // xstdivdp, xstsqrtdp
sewardj4aa412a2011-07-24 14:13:21 +000019187 if (dis_vxs_arith(theInstr, vsxOpc2)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019188 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019189 case 0x180: // xvadddp
19190 case 0x1E0: // xvdivdp
19191 case 0x1C0: // xvmuldp
19192 case 0x1A0: // xvsubdp
19193 case 0x184: case 0x1A4: // xvmaddadp, xvmaddmdp
19194 case 0x1C4: case 0x1E4: // xvmsubadp, xvmsubmdp
19195 case 0x384: case 0x3A4: // xvnmaddadp, xvnmaddmdp
19196 case 0x3C4: case 0x3E4: // xvnmsubadp, xvnmsubmdp
sewardje71e56a2011-09-05 12:11:06 +000019197 case 0x1D4: case 0x1F4: // xvtsqrtdp, xvtdivdp
19198 case 0x196: // xvsqrtdp
sewardj4aa412a2011-07-24 14:13:21 +000019199 if (dis_vxv_dp_arith(theInstr, vsxOpc2)) goto decode_success;
19200 goto decode_failure;
19201 case 0x100: // xvaddsp
19202 case 0x160: // xvdivsp
19203 case 0x140: // xvmulsp
19204 case 0x120: // xvsubsp
19205 case 0x104: case 0x124: // xvmaddasp, xvmaddmsp
19206 case 0x144: case 0x164: // xvmsubasp, xvmsubmsp
19207 case 0x304: case 0x324: // xvnmaddasp, xvnmaddmsp
19208 case 0x344: case 0x364: // xvnmsubasp, xvnmsubmsp
sewardje71e56a2011-09-05 12:11:06 +000019209 case 0x154: case 0x174: // xvtsqrtsp, xvtdivsp
19210 case 0x116: // xvsqrtsp
sewardj4aa412a2011-07-24 14:13:21 +000019211 if (dis_vxv_sp_arith(theInstr, vsxOpc2)) goto decode_success;
19212 goto decode_failure;
19213
carll6c758b62013-10-03 21:38:45 +000019214 case 0x250: // xscvuxdsp
floriandc7948f2012-02-15 04:05:05 +000019215 case 0x2D0: case 0x3d0: // xscvuxddp, xvcvuxddp
19216 case 0x350: case 0x1d0: // xvcvuxdsp, xvcvuxwdp
19217 case 0x090: // xscvdpuxws
19218 // The above VSX conversion instructions employ some ISA 2.06
19219 // floating point conversion instructions under the covers,
19220 // so if allow_VX (which means "supports ISA 2.06") is not set,
19221 // we'll skip the decode.
19222 if (!allow_VX) goto decode_noVX;
19223 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
19224 goto decode_failure;
19225
carll6c758b62013-10-03 21:38:45 +000019226 case 0x2B0: // xscvdpsxds
19227 case 0x270: case 0x2F0: // xscvsxdsp, xscvsxddp
sewardj4aa412a2011-07-24 14:13:21 +000019228 case 0x1b0: case 0x130: // xvcvdpsxws, xvcvspsxws
19229 case 0x0b0: case 0x290: // xscvdpsxws, xscvdpuxds
carll0c74bb52013-08-12 18:01:40 +000019230 case 0x212: case 0x216: // xscvdpsp, xscvdpspn
19231 case 0x292: case 0x296: // xscvspdp, xscvspdpn
19232 case 0x312: // xvcvdpsp
sewardje71e56a2011-09-05 12:11:06 +000019233 case 0x390: case 0x190: // xvcvdpuxds, xvcvdpuxws
19234 case 0x3B0: case 0x310: // xvcvdpsxds, xvcvspuxds
19235 case 0x392: case 0x330: // xvcvspdp, xvcvspsxds
19236 case 0x110: case 0x3f0: // xvcvspuxws, xvcvsxddp
19237 case 0x370: case 0x1f0: // xvcvsxdsp, xvcvsxwdp
19238 case 0x170: case 0x150: // xvcvsxwsp, xvcvuxwsp
sewardj66d5ef22011-04-15 11:55:00 +000019239 if (dis_vx_conv(theInstr, vsxOpc2)) goto decode_success;
19240 goto decode_failure;
19241
sewardj4aa412a2011-07-24 14:13:21 +000019242 case 0x18C: case 0x38C: // xvcmpeqdp[.]
19243 case 0x10C: case 0x30C: // xvcmpeqsp[.]
19244 case 0x14C: case 0x34C: // xvcmpgesp[.]
19245 case 0x12C: case 0x32C: // xvcmpgtsp[.]
19246 case 0x1CC: case 0x3CC: // xvcmpgedp[.]
19247 case 0x1AC: case 0x3AC: // xvcmpgtdp[.]
19248 if (dis_vvec_cmp(theInstr, vsxOpc2)) goto decode_success;
19249 goto decode_failure;
19250
19251 case 0x134: // xvresp
sewardje71e56a2011-09-05 12:11:06 +000019252 case 0x1B4: // xvredp
19253 case 0x194: case 0x114: // xvrsqrtedp, xvrsqrtesp
19254 case 0x380: case 0x3A0: // xvmaxdp, xvmindp
sewardj4aa412a2011-07-24 14:13:21 +000019255 case 0x300: case 0x320: // xvmaxsp, xvminsp
sewardje71e56a2011-09-05 12:11:06 +000019256 case 0x3C0: case 0x340: // xvcpsgndp, xvcpsgnsp
19257 case 0x3B2: case 0x332: // xvabsdp, xvabssp
19258 case 0x3D2: case 0x352: // xvnabsdp, xvnabssp
19259 case 0x192: case 0x1D6: // xvrdpi, xvrdpic
19260 case 0x1F2: case 0x1D2: // xvrdpim, xvrdpip
19261 case 0x1B2: case 0x3F2: // xvrdpiz, xvnegdp
19262 case 0x112: case 0x156: // xvrspi, xvrspic
19263 case 0x172: case 0x152: // xvrspim, xvrspip
19264 case 0x132: // xvrspiz
sewardj4aa412a2011-07-24 14:13:21 +000019265 if (dis_vxv_misc(theInstr, vsxOpc2)) goto decode_success;
19266 goto decode_failure;
19267
sewardj66d5ef22011-04-15 11:55:00 +000019268 default:
19269 goto decode_failure;
19270 }
19271 break;
19272 }
19273
cerionf0de28c2005-12-13 20:21:11 +000019274 /* 64bit Integer Stores */
carll78850ae2013-09-10 18:46:40 +000019275 case 0x3E: // std, stdu, stq
sewardjdd40fdf2006-12-24 02:20:24 +000019276 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionf0de28c2005-12-13 20:21:11 +000019277 goto decode_failure;
19278
cerion3d870a32005-03-18 12:23:33 +000019279 case 0x3F:
sewardj5117ce12006-01-27 21:20:15 +000019280 if (!allow_F) goto decode_noF;
cerion5b2325f2005-12-23 00:55:09 +000019281 /* Instrs using opc[1:5] never overlap instrs using opc[1:10],
cerion3d870a32005-03-18 12:23:33 +000019282 so we can simply fall through the first switch statement */
19283
cerion76de5cf2005-11-18 18:25:12 +000019284 opc2 = IFIELD(theInstr, 1, 5);
cerion3d870a32005-03-18 12:23:33 +000019285 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +000019286 /* Floating Point Arith Instructions */
sewardj5117ce12006-01-27 21:20:15 +000019287 case 0x12: case 0x14: case 0x15: // fdiv, fsub, fadd
19288 case 0x19: // fmul
19289 if (dis_fp_arith(theInstr)) goto decode_success;
19290 goto decode_failure;
19291 case 0x16: // fsqrt
19292 if (!allow_FX) goto decode_noFX;
19293 if (dis_fp_arith(theInstr)) goto decode_success;
19294 goto decode_failure;
19295 case 0x17: case 0x1A: // fsel, frsqrte
19296 if (!allow_GX) goto decode_noGX;
ceriond953ebb2005-11-29 13:27:20 +000019297 if (dis_fp_arith(theInstr)) goto decode_success;
19298 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019299
ceriond953ebb2005-11-29 13:27:20 +000019300 /* Floating Point Mult-Add Instructions */
19301 case 0x1C: case 0x1D: case 0x1E: // fmsub, fmadd, fnmsub
19302 case 0x1F: // fnmadd
19303 if (dis_fp_multadd(theInstr)) goto decode_success;
19304 goto decode_failure;
sewardj79fd33f2006-01-29 17:07:57 +000019305
19306 case 0x18: // fre
19307 if (!allow_GX) goto decode_noGX;
19308 if (dis_fp_arith(theInstr)) goto decode_success;
19309 goto decode_failure;
carll0c74bb52013-08-12 18:01:40 +000019310
ceriond953ebb2005-11-29 13:27:20 +000019311 default:
19312 break; // Fall through
cerion3d870a32005-03-18 12:23:33 +000019313 }
19314
cerion76de5cf2005-11-18 18:25:12 +000019315 opc2 = IFIELD(theInstr, 1, 10);
sewardje14bb9f2005-07-22 09:39:02 +000019316 switch (opc2) {
sewardjc6bbd472012-04-02 10:20:48 +000019317 /* 128-bit DFP instructions */
19318 case 0x2: // daddq - DFP Add
19319 case 0x202: // dsubq - DFP Subtract
19320 case 0x22: // dmulq - DFP Mult
19321 case 0x222: // ddivq - DFP Divide
sewardjc66d6fa2012-04-02 21:24:12 +000019322 if (!allow_DFP) goto decode_noDFP;
sewardjc6bbd472012-04-02 10:20:48 +000019323 if (dis_dfp_arithq( theInstr ))
19324 goto decode_success;
19325 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000019326 case 0x162: // dxexq - DFP Extract exponent
19327 case 0x362: // diexq - DFP Insert exponent
19328 if (!allow_DFP)
19329 goto decode_failure;
19330 if (dis_dfp_extract_insertq( theInstr ))
19331 goto decode_success;
19332 goto decode_failure;
19333
19334 case 0x82: // dcmpoq, DFP comparison ordered instruction
19335 case 0x282: // dcmpuq, DFP comparison unordered instruction
19336 if (!allow_DFP)
19337 goto decode_failure;
19338 if (dis_dfp_compare( theInstr ) )
19339 goto decode_success;
19340 goto decode_failure;
sewardjc6bbd472012-04-02 10:20:48 +000019341
sewardj26217b02012-04-12 17:19:48 +000019342 case 0x102: // dctqpq - DFP convert to DFP extended
19343 case 0x302: // drdpq - DFP round to dfp Long
19344 case 0x122: // dctfixq - DFP convert to fixed quad
19345 case 0x322: // dcffixq - DFP convert from fixed quad
19346 if (!allow_DFP)
19347 goto decode_failure;
19348 if (dis_dfp_fmt_convq( theInstr ))
19349 goto decode_success;
19350 goto decode_failure;
19351
sewardj4c96e612012-06-02 23:47:02 +000019352 case 0x2A2: // dtstsfq - DFP number of significant digits
19353 if (!allow_DFP)
19354 goto decode_failure;
19355 if (dis_dfp_significant_digits(theInstr))
19356 goto decode_success;
19357 goto decode_failure;
19358
19359 case 0x142: // ddedpdq DFP Decode DPD to BCD
19360 case 0x342: // denbcdq DFP Encode BCD to DPD
19361 if (!allow_DFP)
19362 goto decode_failure;
19363 if (dis_dfp_bcdq(theInstr))
19364 goto decode_success;
19365 goto decode_failure;
19366
ceriond953ebb2005-11-29 13:27:20 +000019367 /* Floating Point Compare Instructions */
19368 case 0x000: // fcmpu
19369 case 0x020: // fcmpo
19370 if (dis_fp_cmp(theInstr)) goto decode_success;
19371 goto decode_failure;
cerion2831b002005-11-30 19:55:22 +000019372
sewardj66d5ef22011-04-15 11:55:00 +000019373 case 0x080: // ftdiv
sewardje71e56a2011-09-05 12:11:06 +000019374 case 0x0A0: // ftsqrt
19375 if (dis_fp_tests(theInstr)) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019376 goto decode_failure;
19377
ceriond953ebb2005-11-29 13:27:20 +000019378 /* Floating Point Rounding/Conversion Instructions */
19379 case 0x00C: // frsp
19380 case 0x00E: // fctiw
19381 case 0x00F: // fctiwz
sewardj6be67232006-01-24 19:00:05 +000019382 case 0x32E: // fctid
19383 case 0x32F: // fctidz
19384 case 0x34E: // fcfid
ceriond953ebb2005-11-29 13:27:20 +000019385 if (dis_fp_round(theInstr)) goto decode_success;
19386 goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019387 case 0x3CE: case 0x3AE: case 0x3AF: // fcfidu, fctidu[z] (implemented as native insns)
19388 case 0x08F: case 0x08E: // fctiwu[z] (implemented as native insns)
sewardj66d5ef22011-04-15 11:55:00 +000019389 if (!allow_VX) goto decode_noVX;
19390 if (dis_fp_round(theInstr)) goto decode_success;
19391 goto decode_failure;
19392
sewardj0f1ef862008-08-08 08:37:06 +000019393 /* Power6 rounding stuff */
19394 case 0x1E8: // frim
19395 case 0x1C8: // frip
19396 case 0x188: // frin
19397 case 0x1A8: // friz
sewardj7e846302010-09-03 23:37:02 +000019398 /* A hack to check for P6 capability . . . */
19399 if ((allow_F && allow_V && allow_FX && allow_GX) &&
19400 (dis_fp_round(theInstr)))
sewardj0f1ef862008-08-08 08:37:06 +000019401 goto decode_success;
19402 goto decode_failure;
ceriond953ebb2005-11-29 13:27:20 +000019403
19404 /* Floating Point Move Instructions */
sewardj7e846302010-09-03 23:37:02 +000019405 case 0x008: // fcpsgn
ceriond953ebb2005-11-29 13:27:20 +000019406 case 0x028: // fneg
19407 case 0x048: // fmr
19408 case 0x088: // fnabs
19409 case 0x108: // fabs
19410 if (dis_fp_move( theInstr )) goto decode_success;
19411 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019412
carll78850ae2013-09-10 18:46:40 +000019413 case 0x3c6: case 0x346: // fmrgew, fmrgow
19414 if (dis_fp_merge( theInstr )) goto decode_success;
19415 goto decode_failure;
19416
ceriond953ebb2005-11-29 13:27:20 +000019417 /* Floating Point Status/Control Register Instructions */
cerion3ea49ee2006-01-04 10:53:00 +000019418 case 0x026: // mtfsb1
sewardj496b88f2006-10-04 17:46:11 +000019419 case 0x040: // mcrfs
ceriond953ebb2005-11-29 13:27:20 +000019420 case 0x046: // mtfsb0
19421 case 0x086: // mtfsfi
19422 case 0x247: // mffs
19423 case 0x2C7: // mtfsf
sewardjc6bbd472012-04-02 10:20:48 +000019424 // Some of the above instructions need to know more about the
19425 // ISA level supported by the host.
19426 if (dis_fp_scr( theInstr, allow_GX )) goto decode_success;
ceriond953ebb2005-11-29 13:27:20 +000019427 goto decode_failure;
cerionf0de28c2005-12-13 20:21:11 +000019428
ceriond953ebb2005-11-29 13:27:20 +000019429 default:
sewardj26217b02012-04-12 17:19:48 +000019430 break; // Fall through...
19431 }
19432
19433 opc2 = ifieldOPClo9( theInstr );
19434 switch (opc2) {
19435 case 0x42: // dscli, DFP shift left
19436 case 0x62: // dscri, DFP shift right
19437 if (!allow_DFP)
19438 goto decode_failure;
19439 if (dis_dfp_shiftq( theInstr ))
19440 goto decode_success;
ceriond953ebb2005-11-29 13:27:20 +000019441 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019442 case 0xc2: // dtstdc, DFP test data class
19443 case 0xe2: // dtstdg, DFP test data group
19444 if (!allow_DFP)
19445 goto decode_failure;
19446 if (dis_dfp_class_test( theInstr ))
19447 goto decode_success;
19448 goto decode_failure;
sewardj26217b02012-04-12 17:19:48 +000019449 default:
sewardj26217b02012-04-12 17:19:48 +000019450 break;
sewardje14bb9f2005-07-22 09:39:02 +000019451 }
sewardjcdc376d2012-04-23 11:21:12 +000019452
19453 opc2 = ifieldOPClo8( theInstr );
19454 switch (opc2) {
19455 case 0x3: // dquaq - DFP Quantize Quad
19456 case 0x23: // drrndq - DFP Reround Quad
19457 case 0x43: // dquaiq - DFP Quantize immediate Quad
19458 if (!allow_DFP)
19459 goto decode_failure;
19460 if (dis_dfp_quantize_sig_rrndq( theInstr ))
19461 goto decode_success;
19462 goto decode_failure;
sewardj5eff1c52012-04-29 20:19:17 +000019463 case 0xA2: // dtstexq - DFP Test exponent Quad
19464 if (dis_dfp_exponent_test( theInstr ) )
19465 goto decode_success;
19466 goto decode_failure;
sewardjcdc376d2012-04-23 11:21:12 +000019467 case 0x63: // drintxq - DFP Round to an integer value
19468 case 0xE3: // drintnq - DFP Round to an integer value
19469 if (!allow_DFP)
19470 goto decode_failure;
19471 if (dis_dfp_roundq( theInstr ))
19472 goto decode_success;
19473 goto decode_failure;
19474
19475 default:
19476 goto decode_failure;
19477 }
cerion3d870a32005-03-18 12:23:33 +000019478 break;
sewardj26217b02012-04-12 17:19:48 +000019479
cerion91ad5362005-01-27 23:02:41 +000019480 case 0x13:
cerionb85e8bb2005-02-16 08:54:33 +000019481 switch (opc2) {
cerion91ad5362005-01-27 23:02:41 +000019482
ceriond953ebb2005-11-29 13:27:20 +000019483 /* Condition Register Logical Instructions */
19484 case 0x101: case 0x081: case 0x121: // crand, crandc, creqv
19485 case 0x0E1: case 0x021: case 0x1C1: // crnand, crnor, cror
19486 case 0x1A1: case 0x0C1: case 0x000: // crorc, crxor, mcrf
19487 if (dis_cond_logic( theInstr )) goto decode_success;
19488 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +000019489
ceriond953ebb2005-11-29 13:27:20 +000019490 /* Branch Instructions */
19491 case 0x210: case 0x010: // bcctr, bclr
sewardjdd40fdf2006-12-24 02:20:24 +000019492 if (dis_branch(theInstr, abiinfo, &dres,
sewardjaca070a2006-10-17 00:28:22 +000019493 resteerOkFn, callback_opaque))
sewardjc716aea2006-01-17 01:48:46 +000019494 goto decode_success;
ceriond953ebb2005-11-29 13:27:20 +000019495 goto decode_failure;
19496
19497 /* Memory Synchronization Instructions */
19498 case 0x096: // isync
19499 if (dis_memsync( theInstr )) goto decode_success;
19500 goto decode_failure;
carll78850ae2013-09-10 18:46:40 +000019501
ceriond953ebb2005-11-29 13:27:20 +000019502 default:
19503 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +000019504 }
19505 break;
cerion91ad5362005-01-27 23:02:41 +000019506
19507
cerionb85e8bb2005-02-16 08:54:33 +000019508 case 0x1F:
cerione9d361a2005-03-04 17:35:29 +000019509
19510 /* For arith instns, bit10 is the OE flag (overflow enable) */
19511
cerion76de5cf2005-11-18 18:25:12 +000019512 opc2 = IFIELD(theInstr, 1, 9);
cerionb85e8bb2005-02-16 08:54:33 +000019513 switch (opc2) {
ceriond953ebb2005-11-29 13:27:20 +000019514 /* Integer Arithmetic Instructions */
19515 case 0x10A: case 0x00A: case 0x08A: // add, addc, adde
19516 case 0x0EA: case 0x0CA: case 0x1EB: // addme, addze, divw
19517 case 0x1CB: case 0x04B: case 0x00B: // divwu, mulhw, mulhwu
19518 case 0x0EB: case 0x068: case 0x028: // mullw, neg, subf
19519 case 0x008: case 0x088: case 0x0E8: // subfc, subfe, subfme
sewardj4aa412a2011-07-24 14:13:21 +000019520 case 0x0C8: // subfze
19521 if (dis_int_arith( theInstr )) goto decode_success;
19522 goto decode_failure;
19523
19524 case 0x18B: // divweu (implemented as native insn)
sewardje71e56a2011-09-05 12:11:06 +000019525 case 0x1AB: // divwe (implemented as native insn)
sewardj4aa412a2011-07-24 14:13:21 +000019526 if (!allow_VX) goto decode_noVX;
ceriond953ebb2005-11-29 13:27:20 +000019527 if (dis_int_arith( theInstr )) goto decode_success;
19528 goto decode_failure;
cerionf0de28c2005-12-13 20:21:11 +000019529
19530 /* 64bit Integer Arithmetic */
19531 case 0x009: case 0x049: case 0x0E9: // mulhdu, mulhd, mulld
sewardj4aa412a2011-07-24 14:13:21 +000019532 case 0x1C9: case 0x1E9: // divdu, divd
19533 if (!mode64) goto decode_failure;
19534 if (dis_int_arith( theInstr )) goto decode_success;
19535 goto decode_failure;
19536
19537 case 0x1A9: // divde (implemented as native insn)
sewardje71e56a2011-09-05 12:11:06 +000019538 case 0x189: // divdeuo (implemented as native insn)
sewardj4aa412a2011-07-24 14:13:21 +000019539 if (!allow_VX) goto decode_noVX;
cerionf0de28c2005-12-13 20:21:11 +000019540 if (!mode64) goto decode_failure;
19541 if (dis_int_arith( theInstr )) goto decode_success;
19542 goto decode_failure;
19543
sewardj7e846302010-09-03 23:37:02 +000019544 case 0x1FC: // cmpb
19545 if (dis_int_logic( theInstr )) goto decode_success;
19546 goto decode_failure;
19547
ceriond953ebb2005-11-29 13:27:20 +000019548 default:
19549 break; // Fall through...
cerionb85e8bb2005-02-16 08:54:33 +000019550 }
cerion91ad5362005-01-27 23:02:41 +000019551
cerione9d361a2005-03-04 17:35:29 +000019552 /* All remaining opcodes use full 10 bits. */
19553
cerion76de5cf2005-11-18 18:25:12 +000019554 opc2 = IFIELD(theInstr, 1, 10);
cerionb85e8bb2005-02-16 08:54:33 +000019555 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +000019556 /* Integer Compare Instructions */
19557 case 0x000: case 0x020: // cmp, cmpl
19558 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019559 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000019560
cerione9d361a2005-03-04 17:35:29 +000019561 /* Integer Logical Instructions */
19562 case 0x01C: case 0x03C: case 0x01A: // and, andc, cntlzw
19563 case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh
19564 case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or
19565 case 0x19C: case 0x13C: // orc, xor
sewardj7e846302010-09-03 23:37:02 +000019566 case 0x2DF: case 0x25F: // mftgpr, mffgpr
cerione9d361a2005-03-04 17:35:29 +000019567 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019568 goto decode_failure;
cerion932ad942005-01-30 10:18:50 +000019569
carll8943d022013-10-02 16:25:57 +000019570 case 0x28E: case 0x2AE: // tbegin., tend.
19571 case 0x2EE: case 0x2CE: case 0x30E: // tsr., tcheck., tabortwc.
19572 case 0x32E: case 0x34E: case 0x36E: // tabortdc., tabortwci., tabortdci.
carllfcce5f82013-10-09 17:52:01 +000019573 case 0x38E: case 0x3AE: case 0x3EE: // tabort., treclaim., trechkpt.
carll8943d022013-10-02 16:25:57 +000019574 if (dis_transactional_memory( theInstr,
florian8462d112014-09-24 15:18:09 +000019575 getUIntPPCendianly( &guest_code[delta + 4]),
carll8943d022013-10-02 16:25:57 +000019576 abiinfo, &dres,
19577 resteerOkFn, callback_opaque))
19578 goto decode_success;
19579 goto decode_failure;
19580
cerionf0de28c2005-12-13 20:21:11 +000019581 /* 64bit Integer Logical Instructions */
cerion07b07a92005-12-22 14:32:35 +000019582 case 0x3DA: case 0x03A: // extsw, cntlzd
cerionf0de28c2005-12-13 20:21:11 +000019583 if (!mode64) goto decode_failure;
19584 if (dis_int_logic( theInstr )) goto decode_success;
19585 goto decode_failure;
19586
sewardj7e846302010-09-03 23:37:02 +000019587 /* 64bit Integer Parity Instructions */
carllbb3f4012012-10-29 20:23:41 +000019588 case 0xba: // prtyd
19589 if (!mode64) goto decode_failure;
19590 if (dis_int_parity( theInstr )) goto decode_success;
19591 goto decode_failure;
19592
19593 case 0x9a: // prtyw
sewardj7e846302010-09-03 23:37:02 +000019594 if (dis_int_parity( theInstr )) goto decode_success;
19595 goto decode_failure;
19596
cerione9d361a2005-03-04 17:35:29 +000019597 /* Integer Shift Instructions */
19598 case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
19599 case 0x218: // srw
19600 if (dis_int_shift( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019601 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000019602
cerionf0de28c2005-12-13 20:21:11 +000019603 /* 64bit Integer Shift Instructions */
19604 case 0x01B: case 0x31A: // sld, srad
cerion07b07a92005-12-22 14:32:35 +000019605 case 0x33A: case 0x33B: // sradi
cerionf0de28c2005-12-13 20:21:11 +000019606 case 0x21B: // srd
19607 if (!mode64) goto decode_failure;
19608 if (dis_int_shift( theInstr )) goto decode_success;
19609 goto decode_failure;
19610
cerione9d361a2005-03-04 17:35:29 +000019611 /* Integer Load Instructions */
19612 case 0x057: case 0x077: case 0x157: // lbzx, lbzux, lhax
19613 case 0x177: case 0x117: case 0x137: // lhaux, lhzx, lhzux
19614 case 0x017: case 0x037: // lwzx, lwzux
19615 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019616 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +000019617
cerionf0de28c2005-12-13 20:21:11 +000019618 /* 64bit Integer Load Instructions */
19619 case 0x035: case 0x015: // ldux, ldx
19620 case 0x175: case 0x155: // lwaux, lwax
19621 if (!mode64) goto decode_failure;
19622 if (dis_int_load( theInstr )) goto decode_success;
19623 goto decode_failure;
19624
sewardjb51f0f42005-07-18 11:38:02 +000019625 /* Integer Store Instructions */
cerione9d361a2005-03-04 17:35:29 +000019626 case 0x0F7: case 0x0D7: case 0x1B7: // stbux, stbx, sthux
19627 case 0x197: case 0x0B7: case 0x097: // sthx, stwux, stwx
sewardjdd40fdf2006-12-24 02:20:24 +000019628 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019629 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +000019630
cerionf0de28c2005-12-13 20:21:11 +000019631 /* 64bit Integer Store Instructions */
19632 case 0x0B5: case 0x095: // stdux, stdx
19633 if (!mode64) goto decode_failure;
sewardjdd40fdf2006-12-24 02:20:24 +000019634 if (dis_int_store( theInstr, abiinfo )) goto decode_success;
cerionf0de28c2005-12-13 20:21:11 +000019635 goto decode_failure;
19636
sewardj602857d2005-09-06 09:10:09 +000019637 /* Integer Load and Store with Byte Reverse Instructions */
carllbb3f4012012-10-29 20:23:41 +000019638 case 0x214: case 0x294: // ldbrx, stdbrx
19639 if (!mode64) goto decode_failure;
19640 if (dis_int_ldst_rev( theInstr )) goto decode_success;
19641 goto decode_failure;
19642
19643 case 0x216: case 0x316: case 0x296: // lwbrx, lhbrx, stwbrx
19644 case 0x396: // sthbrx
sewardj602857d2005-09-06 09:10:09 +000019645 if (dis_int_ldst_rev( theInstr )) goto decode_success;
19646 goto decode_failure;
19647
sewardj87e651f2005-09-09 08:31:18 +000019648 /* Integer Load and Store String Instructions */
19649 case 0x255: case 0x215: case 0x2D5: // lswi, lswx, stswi
19650 case 0x295: { // stswx
19651 Bool stopHere = False;
19652 Bool ok = dis_int_ldst_str( theInstr, &stopHere );
19653 if (!ok) goto decode_failure;
19654 if (stopHere) {
sewardj3dee8492012-04-20 00:13:28 +000019655 putGST( PPC_GST_CIA, mkSzImm(ty, nextInsnAddr()) );
19656 dres.jk_StopHere = Ijk_Boring;
19657 dres.whatNext = Dis_StopHere;
sewardj87e651f2005-09-09 08:31:18 +000019658 }
19659 goto decode_success;
19660 }
cerion645c9302005-01-31 10:09:59 +000019661
cerione9d361a2005-03-04 17:35:29 +000019662 /* Memory Synchronization Instructions */
19663 case 0x356: case 0x014: case 0x096: // eieio, lwarx, stwcx.
19664 case 0x256: // sync
19665 if (dis_memsync( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019666 goto decode_failure;
19667
cerionf0de28c2005-12-13 20:21:11 +000019668 /* 64bit Memory Synchronization Instructions */
19669 case 0x054: case 0x0D6: // ldarx, stdcx.
19670 if (!mode64) goto decode_failure;
19671 if (dis_memsync( theInstr )) goto decode_success;
19672 goto decode_failure;
19673
carll78850ae2013-09-10 18:46:40 +000019674 case 0x114: case 0x0B6: // lqarx, stqcx.
19675 if (dis_memsync( theInstr )) goto decode_success;
19676 goto decode_failure;
19677
cerione9d361a2005-03-04 17:35:29 +000019678 /* Processor Control Instructions */
carll78850ae2013-09-10 18:46:40 +000019679 case 0x33: case 0x73: // mfvsrd, mfvsrwz
19680 case 0xB3: case 0xD3: case 0xF3: // mtvsrd, mtvsrwa, mtvsrwz
cerione9d361a2005-03-04 17:35:29 +000019681 case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
19682 case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
carll78850ae2013-09-10 18:46:40 +000019683 case 0x220: // mcrxrt
sewardjdd40fdf2006-12-24 02:20:24 +000019684 if (dis_proc_ctl( abiinfo, theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019685 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +000019686
cerione9d361a2005-03-04 17:35:29 +000019687 /* Cache Management Instructions */
19688 case 0x2F6: case 0x056: case 0x036: // dcba, dcbf, dcbst
19689 case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
19690 case 0x3D6: // icbi
carll1f5fe1f2014-08-07 23:25:23 +000019691 if (dis_cache_manage( theInstr, &dres, archinfo ))
sewardjd94b73a2005-06-30 12:08:48 +000019692 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +000019693 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +000019694
sewardjb51f0f42005-07-18 11:38:02 +000019695//zz /* External Control Instructions */
19696//zz case 0x136: case 0x1B6: // eciwx, ecowx
19697//zz DIP("external control op => not implemented\n");
19698//zz goto decode_failure;
sewardj59c0d8f2007-08-28 14:48:35 +000019699
19700 /* Trap Instructions */
carllbb3f4012012-10-29 20:23:41 +000019701 case 0x004: // tw
19702 if (dis_trap(theInstr, &dres)) goto decode_success;
19703 goto decode_failure;
19704
19705 case 0x044: // td
19706 if (!mode64) goto decode_failure;
sewardj59c0d8f2007-08-28 14:48:35 +000019707 if (dis_trap(theInstr, &dres)) goto decode_success;
19708 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019709
19710 /* Floating Point Load Instructions */
19711 case 0x217: case 0x237: case 0x257: // lfsx, lfsux, lfdx
19712 case 0x277: // lfdux
sewardj5117ce12006-01-27 21:20:15 +000019713 if (!allow_F) goto decode_noF;
sewardje14bb9f2005-07-22 09:39:02 +000019714 if (dis_fp_load( theInstr )) goto decode_success;
19715 goto decode_failure;
19716
19717 /* Floating Point Store Instructions */
19718 case 0x297: case 0x2B7: case 0x2D7: // stfs, stfsu, stfd
sewardj5117ce12006-01-27 21:20:15 +000019719 case 0x2F7: // stfdu, stfiwx
19720 if (!allow_F) goto decode_noF;
sewardje14bb9f2005-07-22 09:39:02 +000019721 if (dis_fp_store( theInstr )) goto decode_success;
19722 goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000019723 case 0x3D7: // stfiwx
19724 if (!allow_F) goto decode_noF;
19725 if (!allow_GX) goto decode_noGX;
19726 if (dis_fp_store( theInstr )) goto decode_success;
19727 goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +000019728
sewardj7e846302010-09-03 23:37:02 +000019729 /* Floating Point Double Pair Indexed Instructions */
19730 case 0x317: // lfdpx (Power6)
19731 case 0x397: // stfdpx (Power6)
19732 if (!allow_F) goto decode_noF;
19733 if (dis_fp_pair(theInstr)) goto decode_success;
19734 goto decode_failure;
19735
19736 case 0x357: // lfiwax
19737 if (!allow_F) goto decode_noF;
19738 if (dis_fp_load( theInstr )) goto decode_success;
19739 goto decode_failure;
19740
sewardj66d5ef22011-04-15 11:55:00 +000019741 case 0x377: // lfiwzx
19742 if (!allow_F) goto decode_noF;
19743 if (dis_fp_load( theInstr )) goto decode_success;
19744 goto decode_failure;
19745
cerion32aad402005-09-10 12:02:24 +000019746 /* AltiVec instructions */
19747
19748 /* AV Cache Control - Data streams */
19749 case 0x156: case 0x176: case 0x336: // dst, dstst, dss
sewardj5117ce12006-01-27 21:20:15 +000019750 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019751 if (dis_av_datastream( theInstr )) goto decode_success;
19752 goto decode_failure;
ceriona982c052005-06-28 17:23:09 +000019753
19754 /* AV Load */
19755 case 0x006: case 0x026: // lvsl, lvsr
19756 case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx
19757 case 0x067: case 0x167: // lvx, lvxl
sewardj5117ce12006-01-27 21:20:15 +000019758 if (!allow_V) goto decode_noV;
sewardjdd40fdf2006-12-24 02:20:24 +000019759 if (dis_av_load( abiinfo, theInstr )) goto decode_success;
ceriona982c052005-06-28 17:23:09 +000019760 goto decode_failure;
19761
19762 /* AV Store */
19763 case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx
19764 case 0x0E7: case 0x1E7: // stvx, stvxl
sewardj5117ce12006-01-27 21:20:15 +000019765 if (!allow_V) goto decode_noV;
ceriona982c052005-06-28 17:23:09 +000019766 if (dis_av_store( theInstr )) goto decode_success;
19767 goto decode_failure;
19768
sewardj66d5ef22011-04-15 11:55:00 +000019769 /* VSX Load */
carll6c758b62013-10-03 21:38:45 +000019770 case 0x00C: // lxsiwzx
19771 case 0x04C: // lxsiwax
19772 case 0x20C: // lxsspx
sewardj66d5ef22011-04-15 11:55:00 +000019773 case 0x24C: // lxsdx
19774 case 0x34C: // lxvd2x
19775 case 0x14C: // lxvdsx
19776 case 0x30C: // lxvw4x
floriandc7948f2012-02-15 04:05:05 +000019777 // All of these VSX load instructions use some VMX facilities, so
19778 // if allow_V is not set, we'll skip trying to decode.
19779 if (!allow_V) goto decode_noV;
19780
carll1f5fe1f2014-08-07 23:25:23 +000019781 if (dis_vx_load( theInstr )) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019782 goto decode_failure;
19783
19784 /* VSX Store */
carll6c758b62013-10-03 21:38:45 +000019785 case 0x08C: // stxsiwx
19786 case 0x28C: // stxsspx
sewardj66d5ef22011-04-15 11:55:00 +000019787 case 0x2CC: // stxsdx
19788 case 0x3CC: // stxvd2x
19789 case 0x38C: // stxvw4x
floriandc7948f2012-02-15 04:05:05 +000019790 // All of these VSX store instructions use some VMX facilities, so
19791 // if allow_V is not set, we'll skip trying to decode.
19792 if (!allow_V) goto decode_noV;
19793
carll1f5fe1f2014-08-07 23:25:23 +000019794 if (dis_vx_store( theInstr )) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019795 goto decode_failure;
19796
19797 /* Miscellaneous ISA 2.06 instructions */
19798 case 0x1FA: // popcntd
sewardje71e56a2011-09-05 12:11:06 +000019799 case 0x17A: // popcntw
philippe738d9dd2012-07-06 21:56:53 +000019800 case 0x7A: // popcntb
carll1f5fe1f2014-08-07 23:25:23 +000019801 if (dis_int_logic( theInstr )) goto decode_success;
sewardj66d5ef22011-04-15 11:55:00 +000019802 goto decode_failure;
19803
sewardj4aa412a2011-07-24 14:13:21 +000019804 case 0x0FC: // bpermd
carllbb3f4012012-10-29 20:23:41 +000019805 if (!mode64) goto decode_failure;
sewardj4aa412a2011-07-24 14:13:21 +000019806 if (dis_int_logic( theInstr )) goto decode_success;
19807 goto decode_failure;
19808
ceriona982c052005-06-28 17:23:09 +000019809 default:
sewardjcb07be22008-11-06 09:02:34 +000019810 /* Deal with some other cases that we would otherwise have
19811 punted on. */
19812 /* --- ISEL (PowerISA_V2.05.pdf, p74) --- */
sewardj1685c282008-11-06 09:22:05 +000019813 /* only decode this insn when reserved bit 0 (31 in IBM's
19814 notation) is zero */
19815 if (IFIELD(theInstr, 0, 6) == (15<<1)) {
sewardjcb07be22008-11-06 09:02:34 +000019816 UInt rT = ifieldRegDS( theInstr );
19817 UInt rA = ifieldRegA( theInstr );
19818 UInt rB = ifieldRegB( theInstr );
19819 UInt bi = ifieldRegC( theInstr );
19820 putIReg(
19821 rT,
florian99dd03e2013-01-29 03:56:06 +000019822 IRExpr_ITE( binop(Iop_CmpNE32, getCRbit( bi ), mkU32(0)),
19823 rA == 0 ? (mode64 ? mkU64(0) : mkU32(0))
19824 : getIReg(rA),
19825 getIReg(rB))
19826
sewardjcb07be22008-11-06 09:02:34 +000019827 );
19828 DIP("isel r%u,r%u,r%u,crb%u\n", rT,rA,rB,bi);
19829 goto decode_success;
19830 }
ceriona982c052005-06-28 17:23:09 +000019831 goto decode_failure;
19832 }
19833 break;
19834
19835
cerion32aad402005-09-10 12:02:24 +000019836 case 0x04:
19837 /* AltiVec instructions */
19838
cerion76de5cf2005-11-18 18:25:12 +000019839 opc2 = IFIELD(theInstr, 0, 6);
cerion32aad402005-09-10 12:02:24 +000019840 switch (opc2) {
19841 /* AV Mult-Add, Mult-Sum */
19842 case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm
19843 case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm
19844 case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs
sewardj5117ce12006-01-27 21:20:15 +000019845 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019846 if (dis_av_multarith( theInstr )) goto decode_success;
19847 goto decode_failure;
19848
19849 /* AV Permutations */
19850 case 0x2A: // vsel
19851 case 0x2B: // vperm
cerion32aad402005-09-10 12:02:24 +000019852 case 0x2C: // vsldoi
sewardj5117ce12006-01-27 21:20:15 +000019853 if (!allow_V) goto decode_noV;
cerion92d9d872005-09-15 21:58:50 +000019854 if (dis_av_permute( theInstr )) goto decode_success;
cerion32aad402005-09-10 12:02:24 +000019855 goto decode_failure;
19856
carll7deaf952013-10-15 18:11:20 +000019857 case 0x2D: // vpermxor
19858 if (!allow_isa_2_07) goto decode_noP8;
19859 if (dis_av_permute( theInstr )) goto decode_success;
19860 goto decode_failure;
19861
cerion32aad402005-09-10 12:02:24 +000019862 /* AV Floating Point Mult-Add/Sub */
19863 case 0x2E: case 0x2F: // vmaddfp, vnmsubfp
sewardj5117ce12006-01-27 21:20:15 +000019864 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019865 if (dis_av_fp_arith( theInstr )) goto decode_success;
19866 goto decode_failure;
19867
carll60c6bac2013-10-18 01:19:06 +000019868 case 0x3D: case 0x3C: // vaddecuq, vaddeuqm
19869 case 0x3F: case 0x3E: // vsubecuq, vsubeuqm
19870 if (!allow_V) goto decode_noV;
19871 if (dis_av_quad( theInstr)) goto decode_success;
19872 goto decode_failure;
19873
cerion32aad402005-09-10 12:02:24 +000019874 default:
19875 break; // Fall through...
19876 }
19877
carll7deaf952013-10-15 18:11:20 +000019878 opc2 = IFIELD(theInstr, 0, 9);
19879 switch (opc2) {
19880 /* BCD arithmetic */
19881 case 0x1: case 0x41: // bcdadd, bcdsub
19882 if (!allow_isa_2_07) goto decode_noP8;
19883 if (dis_av_bcd( theInstr )) goto decode_success;
19884 goto decode_failure;
19885
19886 default:
19887 break; // Fall through...
19888 }
19889
cerion76de5cf2005-11-18 18:25:12 +000019890 opc2 = IFIELD(theInstr, 0, 11);
cerion32aad402005-09-10 12:02:24 +000019891 switch (opc2) {
19892 /* AV Arithmetic */
19893 case 0x180: // vaddcuw
19894 case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm
19895 case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws
19896 case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws
19897 case 0x580: // vsubcuw
19898 case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm
19899 case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws
19900 case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws
19901 case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw
19902 case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw
19903 case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw
19904 case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw
19905 case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw
19906 case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw
19907 case 0x008: case 0x048: // vmuloub, vmulouh
19908 case 0x108: case 0x148: // vmulosb, vmulosh
19909 case 0x208: case 0x248: // vmuleub, vmuleuh
19910 case 0x308: case 0x348: // vmulesb, vmulesh
19911 case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs
19912 case 0x688: case 0x788: // vsum2sws, vsumsws
sewardj5117ce12006-01-27 21:20:15 +000019913 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019914 if (dis_av_arith( theInstr )) goto decode_success;
19915 goto decode_failure;
19916
carll48ae46b2013-10-01 15:45:54 +000019917 case 0x088: case 0x089: // vmulouw, vmuluwm
19918 case 0x0C0: case 0x0C2: // vaddudm, vmaxud
19919 case 0x1C2: case 0x2C2: case 0x3C2: // vnaxsd, vminud, vminsd
19920 case 0x188: case 0x288: case 0x388: // vmulosw, vmuleuw, vmulesw
19921 case 0x4C0: // vsubudm
carll0c74bb52013-08-12 18:01:40 +000019922 if (!allow_isa_2_07) goto decode_noP8;
19923 if (dis_av_arith( theInstr )) goto decode_success;
19924 goto decode_failure;
19925
carll7deaf952013-10-15 18:11:20 +000019926 /* AV Polynomial Vector Multiply Add */
19927 case 0x408: case 0x448: // vpmsumb, vpmsumd
19928 case 0x488: case 0x4C8: // vpmsumw, vpmsumh
19929 if (!allow_isa_2_07) goto decode_noP8;
19930 if (dis_av_polymultarith( theInstr )) goto decode_success;
19931 goto decode_failure;
19932
cerion32aad402005-09-10 12:02:24 +000019933 /* AV Rotate, Shift */
19934 case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
19935 case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
19936 case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw
19937 case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw
19938 case 0x1C4: case 0x2C4: // vsl, vsr
19939 case 0x40C: case 0x44C: // vslo, vsro
sewardj5117ce12006-01-27 21:20:15 +000019940 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019941 if (dis_av_shift( theInstr )) goto decode_success;
19942 goto decode_failure;
19943
carll48ae46b2013-10-01 15:45:54 +000019944 case 0x0C4: // vrld
19945 case 0x3C4: case 0x5C4: case 0x6C4: // vsrad, vsld, vsrd
19946 if (!allow_isa_2_07) goto decode_noP8;
19947 if (dis_av_shift( theInstr )) goto decode_success;
19948 goto decode_failure;
19949
cerion32aad402005-09-10 12:02:24 +000019950 /* AV Logic */
19951 case 0x404: case 0x444: case 0x484: // vand, vandc, vor
19952 case 0x4C4: case 0x504: // vxor, vnor
sewardj5117ce12006-01-27 21:20:15 +000019953 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019954 if (dis_av_logic( theInstr )) goto decode_success;
19955 goto decode_failure;
19956
carll7deaf952013-10-15 18:11:20 +000019957 case 0x544: // vorc
19958 case 0x584: case 0x684: // vnand, veqv
19959 if (!allow_isa_2_07) goto decode_noP8;
19960 if (dis_av_logic( theInstr )) goto decode_success;
19961 goto decode_failure;
19962
cerion32aad402005-09-10 12:02:24 +000019963 /* AV Processor Control */
19964 case 0x604: case 0x644: // mfvscr, mtvscr
sewardj5117ce12006-01-27 21:20:15 +000019965 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019966 if (dis_av_procctl( theInstr )) goto decode_success;
19967 goto decode_failure;
19968
19969 /* AV Floating Point Arithmetic */
19970 case 0x00A: case 0x04A: // vaddfp, vsubfp
19971 case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp
19972 case 0x1CA: // vlogefp
19973 case 0x40A: case 0x44A: // vmaxfp, vminfp
sewardj5117ce12006-01-27 21:20:15 +000019974 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019975 if (dis_av_fp_arith( theInstr )) goto decode_success;
19976 goto decode_failure;
19977
19978 /* AV Floating Point Round/Convert */
19979 case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip
19980 case 0x2CA: // vrfim
19981 case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs
19982 case 0x3CA: // vctsxs
sewardj5117ce12006-01-27 21:20:15 +000019983 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019984 if (dis_av_fp_convert( theInstr )) goto decode_success;
19985 goto decode_failure;
19986
19987 /* AV Merge, Splat */
19988 case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw
19989 case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw
19990 case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw
19991 case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw
sewardj5117ce12006-01-27 21:20:15 +000019992 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000019993 if (dis_av_permute( theInstr )) goto decode_success;
19994 goto decode_failure;
19995
carll48ae46b2013-10-01 15:45:54 +000019996 case 0x68C: case 0x78C: // vmrgow, vmrgew
19997 if (!allow_isa_2_07) goto decode_noP8;
19998 if (dis_av_permute( theInstr )) goto decode_success;
19999 goto decode_failure;
20000
cerion32aad402005-09-10 12:02:24 +000020001 /* AV Pack, Unpack */
20002 case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
20003 case 0x0CE: // vpkuwus
20004 case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss
20005 case 0x1CE: // vpkswss
20006 case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb
20007 case 0x2CE: // vupklsh
20008 case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx
carll48ae46b2013-10-01 15:45:54 +000020009 if (!allow_V) goto decode_noV;
20010 if (dis_av_pack( theInstr )) goto decode_success;
20011 goto decode_failure;
cerion32aad402005-09-10 12:02:24 +000020012
carll48ae46b2013-10-01 15:45:54 +000020013 case 0x44E: case 0x4CE: case 0x54E: // vpkudum, vpkudus, vpksdus
20014 case 0x5CE: case 0x64E: case 0x6cE: // vpksdss, vupkhsw, vupklsw
carll0c74bb52013-08-12 18:01:40 +000020015 if (!allow_isa_2_07) goto decode_noP8;
20016 if (dis_av_pack( theInstr )) goto decode_success;
20017 goto decode_failure;
20018
carll7deaf952013-10-15 18:11:20 +000020019 case 0x508: case 0x509: // vcipher, vcipherlast
20020 case 0x548: case 0x549: // vncipher, vncipherlast
20021 case 0x5C8: // vsbox
20022 if (!allow_isa_2_07) goto decode_noP8;
20023 if (dis_av_cipher( theInstr )) goto decode_success;
20024 goto decode_failure;
20025
20026 case 0x6C2: case 0x682: // vshasigmaw, vshasigmad
20027 if (!allow_isa_2_07) goto decode_noP8;
20028 if (dis_av_hash( theInstr )) goto decode_success;
20029 goto decode_failure;
20030
20031 case 0x702: case 0x742: // vclzb, vclzh
20032 case 0x782: case 0x7c2: // vclzw, vclzd
20033 if (!allow_isa_2_07) goto decode_noP8;
carll60c6bac2013-10-18 01:19:06 +000020034 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
carll7deaf952013-10-15 18:11:20 +000020035 goto decode_failure;
20036
20037 case 0x703: case 0x743: // vpopcntb, vpopcnth
20038 case 0x783: case 0x7c3: // vpopcntw, vpopcntd
20039 if (!allow_isa_2_07) goto decode_noP8;
carll60c6bac2013-10-18 01:19:06 +000020040 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
20041 goto decode_failure;
20042
20043 case 0x50c: // vgbbd
20044 if (!allow_isa_2_07) goto decode_noP8;
20045 if (dis_av_count_bitTranspose( theInstr, opc2 )) goto decode_success;
20046 goto decode_failure;
20047
20048 case 0x140: case 0x100: // vaddcuq, vadduqm
20049 case 0x540: case 0x500: // vsubcuq, vsubuqm
20050 case 0x54C: // vbpermq
20051 if (!allow_V) goto decode_noV;
20052 if (dis_av_quad( theInstr)) goto decode_success;
carll7deaf952013-10-15 18:11:20 +000020053 goto decode_failure;
20054
cerion32aad402005-09-10 12:02:24 +000020055 default:
20056 break; // Fall through...
20057 }
20058
cerion76de5cf2005-11-18 18:25:12 +000020059 opc2 = IFIELD(theInstr, 0, 10);
cerion32aad402005-09-10 12:02:24 +000020060 switch (opc2) {
20061
20062 /* AV Compare */
20063 case 0x006: case 0x046: case 0x086: // vcmpequb, vcmpequh, vcmpequw
20064 case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw
20065 case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw
sewardj5117ce12006-01-27 21:20:15 +000020066 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000020067 if (dis_av_cmp( theInstr )) goto decode_success;
20068 goto decode_failure;
20069
carll48ae46b2013-10-01 15:45:54 +000020070 case 0x0C7: // vcmpequd
20071 case 0x2C7: // vcmpgtud
20072 case 0x3C7: // vcmpgtsd
20073 if (!allow_isa_2_07) goto decode_noP8;
20074 if (dis_av_cmp( theInstr )) goto decode_success;
20075 goto decode_failure;
20076
cerion32aad402005-09-10 12:02:24 +000020077 /* AV Floating Point Compare */
20078 case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp
20079 case 0x3C6: // vcmpbfp
sewardj5117ce12006-01-27 21:20:15 +000020080 if (!allow_V) goto decode_noV;
cerion32aad402005-09-10 12:02:24 +000020081 if (dis_av_fp_cmp( theInstr )) goto decode_success;
20082 goto decode_failure;
20083
20084 default:
20085 goto decode_failure;
20086 }
20087 break;
cerion7aa4bbc2005-01-29 09:32:07 +000020088
cerion896a1372005-01-25 12:24:25 +000020089 default:
cerion5b2325f2005-12-23 00:55:09 +000020090 goto decode_failure;
20091
sewardj5117ce12006-01-27 21:20:15 +000020092 decode_noF:
20093 vassert(!allow_F);
20094 vex_printf("disInstr(ppc): declined to decode an FP insn.\n");
20095 goto decode_failure;
20096 decode_noV:
20097 vassert(!allow_V);
20098 vex_printf("disInstr(ppc): declined to decode an AltiVec insn.\n");
20099 goto decode_failure;
sewardj66d5ef22011-04-15 11:55:00 +000020100 decode_noVX:
20101 vassert(!allow_VX);
sewardj4aa412a2011-07-24 14:13:21 +000020102 vex_printf("disInstr(ppc): declined to decode a Power ISA 2.06 insn.\n");
sewardj66d5ef22011-04-15 11:55:00 +000020103 goto decode_failure;
sewardj5117ce12006-01-27 21:20:15 +000020104 decode_noFX:
sewardj7c545862006-01-27 21:52:19 +000020105 vassert(!allow_FX);
sewardj5117ce12006-01-27 21:20:15 +000020106 vex_printf("disInstr(ppc): "
sewardjb183b852006-02-03 16:08:03 +000020107 "declined to decode a GeneralPurpose-Optional insn.\n");
sewardj5117ce12006-01-27 21:20:15 +000020108 goto decode_failure;
20109 decode_noGX:
sewardj7c545862006-01-27 21:52:19 +000020110 vassert(!allow_GX);
sewardj5117ce12006-01-27 21:20:15 +000020111 vex_printf("disInstr(ppc): "
20112 "declined to decode a Graphics-Optional insn.\n");
cerion5b2325f2005-12-23 00:55:09 +000020113 goto decode_failure;
sewardjc66d6fa2012-04-02 21:24:12 +000020114 decode_noDFP:
20115 vassert(!allow_DFP);
20116 vex_printf("disInstr(ppc): "
20117 "declined to decode a Decimal Floating Point insn.\n");
20118 goto decode_failure;
carll0c74bb52013-08-12 18:01:40 +000020119 decode_noP8:
20120 vassert(!allow_isa_2_07);
20121 vex_printf("disInstr(ppc): "
20122 "declined to decode a Power 8 insn.\n");
20123 goto decode_failure;
sewardjc66d6fa2012-04-02 21:24:12 +000020124
cerion5b2325f2005-12-23 00:55:09 +000020125
cerion896a1372005-01-25 12:24:25 +000020126 decode_failure:
20127 /* All decode failures end up here. */
cerion225a0342005-09-12 20:49:09 +000020128 opc2 = (theInstr) & 0x7FF;
sewardj442e51a2012-12-06 18:08:04 +000020129 if (sigill_diag) {
20130 vex_printf("disInstr(ppc): unhandled instruction: "
20131 "0x%x\n", theInstr);
20132 vex_printf(" primary %d(0x%x), secondary %u(0x%x)\n",
20133 opc1, opc1, opc2, opc2);
20134 }
cerion995bc362005-02-03 11:03:31 +000020135
sewardj01a9e802005-02-01 20:46:00 +000020136 /* Tell the dispatcher that this insn cannot be decoded, and so has
20137 not been executed, and (is currently) the next to be executed.
20138 CIA should be up-to-date since it made so at the start of each
20139 insn, but nevertheless be paranoid and update it again right
20140 now. */
cerion2831b002005-11-30 19:55:22 +000020141 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr) );
philippe2faf5912014-08-11 22:45:47 +000020142 dres.len = 0;
sewardj3dee8492012-04-20 00:13:28 +000020143 dres.whatNext = Dis_StopHere;
20144 dres.jk_StopHere = Ijk_NoDecode;
philippe2faf5912014-08-11 22:45:47 +000020145 dres.continueAt = 0;
sewardj9e6491a2005-07-02 19:24:10 +000020146 return dres;
cerion896a1372005-01-25 12:24:25 +000020147 } /* switch (opc) for the main (primary) opcode switch. */
20148
20149 decode_success:
20150 /* All decode successes end up here. */
sewardj3dee8492012-04-20 00:13:28 +000020151 switch (dres.whatNext) {
20152 case Dis_Continue:
20153 putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr + 4));
20154 break;
20155 case Dis_ResteerU:
20156 case Dis_ResteerC:
20157 putGST( PPC_GST_CIA, mkSzImm(ty, dres.continueAt));
20158 break;
20159 case Dis_StopHere:
20160 break;
20161 default:
20162 vassert(0);
20163 }
cerion896a1372005-01-25 12:24:25 +000020164 DIP("\n");
20165
sewardjce02aa72006-01-12 12:27:58 +000020166 if (dres.len == 0) {
20167 dres.len = 4;
20168 } else {
20169 vassert(dres.len == 20);
20170 }
sewardj9e6491a2005-07-02 19:24:10 +000020171 return dres;
cerion896a1372005-01-25 12:24:25 +000020172}
20173
20174#undef DIP
20175#undef DIS
20176
sewardj9e6491a2005-07-02 19:24:10 +000020177
20178/*------------------------------------------------------------*/
20179/*--- Top-level fn ---*/
20180/*------------------------------------------------------------*/
20181
20182/* Disassemble a single instruction into IR. The instruction
20183 is located in host memory at &guest_code[delta]. */
20184
sewardjdd40fdf2006-12-24 02:20:24 +000020185DisResult disInstr_PPC ( IRSB* irsb_IN,
sewardjc716aea2006-01-17 01:48:46 +000020186 Bool (*resteerOkFn) ( void*, Addr64 ),
sewardj984d9b12010-01-15 10:53:21 +000020187 Bool resteerCisOk,
sewardjc716aea2006-01-17 01:48:46 +000020188 void* callback_opaque,
florian8462d112014-09-24 15:18:09 +000020189 const UChar* guest_code_IN,
cerion5b2325f2005-12-23 00:55:09 +000020190 Long delta,
20191 Addr64 guest_IP,
sewardja5f55da2006-04-30 23:37:32 +000020192 VexArch guest_arch,
cerion5b2325f2005-12-23 00:55:09 +000020193 VexArchInfo* archinfo,
sewardjdd40fdf2006-12-24 02:20:24 +000020194 VexAbiInfo* abiinfo,
sewardj9b769162014-07-24 12:42:03 +000020195 VexEndness host_endness_IN,
sewardj442e51a2012-12-06 18:08:04 +000020196 Bool sigill_diag_IN )
sewardj9e6491a2005-07-02 19:24:10 +000020197{
sewardj5df65bb2005-11-29 14:47:04 +000020198 IRType ty;
20199 DisResult dres;
sewardj5117ce12006-01-27 21:20:15 +000020200 UInt mask32, mask64;
20201 UInt hwcaps_guest = archinfo->hwcaps;
20202
sewardja5f55da2006-04-30 23:37:32 +000020203 vassert(guest_arch == VexArchPPC32 || guest_arch == VexArchPPC64);
sewardj5df65bb2005-11-29 14:47:04 +000020204
sewardja5f55da2006-04-30 23:37:32 +000020205 /* global -- ick */
20206 mode64 = guest_arch == VexArchPPC64;
20207 ty = mode64 ? Ity_I64 : Ity_I32;
carll1f5fe1f2014-08-07 23:25:23 +000020208 if (!mode64 && (host_endness_IN == VexEndnessLE)) {
20209 vex_printf("disInstr(ppc): Little Endian 32-bit mode is not supported\n");
philippe2faf5912014-08-11 22:45:47 +000020210 dres.len = 0;
carll1f5fe1f2014-08-07 23:25:23 +000020211 dres.whatNext = Dis_StopHere;
20212 dres.jk_StopHere = Ijk_NoDecode;
philippe99af2432014-08-09 08:13:19 +000020213 dres.continueAt = 0;
carll1f5fe1f2014-08-07 23:25:23 +000020214 return dres;
20215 }
sewardja5f55da2006-04-30 23:37:32 +000020216
20217 /* do some sanity checks */
sewardj5117ce12006-01-27 21:20:15 +000020218 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
sewardjc66d6fa2012-04-02 21:24:12 +000020219 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
carll0c74bb52013-08-12 18:01:40 +000020220 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
sewardj5117ce12006-01-27 21:20:15 +000020221
sewardj66d5ef22011-04-15 11:55:00 +000020222 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
carll0c74bb52013-08-12 18:01:40 +000020223 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
20224 | VEX_HWCAPS_PPC64_ISA2_07;
sewardj5117ce12006-01-27 21:20:15 +000020225
sewardja5f55da2006-04-30 23:37:32 +000020226 if (mode64) {
20227 vassert((hwcaps_guest & mask32) == 0);
20228 } else {
20229 vassert((hwcaps_guest & mask64) == 0);
20230 }
sewardj9e6491a2005-07-02 19:24:10 +000020231
20232 /* Set globals (see top of this file) */
20233 guest_code = guest_code_IN;
sewardjdd40fdf2006-12-24 02:20:24 +000020234 irsb = irsb_IN;
sewardj9b769162014-07-24 12:42:03 +000020235 host_endness = host_endness_IN;
ceriond953ebb2005-11-29 13:27:20 +000020236
cerion2831b002005-11-30 19:55:22 +000020237 guest_CIA_curr_instr = mkSzAddr(ty, guest_IP);
20238 guest_CIA_bbstart = mkSzAddr(ty, guest_IP - delta);
sewardj9e6491a2005-07-02 19:24:10 +000020239
sewardj3dee8492012-04-20 00:13:28 +000020240 dres = disInstr_PPC_WRK ( resteerOkFn, resteerCisOk, callback_opaque,
carll1f5fe1f2014-08-07 23:25:23 +000020241 delta, archinfo, abiinfo, sigill_diag_IN);
sewardj9e6491a2005-07-02 19:24:10 +000020242
20243 return dres;
20244}
20245
20246
sewardjc808ef72005-08-18 11:50:43 +000020247/*------------------------------------------------------------*/
20248/*--- Unused stuff ---*/
20249/*------------------------------------------------------------*/
20250
20251///* A potentially more memcheck-friendly implementation of Clz32, with
20252// the boundary case Clz32(0) = 32, which is what ppc requires. */
20253//
20254//static IRExpr* /* :: Ity_I32 */ verbose_Clz32 ( IRTemp arg )
20255//{
20256// /* Welcome ... to SSA R Us. */
20257// IRTemp n1 = newTemp(Ity_I32);
20258// IRTemp n2 = newTemp(Ity_I32);
20259// IRTemp n3 = newTemp(Ity_I32);
20260// IRTemp n4 = newTemp(Ity_I32);
20261// IRTemp n5 = newTemp(Ity_I32);
20262// IRTemp n6 = newTemp(Ity_I32);
20263// IRTemp n7 = newTemp(Ity_I32);
20264// IRTemp n8 = newTemp(Ity_I32);
20265// IRTemp n9 = newTemp(Ity_I32);
20266// IRTemp n10 = newTemp(Ity_I32);
20267// IRTemp n11 = newTemp(Ity_I32);
20268// IRTemp n12 = newTemp(Ity_I32);
20269//
20270// /* First, propagate the most significant 1-bit into all lower
20271// positions in the word. */
20272// /* unsigned int clz ( unsigned int n )
20273// {
20274// n |= (n >> 1);
20275// n |= (n >> 2);
20276// n |= (n >> 4);
20277// n |= (n >> 8);
20278// n |= (n >> 16);
20279// return bitcount(~n);
20280// }
20281// */
20282// assign(n1, mkexpr(arg));
20283// assign(n2, binop(Iop_Or32, mkexpr(n1), binop(Iop_Shr32, mkexpr(n1), mkU8(1))));
20284// assign(n3, binop(Iop_Or32, mkexpr(n2), binop(Iop_Shr32, mkexpr(n2), mkU8(2))));
20285// assign(n4, binop(Iop_Or32, mkexpr(n3), binop(Iop_Shr32, mkexpr(n3), mkU8(4))));
20286// assign(n5, binop(Iop_Or32, mkexpr(n4), binop(Iop_Shr32, mkexpr(n4), mkU8(8))));
20287// assign(n6, binop(Iop_Or32, mkexpr(n5), binop(Iop_Shr32, mkexpr(n5), mkU8(16))));
20288// /* This gives a word of the form 0---01---1. Now invert it, giving
20289// a word of the form 1---10---0, then do a population-count idiom
20290// (to count the 1s, which is the number of leading zeroes, or 32
20291// if the original word was 0. */
20292// assign(n7, unop(Iop_Not32, mkexpr(n6)));
20293//
20294// /* unsigned int bitcount ( unsigned int n )
20295// {
20296// n = n - ((n >> 1) & 0x55555555);
20297// n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
20298// n = (n + (n >> 4)) & 0x0F0F0F0F;
20299// n = n + (n >> 8);
20300// n = (n + (n >> 16)) & 0x3F;
20301// return n;
20302// }
20303// */
20304// assign(n8,
20305// binop(Iop_Sub32,
20306// mkexpr(n7),
20307// binop(Iop_And32,
20308// binop(Iop_Shr32, mkexpr(n7), mkU8(1)),
20309// mkU32(0x55555555))));
20310// assign(n9,
20311// binop(Iop_Add32,
20312// binop(Iop_And32, mkexpr(n8), mkU32(0x33333333)),
20313// binop(Iop_And32,
20314// binop(Iop_Shr32, mkexpr(n8), mkU8(2)),
20315// mkU32(0x33333333))));
20316// assign(n10,
20317// binop(Iop_And32,
20318// binop(Iop_Add32,
20319// mkexpr(n9),
20320// binop(Iop_Shr32, mkexpr(n9), mkU8(4))),
20321// mkU32(0x0F0F0F0F)));
20322// assign(n11,
20323// binop(Iop_Add32,
20324// mkexpr(n10),
20325// binop(Iop_Shr32, mkexpr(n10), mkU8(8))));
20326// assign(n12,
20327// binop(Iop_Add32,
20328// mkexpr(n11),
20329// binop(Iop_Shr32, mkexpr(n11), mkU8(16))));
20330// return
20331// binop(Iop_And32, mkexpr(n12), mkU32(0x3F));
20332//}
20333
cerion896a1372005-01-25 12:24:25 +000020334/*--------------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +000020335/*--- end guest_ppc_toIR.c ---*/
cerion896a1372005-01-25 12:24:25 +000020336/*--------------------------------------------------------------------*/